mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Merge remote-tracking branch 'upstream/master' into smart-card-art-deck-import-desktop-and-mobile
This commit is contained in:
@@ -83,7 +83,11 @@ public class AdventureApplicationAdapter extends ApplicationAdapter {
|
|||||||
|
|
||||||
private void storeScreen() {
|
private void storeScreen() {
|
||||||
if(!(currentScene instanceof ForgeScene))
|
if(!(currentScene instanceof ForgeScene))
|
||||||
|
{
|
||||||
|
if(lastScreenTexture!=null)
|
||||||
|
lastScreenTexture.getTexture().dispose();
|
||||||
lastScreenTexture = ScreenUtils.getFrameBufferTexture();
|
lastScreenTexture = ScreenUtils.getFrameBufferTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package forge.adventure.data;
|
package forge.adventure.data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import forge.adventure.util.SaveFileContent;
|
||||||
|
import forge.adventure.util.SaveFileData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data class that will be used to read Json configuration files
|
* Data class that will be used to read Json configuration files
|
||||||
* BiomeSpriteData
|
* BiomeSpriteData
|
||||||
* contains the information for the sprites on the map like trees and rocks
|
* contains the information for the sprites on the map like trees and rocks
|
||||||
*/
|
*/
|
||||||
public class BiomeSpriteData implements Serializable {
|
public class BiomeSpriteData implements SaveFileContent {
|
||||||
public String name;
|
public String name;
|
||||||
public double startArea;
|
public double startArea;
|
||||||
public double endArea;
|
public double endArea;
|
||||||
@@ -18,4 +19,26 @@ public class BiomeSpriteData implements Serializable {
|
|||||||
public String key() {
|
public String key() {
|
||||||
return "BiomeSprite&" + name;
|
return "BiomeSprite&" + name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(SaveFileData data) {
|
||||||
|
name=data.readString("name");
|
||||||
|
startArea=data.readDouble("startArea");
|
||||||
|
endArea=data.readDouble("endArea");
|
||||||
|
density=data.readDouble("density");
|
||||||
|
resolution=data.readDouble("resolution");;
|
||||||
|
layer=data.readInt("layer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SaveFileData save() {
|
||||||
|
SaveFileData data=new SaveFileData();
|
||||||
|
data.store("name",name);
|
||||||
|
data.store("startArea",startArea);
|
||||||
|
data.store("endArea",endArea);
|
||||||
|
data.store("density",density);
|
||||||
|
data.store("resolution",resolution);
|
||||||
|
data.store("layer",layer);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ public class DeckEditScene extends ForgeScene {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (PaperCard card : AdventurePlayer.current().getCards())
|
for (Map.Entry<PaperCard, Integer> card : AdventurePlayer.current().getCards())
|
||||||
FModel.getQuest().getCards().addSingleCard(card, 1);
|
FModel.getQuest().getCards().addSingleCard(card.getKey(), card.getValue());
|
||||||
|
|
||||||
|
|
||||||
Deck deck = AdventurePlayer.current().getDeck();
|
Deck deck = AdventurePlayer.current().getDeck();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package forge.adventure.scene;
|
package forge.adventure.scene;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
|
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
|
||||||
import forge.adventure.AdventureApplicationAdapter;
|
import forge.adventure.AdventureApplicationAdapter;
|
||||||
import forge.adventure.util.Current;
|
import forge.adventure.util.Current;
|
||||||
@@ -37,5 +38,14 @@ public class InnScene extends UIScene {
|
|||||||
TextButton doneButton = ui.findActor("done");
|
TextButton doneButton = ui.findActor("done");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keycode)
|
||||||
|
{
|
||||||
|
if (keycode == Input.Keys.ESCAPE)
|
||||||
|
{
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package forge.adventure.scene;
|
package forge.adventure.scene;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
|
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
|
||||||
@@ -103,6 +104,15 @@ public class RewardScene extends UIScene {
|
|||||||
doneButton=ui.findActor("done");
|
doneButton=ui.findActor("done");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keycode)
|
||||||
|
{
|
||||||
|
if (keycode == Input.Keys.ESCAPE)
|
||||||
|
{
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void loadRewards(Array<Reward> newRewards, Type type, ShopActor shopActor)
|
public void loadRewards(Array<Reward> newRewards, Type type, ShopActor shopActor)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package forge.adventure.scene;
|
package forge.adventure.scene;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||||
@@ -36,6 +37,8 @@ public class SaveLoadScene extends UIScene {
|
|||||||
int currentSlot = -3;
|
int currentSlot = -3;
|
||||||
Image previewImage;
|
Image previewImage;
|
||||||
TextButton saveLoadButton;
|
TextButton saveLoadButton;
|
||||||
|
TextButton quickSave;
|
||||||
|
TextButton autoSave;
|
||||||
|
|
||||||
public SaveLoadScene() {
|
public SaveLoadScene() {
|
||||||
super("ui/save_load.json");
|
super("ui/save_load.json");
|
||||||
@@ -44,13 +47,14 @@ public class SaveLoadScene extends UIScene {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void addSaveSlot(String name, int i) {
|
private TextButton addSaveSlot(String name, int i) {
|
||||||
layout.add(Controls.newLabel(name));
|
layout.add(Controls.newLabel(name));
|
||||||
TextButton button = Controls.newTextButton("...");
|
TextButton button = Controls.newTextButton("...");
|
||||||
button.addListener(new ClickListener() {
|
button.addListener(new ClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void clicked(InputEvent event, float x, float y) {
|
public void clicked(InputEvent event, float x, float y) {
|
||||||
try {
|
try {
|
||||||
|
if(!button.isDisabled())
|
||||||
select(i);
|
select(i);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -60,6 +64,7 @@ public class SaveLoadScene extends UIScene {
|
|||||||
layout.add(button).expandX();
|
layout.add(button).expandX();
|
||||||
buttons.put(i, button);
|
buttons.put(i, button);
|
||||||
layout.row();
|
layout.row();
|
||||||
|
return button;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +110,15 @@ public class SaveLoadScene extends UIScene {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keycode)
|
||||||
|
{
|
||||||
|
if (keycode == Input.Keys.ESCAPE)
|
||||||
|
{
|
||||||
|
back();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
public void save() {
|
public void save() {
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
if( WorldSave.getCurrentSave().save(textInput.getText(), currentSlot))
|
if( WorldSave.getCurrentSave().save(textInput.getText(), currentSlot))
|
||||||
@@ -157,6 +171,8 @@ public class SaveLoadScene extends UIScene {
|
|||||||
header.setText("Load game");
|
header.setText("Load game");
|
||||||
saveLoadButton.setText("Load");
|
saveLoadButton.setText("Load");
|
||||||
}
|
}
|
||||||
|
autoSave.setDisabled(save);
|
||||||
|
quickSave.setDisabled(save);
|
||||||
this.save = save;
|
this.save = save;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,8 +204,8 @@ public class SaveLoadScene extends UIScene {
|
|||||||
header.setHeight(header.getHeight() * 2);
|
header.setHeight(header.getHeight() * 2);
|
||||||
layout.add(header).colspan(2).align(Align.center);
|
layout.add(header).colspan(2).align(Align.center);
|
||||||
layout.row();
|
layout.row();
|
||||||
addSaveSlot("Auto save", -2);
|
autoSave=addSaveSlot("Auto save", WorldSave.AUTO_SAVE_SLOT);
|
||||||
addSaveSlot("Quick save", -1);
|
quickSave=addSaveSlot("Quick save", WorldSave.QUICK_SAVE_SLOT);
|
||||||
for (int i = 1; i < 11; i++)
|
for (int i = 1; i < 11; i++)
|
||||||
addSaveSlot("Slot:" + i, i);
|
addSaveSlot("Slot:" + i, i);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package forge.adventure.scene;
|
package forge.adventure.scene;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.graphics.GL20;
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||||
@@ -53,6 +54,15 @@ public class SettingsScene extends UIScene {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keycode)
|
||||||
|
{
|
||||||
|
if (keycode == Input.Keys.ESCAPE)
|
||||||
|
{
|
||||||
|
back();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
public boolean back() {
|
public boolean back() {
|
||||||
AdventureApplicationAdapter.instance.switchToLast();
|
AdventureApplicationAdapter.instance.switchToLast();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package forge.adventure.scene;
|
package forge.adventure.scene;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||||
import forge.adventure.AdventureApplicationAdapter;
|
import forge.adventure.AdventureApplicationAdapter;
|
||||||
import forge.adventure.world.WorldSave;
|
import forge.adventure.world.WorldSave;
|
||||||
@@ -18,7 +19,6 @@ public class StartScene extends UIScene {
|
|||||||
super("ui/start_menu.json");
|
super("ui/start_menu.json");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean NewGame() {
|
public boolean NewGame() {
|
||||||
AdventureApplicationAdapter.instance.switchScene(SceneType.NewGameScene.instance);
|
AdventureApplicationAdapter.instance.switchScene(SceneType.NewGameScene.instance);
|
||||||
return true;
|
return true;
|
||||||
@@ -67,6 +67,16 @@ public class StartScene extends UIScene {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keycode)
|
||||||
|
{
|
||||||
|
if (keycode == Input.Keys.ESCAPE)
|
||||||
|
{
|
||||||
|
if(WorldSave.getCurrentSave().getWorld().getData() != null)
|
||||||
|
Resume();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public void resLoaded() {
|
public void resLoaded() {
|
||||||
super.resLoaded();
|
super.resLoaded();
|
||||||
|
|||||||
@@ -47,9 +47,19 @@ public class UIScene extends Scene{
|
|||||||
{
|
{
|
||||||
return ui;
|
return ui;
|
||||||
}
|
}
|
||||||
|
public boolean keyPressed(int keycode)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public void resLoaded() {
|
public void resLoaded() {
|
||||||
stage = new Stage(new StretchViewport(GetIntendedWidth(), GetIntendedHeight()));
|
stage = new Stage(new StretchViewport(GetIntendedWidth(), GetIntendedHeight())){
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyUp(int keycode) {
|
||||||
|
return keyPressed(keycode);
|
||||||
|
}
|
||||||
|
};
|
||||||
ui = new UIActor(Config.instance().getFile(uiFile));
|
ui = new UIActor(Config.instance().getFile(uiFile));
|
||||||
screenImage=ui.findActor("lastScreen");
|
screenImage=ui.findActor("lastScreen");
|
||||||
stage.addActor(ui);
|
stage.addActor(ui);
|
||||||
@@ -75,6 +85,8 @@ public class UIScene extends Scene{
|
|||||||
potPixmap.fillRectangle(0,0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
potPixmap.fillRectangle(0,0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||||
backgroundTexture = new TextureRegion(new Texture(potPixmap), 0, Gdx.graphics.getHeight(), Gdx.graphics.getWidth(), -Gdx.graphics.getHeight());
|
backgroundTexture = new TextureRegion(new Texture(potPixmap), 0, Gdx.graphics.getHeight(), Gdx.graphics.getWidth(), -Gdx.graphics.getHeight());
|
||||||
screenImage.setDrawable(new TextureRegionDrawable(backgroundTexture));
|
screenImage.setDrawable(new TextureRegionDrawable(backgroundTexture));
|
||||||
|
pixmap.dispose();
|
||||||
|
potPixmap.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
super.enter();
|
super.enter();
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public class GameHUD extends Stage {
|
|||||||
|
|
||||||
addActor(ui);
|
addActor(ui);
|
||||||
addActor(miniMapPlayer);
|
addActor(miniMapPlayer);
|
||||||
|
WorldSave.getCurrentSave().onLoad(() -> enter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameHUD getInstance() {
|
public static GameHUD getInstance() {
|
||||||
@@ -94,10 +95,9 @@ public class GameHUD extends Stage {
|
|||||||
Texture miniMapTexture;
|
Texture miniMapTexture;
|
||||||
public void enter() {
|
public void enter() {
|
||||||
|
|
||||||
if(miniMapTexture==null)
|
if(miniMapTexture!=null)
|
||||||
{
|
miniMapTexture.dispose();
|
||||||
miniMapTexture=new Texture(WorldSave.getCurrentSave().getWorld().getBiomeImage());
|
miniMapTexture=new Texture(WorldSave.getCurrentSave().getWorld().getBiomeImage());
|
||||||
}
|
|
||||||
|
|
||||||
miniMap.setDrawable(new TextureRegionDrawable(miniMapTexture));
|
miniMap.setDrawable(new TextureRegionDrawable(miniMapTexture));
|
||||||
avatar.setDrawable(new TextureRegionDrawable(Current.player().avatar()));
|
avatar.setDrawable(new TextureRegionDrawable(Current.player().avatar()));
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package forge.adventure.stage;
|
package forge.adventure.stage;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.Input;
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||||
import com.badlogic.gdx.graphics.Pixmap;
|
|
||||||
import com.badlogic.gdx.math.Rectangle;
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||||
@@ -16,7 +14,6 @@ import forge.adventure.character.PlayerSprite;
|
|||||||
import forge.adventure.scene.Scene;
|
import forge.adventure.scene.Scene;
|
||||||
import forge.adventure.scene.SceneType;
|
import forge.adventure.scene.SceneType;
|
||||||
import forge.adventure.world.WorldSave;
|
import forge.adventure.world.WorldSave;
|
||||||
import forge.adventure.world.WorldSaveHeader;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class to render a player sprite on a map
|
* Base class to render a player sprite on a map
|
||||||
@@ -48,6 +45,13 @@ public abstract class GameStage extends Stage {
|
|||||||
|
|
||||||
public GameStage() {
|
public GameStage() {
|
||||||
super(new StretchViewport(Scene.GetIntendedWidth(), Scene.GetIntendedHeight(), new OrthographicCamera()));
|
super(new StretchViewport(Scene.GetIntendedWidth(), Scene.GetIntendedHeight(), new OrthographicCamera()));
|
||||||
|
WorldSave.getCurrentSave().onLoad(() -> {
|
||||||
|
if(player==null)
|
||||||
|
return;
|
||||||
|
foregroundSprites.removeActor(player);
|
||||||
|
player=null;
|
||||||
|
GetPlayer();
|
||||||
|
});
|
||||||
camera = (OrthographicCamera) getCamera();
|
camera = (OrthographicCamera) getCamera();
|
||||||
|
|
||||||
backgroundSprites = new Group();
|
backgroundSprites = new Group();
|
||||||
@@ -157,6 +161,18 @@ public abstract class GameStage extends Stage {
|
|||||||
{
|
{
|
||||||
player.getMovementDirection().y = -1;
|
player.getMovementDirection().y = -1;
|
||||||
}
|
}
|
||||||
|
if (keycode == Input.Keys.F5)//todo config
|
||||||
|
{
|
||||||
|
GetPlayer().storePos();
|
||||||
|
WorldSave.getCurrentSave().header.createPreview();
|
||||||
|
WorldSave.getCurrentSave().quickSave();
|
||||||
|
|
||||||
|
}
|
||||||
|
if (keycode == Input.Keys.F8)//todo config
|
||||||
|
{
|
||||||
|
WorldSave.getCurrentSave().quickLoad();
|
||||||
|
enter();
|
||||||
|
}
|
||||||
if (keycode == Input.Keys.F12)
|
if (keycode == Input.Keys.F12)
|
||||||
{
|
{
|
||||||
debugCollision(true);
|
debugCollision(true);
|
||||||
@@ -258,15 +274,8 @@ public abstract class GameStage extends Stage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void openMenu() {
|
public void openMenu() {
|
||||||
Pixmap pixmap = Pixmap.createFromFrameBuffer(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
|
||||||
Pixmap scaled = new Pixmap(WorldSaveHeader.previewImageWidth, (int) (WorldSaveHeader.previewImageWidth / (Scene.GetIntendedWidth() / (float) Scene.GetIntendedHeight())), Pixmap.Format.RGB888);
|
WorldSave.getCurrentSave().header.createPreview();
|
||||||
scaled.drawPixmap(pixmap,
|
|
||||||
0, 0, pixmap.getWidth(), pixmap.getHeight(),
|
|
||||||
0, 0, scaled.getWidth(), scaled.getHeight());
|
|
||||||
pixmap.dispose();
|
|
||||||
if (WorldSave.getCurrentSave().header.preview != null)
|
|
||||||
WorldSave.getCurrentSave().header.preview.dispose();
|
|
||||||
WorldSave.getCurrentSave().header.preview = scaled;
|
|
||||||
AdventureApplicationAdapter.instance.switchScene(SceneType.StartScene.instance);
|
AdventureApplicationAdapter.instance.switchScene(SceneType.StartScene.instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,17 +128,45 @@ public class WorldBackground extends Actor {
|
|||||||
public void initialize() {
|
public void initialize() {
|
||||||
tileSize = WorldSave.getCurrentSave().getWorld().getTileSize();
|
tileSize = WorldSave.getCurrentSave().getWorld().getTileSize();
|
||||||
chunkSize = WorldSave.getCurrentSave().getWorld().getChunkSize();
|
chunkSize = WorldSave.getCurrentSave().getWorld().getChunkSize();
|
||||||
|
if(chunks!=null)
|
||||||
|
{
|
||||||
|
stage.GetSpriteGroup().clear();
|
||||||
|
for(int i=0;i<chunks.length;i++)
|
||||||
|
for(int j=0;j<chunks[i].length;j++)
|
||||||
|
if(chunks[i][j]!=null)
|
||||||
|
chunks[i][j].dispose();
|
||||||
|
}
|
||||||
chunks = new Texture[WorldSave.getCurrentSave().getWorld().getWidthInTiles()][WorldSave.getCurrentSave().getWorld().getHeightInTiles()];
|
chunks = new Texture[WorldSave.getCurrentSave().getWorld().getWidthInTiles()][WorldSave.getCurrentSave().getWorld().getHeightInTiles()];
|
||||||
ArrayList[][] createChunks = new ArrayList[WorldSave.getCurrentSave().getWorld().getWidthInTiles()][WorldSave.getCurrentSave().getWorld().getHeightInTiles()];
|
ArrayList[][] createChunks = new ArrayList[WorldSave.getCurrentSave().getWorld().getWidthInTiles()][WorldSave.getCurrentSave().getWorld().getHeightInTiles()];
|
||||||
chunksSprites = createChunks;
|
chunksSprites = createChunks;
|
||||||
ArrayList[][] createSprites = new ArrayList[WorldSave.getCurrentSave().getWorld().getWidthInTiles()][WorldSave.getCurrentSave().getWorld().getHeightInTiles()];
|
ArrayList[][] createSprites = new ArrayList[WorldSave.getCurrentSave().getWorld().getWidthInTiles()][WorldSave.getCurrentSave().getWorld().getHeightInTiles()];
|
||||||
chunksSpritesBackground = createSprites;
|
chunksSpritesBackground = createSprites;
|
||||||
|
|
||||||
|
|
||||||
|
if(loadingTexture==null)
|
||||||
|
{
|
||||||
Pixmap loadPix = new Pixmap(chunkSize * tileSize, chunkSize * tileSize, Pixmap.Format.RGB565);
|
Pixmap loadPix = new Pixmap(chunkSize * tileSize, chunkSize * tileSize, Pixmap.Format.RGB565);
|
||||||
loadPix.setColor(0.5f, 0.5f, 0.5f, 1);
|
loadPix.setColor(0.5f, 0.5f, 0.5f, 1);
|
||||||
loadPix.fill();
|
loadPix.fill();
|
||||||
loadingTexture = new Texture(loadPix);
|
loadingTexture = new Texture(loadPix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (int x = -1; x < 2; x++) {
|
||||||
|
for (int y = -1; y < 2; y++) {
|
||||||
|
Point point = new Point(currentChunkX + x, currentChunkY + y);
|
||||||
|
if (point.y < 0 || point.x < 0 || point.y >= chunks[0].length || point.x >= chunks.length)
|
||||||
|
continue;
|
||||||
|
loadChunk(point.x, point.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
super.clear();
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
int transChunkToWorld(int xy) {
|
int transChunkToWorld(int xy) {
|
||||||
return xy * tileSize * chunkSize;
|
return xy * tileSize * chunkSize;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ import forge.adventure.character.CharacterSprite;
|
|||||||
import forge.adventure.character.EnemySprite;
|
import forge.adventure.character.EnemySprite;
|
||||||
import forge.adventure.data.BiomeData;
|
import forge.adventure.data.BiomeData;
|
||||||
import forge.adventure.data.EnemyData;
|
import forge.adventure.data.EnemyData;
|
||||||
|
import forge.adventure.data.WorldData;
|
||||||
import forge.adventure.scene.*;
|
import forge.adventure.scene.*;
|
||||||
import forge.adventure.util.Current;
|
import forge.adventure.util.Current;
|
||||||
|
import forge.adventure.util.SaveFileContent;
|
||||||
|
import forge.adventure.util.SaveFileData;
|
||||||
import forge.adventure.world.World;
|
import forge.adventure.world.World;
|
||||||
import forge.adventure.world.WorldSave;
|
import forge.adventure.world.WorldSave;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
@@ -22,7 +25,7 @@ import java.util.Random;
|
|||||||
/**
|
/**
|
||||||
* Stage for the over world. Will handle monster spawns
|
* Stage for the over world. Will handle monster spawns
|
||||||
*/
|
*/
|
||||||
public class WorldStage extends GameStage {
|
public class WorldStage extends GameStage implements SaveFileContent {
|
||||||
|
|
||||||
private static WorldStage instance=null;
|
private static WorldStage instance=null;
|
||||||
protected EnemySprite currentMob;
|
protected EnemySprite currentMob;
|
||||||
@@ -75,6 +78,7 @@ public class WorldStage extends GameStage {
|
|||||||
AdventureApplicationAdapter.instance.switchScene(SceneType.DuelScene.instance);
|
AdventureApplicationAdapter.instance.switchScene(SceneType.DuelScene.instance);
|
||||||
});
|
});
|
||||||
currentMob = mob;
|
currentMob = mob;
|
||||||
|
WorldSave.getCurrentSave().autoSave();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,7 +228,6 @@ public class WorldStage extends GameStage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setBounds(WorldSave.getCurrentSave().getWorld().getWidthInPixels(), WorldSave.getCurrentSave().getWorld().getHeightInPixels());
|
setBounds(WorldSave.getCurrentSave().getWorld().getWidthInPixels(), WorldSave.getCurrentSave().getWorld().getHeightInPixels());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,4 +235,55 @@ public class WorldStage extends GameStage {
|
|||||||
public void leave() {
|
public void leave() {
|
||||||
GetPlayer().storePos();
|
GetPlayer().storePos();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(SaveFileData data) {
|
||||||
|
try {
|
||||||
|
for(Pair<Float, EnemySprite> enemy:enemies)
|
||||||
|
foregroundSprites.removeActor(enemy.getValue());
|
||||||
|
enemies.clear();
|
||||||
|
background.clear();
|
||||||
|
|
||||||
|
|
||||||
|
List<Float> timeouts= (List<Float>) data.readObject("timeouts");
|
||||||
|
List<String> names = (List<String>) data.readObject("names");
|
||||||
|
List<Float> x = (List<Float>) data.readObject("x");
|
||||||
|
List<Float> y = (List<Float>) data.readObject("y");
|
||||||
|
for(int i=0;i<timeouts.size();i++)
|
||||||
|
{
|
||||||
|
EnemySprite sprite = new EnemySprite(WorldData.getEnemy(names.get(i)));
|
||||||
|
sprite.setX(x.get(i));
|
||||||
|
sprite.setY(y.get(i));
|
||||||
|
enemies.add(Pair.of(timeouts.get(i),sprite));
|
||||||
|
foregroundSprites.addActor(sprite);
|
||||||
|
}
|
||||||
|
globalTimer=data.readFloat("globalTimer");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SaveFileData save() {
|
||||||
|
SaveFileData data=new SaveFileData();
|
||||||
|
List<Float> timeouts=new ArrayList<>();
|
||||||
|
List<String> names=new ArrayList<>();
|
||||||
|
List<Float> x=new ArrayList<>();
|
||||||
|
List<Float> y=new ArrayList<>();
|
||||||
|
for(Pair<Float, EnemySprite> enemy:enemies)
|
||||||
|
{
|
||||||
|
timeouts.add(enemy.getKey());
|
||||||
|
names.add(enemy.getValue().getData().name);
|
||||||
|
x.add(enemy.getValue().getX());
|
||||||
|
y.add(enemy.getValue().getY());
|
||||||
|
}
|
||||||
|
data.storeObject("timeouts",timeouts);
|
||||||
|
data.storeObject("names",names);
|
||||||
|
data.storeObject("x",x);
|
||||||
|
data.storeObject("y",y);
|
||||||
|
data.store("globalTimer",globalTimer);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ public class CardUtil {
|
|||||||
case MythicRare:
|
case MythicRare:
|
||||||
return 500;
|
return 500;
|
||||||
default:
|
default:
|
||||||
return 90000;
|
return 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
|
|
||||||
if(needsToBeDisposed)
|
if(needsToBeDisposed)
|
||||||
image.dispose();
|
image.dispose();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Reward getReward() {
|
public Reward getReward() {
|
||||||
@@ -54,18 +55,9 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onImageFetched() {
|
public void onImageFetched() {
|
||||||
if(ImageCache.imageKeyFileExists(reward.getCard().getImageKey(false)))
|
|
||||||
{
|
|
||||||
setCardImage(ImageCache.getImage(reward.getCard().getImageKey(false),false));
|
setCardImage(ImageCache.getImage(reward.getCard().getImageKey(false),false));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public enum Type
|
|
||||||
{
|
|
||||||
Shop,
|
|
||||||
Loot
|
|
||||||
|
|
||||||
}
|
|
||||||
public RewardActor(Reward reward,boolean flippable)
|
public RewardActor(Reward reward,boolean flippable)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
package forge.adventure.util;
|
package forge.adventure.util;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to save the content the the save game file
|
* Interface to save the content the the save game file
|
||||||
*/
|
*/
|
||||||
public interface SaveFileContent {
|
public interface SaveFileContent {
|
||||||
void writeToSaveFile(ObjectOutputStream saveFile) throws IOException ;
|
void load(SaveFileData data);
|
||||||
void readFromSaveFile(ObjectInputStream saveFile) throws IOException, ClassNotFoundException;
|
SaveFileData save();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,325 @@
|
|||||||
|
package forge.adventure.util;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap;
|
||||||
|
import com.badlogic.gdx.graphics.PixmapIO;
|
||||||
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class SaveFileData extends HashMap<String,byte[]>
|
||||||
|
{
|
||||||
|
public void store(String key,SaveFileData subData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream objStream=new ObjectOutputStream(stream);
|
||||||
|
objStream.writeObject(subData);
|
||||||
|
objStream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void store(String key,float subData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream objStream=new ObjectOutputStream(stream);
|
||||||
|
objStream.writeFloat(subData);
|
||||||
|
objStream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void store(String key,double subData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream objStream=new ObjectOutputStream(stream);
|
||||||
|
objStream.writeDouble(subData);
|
||||||
|
objStream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void store(String key,int subData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream objStream=new ObjectOutputStream(stream);
|
||||||
|
objStream.writeInt(subData);
|
||||||
|
objStream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void store(String key,long subData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream objStream=new ObjectOutputStream(stream);
|
||||||
|
objStream.writeLong(subData);
|
||||||
|
objStream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void store(String key,boolean subData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream objStream=new ObjectOutputStream(stream);
|
||||||
|
objStream.writeBoolean(subData);
|
||||||
|
objStream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void store(String key, Pixmap pixmap)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
PixmapIO.PNG png = new PixmapIO.PNG();
|
||||||
|
png.setFlipY(false);
|
||||||
|
png.write(stream, pixmap);
|
||||||
|
stream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void storeObject(String key,Object subData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream objStream=new ObjectOutputStream(stream);
|
||||||
|
objStream.writeObject(subData);
|
||||||
|
objStream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void store(String key,String subData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream objStream=new ObjectOutputStream(stream);
|
||||||
|
objStream.writeUTF(subData);
|
||||||
|
objStream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void store(String key, Vector2 vector) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream objStream=new ObjectOutputStream(stream);
|
||||||
|
objStream.writeFloat(vector.x);
|
||||||
|
objStream.writeFloat(vector.y);
|
||||||
|
objStream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void store(String key, Rectangle rectangle) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream=new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream objStream=new ObjectOutputStream(stream);
|
||||||
|
objStream.writeFloat(rectangle.x);
|
||||||
|
objStream.writeFloat(rectangle.y);
|
||||||
|
objStream.writeFloat(rectangle.width);
|
||||||
|
objStream.writeFloat(rectangle.height);
|
||||||
|
objStream.flush();
|
||||||
|
put(key,stream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaveFileData readSubData(String key)
|
||||||
|
{
|
||||||
|
if(!containsKey(key))
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayInputStream stream=new ByteArrayInputStream(get(key));
|
||||||
|
ObjectInputStream objStream=new ObjectInputStream(stream);
|
||||||
|
return (SaveFileData)objStream.readObject();
|
||||||
|
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public Object readObject(String key)
|
||||||
|
{
|
||||||
|
if(!containsKey(key))
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayInputStream stream=new ByteArrayInputStream(get(key));
|
||||||
|
ObjectInputStream objStream=new ObjectInputStream(stream);
|
||||||
|
return objStream.readObject();
|
||||||
|
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public String readString(String key)
|
||||||
|
{
|
||||||
|
if(!containsKey(key))
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayInputStream stream=new ByteArrayInputStream(get(key));
|
||||||
|
ObjectInputStream objStream=new ObjectInputStream(stream);
|
||||||
|
return objStream.readUTF();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long readLong(String key) {
|
||||||
|
if(!containsKey(key))
|
||||||
|
return 0;
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayInputStream stream=new ByteArrayInputStream(get(key));
|
||||||
|
ObjectInputStream objStream=new ObjectInputStream(stream);
|
||||||
|
return objStream.readLong();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
public float readFloat(String key)
|
||||||
|
{
|
||||||
|
if(!containsKey(key))
|
||||||
|
return 0.0f;
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayInputStream stream=new ByteArrayInputStream(get(key));
|
||||||
|
ObjectInputStream objStream=new ObjectInputStream(stream);
|
||||||
|
return objStream.readFloat();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double readDouble(String key)
|
||||||
|
{
|
||||||
|
if(!containsKey(key))
|
||||||
|
return 0.0;
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayInputStream stream=new ByteArrayInputStream(get(key));
|
||||||
|
ObjectInputStream objStream=new ObjectInputStream(stream);
|
||||||
|
return objStream.readDouble();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
public Vector2 readVector2(String key)
|
||||||
|
{
|
||||||
|
if(!containsKey(key))
|
||||||
|
return new Vector2();
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayInputStream stream=new ByteArrayInputStream(get(key));
|
||||||
|
ObjectInputStream objStream=new ObjectInputStream(stream);
|
||||||
|
float x= objStream.readFloat();
|
||||||
|
float y= objStream.readFloat();
|
||||||
|
return new Vector2(x,y);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return new Vector2();
|
||||||
|
}
|
||||||
|
public Rectangle readRectangle(String key)
|
||||||
|
{
|
||||||
|
if(!containsKey(key))
|
||||||
|
return new Rectangle();
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayInputStream stream=new ByteArrayInputStream(get(key));
|
||||||
|
ObjectInputStream objStream=new ObjectInputStream(stream);
|
||||||
|
float x= objStream.readFloat();
|
||||||
|
float y= objStream.readFloat();
|
||||||
|
float width= objStream.readFloat();
|
||||||
|
float height= objStream.readFloat();
|
||||||
|
return new Rectangle(x,y,width,height);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return new Rectangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Pixmap readPixmap(String key)
|
||||||
|
{
|
||||||
|
if(!containsKey(key))
|
||||||
|
return null;
|
||||||
|
return new Pixmap(get(key), 0, get(key).length);
|
||||||
|
}
|
||||||
|
public int readInt(String key)
|
||||||
|
{
|
||||||
|
if(!containsKey(key))
|
||||||
|
return 0;
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayInputStream stream=new ByteArrayInputStream(get(key));
|
||||||
|
ObjectInputStream objStream=new ObjectInputStream(stream);
|
||||||
|
return objStream.readInt();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
public boolean readBool(String key)
|
||||||
|
{
|
||||||
|
if(!containsKey(key))
|
||||||
|
return false;
|
||||||
|
try {
|
||||||
|
|
||||||
|
ByteArrayInputStream stream=new ByteArrayInputStream(get(key));
|
||||||
|
ObjectInputStream objStream=new ObjectInputStream(stream);
|
||||||
|
return objStream.readBoolean();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -44,10 +44,10 @@ public abstract class Serializer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WritePixmap(ObjectOutputStream out, Pixmap pixmap, boolean b) throws IOException {
|
public static void WritePixmap(ObjectOutputStream out, Pixmap pixmap, boolean flip) throws IOException {
|
||||||
if (pixmap != null) {
|
if (pixmap != null) {
|
||||||
PixmapIO.PNG png = new PixmapIO.PNG();
|
PixmapIO.PNG png = new PixmapIO.PNG();
|
||||||
png.setFlipY(b);
|
png.setFlipY(flip);
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
png.write(stream, pixmap);
|
png.write(stream, pixmap);
|
||||||
byte[] data = stream.toByteArray();
|
byte[] data = stream.toByteArray();
|
||||||
|
|||||||
@@ -2,25 +2,19 @@ package forge.adventure.world;
|
|||||||
|
|
||||||
import com.badlogic.gdx.files.FileHandle;
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
import com.badlogic.gdx.utils.Disposable;
|
import com.google.common.collect.Lists;
|
||||||
import forge.adventure.data.DifficultyData;
|
import forge.adventure.data.DifficultyData;
|
||||||
import forge.adventure.data.HeroListData;
|
import forge.adventure.data.HeroListData;
|
||||||
import forge.adventure.util.Config;
|
import forge.adventure.util.*;
|
||||||
import forge.adventure.util.Reward;
|
import forge.deck.CardPool;
|
||||||
import forge.adventure.util.SaveFileContent;
|
|
||||||
import forge.adventure.util.SignalList;
|
|
||||||
import forge.deck.Deck;
|
import forge.deck.Deck;
|
||||||
import forge.item.PaperCard;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that represents the player (not the player sprite)
|
* Class that represents the player (not the player sprite)
|
||||||
*/
|
*/
|
||||||
public class AdventurePlayer implements Serializable, Disposable, SaveFileContent {
|
public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||||
private Deck deck;
|
private Deck deck;
|
||||||
private int avatarIndex;
|
private int avatarIndex;
|
||||||
private int heroRace;
|
private int heroRace;
|
||||||
@@ -31,20 +25,25 @@ public class AdventurePlayer implements Serializable, Disposable, SaveFileConten
|
|||||||
private int gold=0;
|
private int gold=0;
|
||||||
private int maxLife=20;
|
private int maxLife=20;
|
||||||
private int life=20;
|
private int life=20;
|
||||||
private DifficultyData difficultyData;
|
private final DifficultyData difficultyData=new DifficultyData();
|
||||||
static public AdventurePlayer current()
|
static public AdventurePlayer current()
|
||||||
{
|
{
|
||||||
return WorldSave.currentSave.getPlayer();
|
return WorldSave.currentSave.getPlayer();
|
||||||
}
|
}
|
||||||
private List<PaperCard> cards=new ArrayList<>();
|
private final CardPool cards=new CardPool();
|
||||||
|
|
||||||
public void create(String n, Deck startingDeck, boolean male, int race, int avatar,DifficultyData difficultyData) {
|
public void create(String n, Deck startingDeck, boolean male, int race, int avatar,DifficultyData difficultyData) {
|
||||||
|
|
||||||
deck = startingDeck;
|
deck = startingDeck;
|
||||||
gold =difficultyData.staringMoney;
|
gold =difficultyData.staringMoney;
|
||||||
cards.addAll(deck.getAllCardsInASinglePool().toFlatList());
|
cards.clear();
|
||||||
|
cards.addAllFlat(deck.getAllCardsInASinglePool().toFlatList());
|
||||||
maxLife=difficultyData.startingLife;
|
maxLife=difficultyData.startingLife;
|
||||||
this.difficultyData=difficultyData;
|
this.difficultyData.startingLife=difficultyData.startingLife;
|
||||||
|
this.difficultyData.staringMoney=difficultyData.staringMoney;
|
||||||
|
this.difficultyData.startingDifficulty=difficultyData.startingDifficulty;
|
||||||
|
this.difficultyData.name=difficultyData.name;
|
||||||
|
this.difficultyData.enemyLifeFactor=difficultyData.enemyLifeFactor;
|
||||||
life=maxLife;
|
life=maxLife;
|
||||||
avatarIndex = avatar;
|
avatarIndex = avatar;
|
||||||
heroRace = race;
|
heroRace = race;
|
||||||
@@ -57,7 +56,7 @@ public class AdventurePlayer implements Serializable, Disposable, SaveFileConten
|
|||||||
public Deck getDeck() {
|
public Deck getDeck() {
|
||||||
return deck;
|
return deck;
|
||||||
}
|
}
|
||||||
public List<PaperCard> getCards() {
|
public CardPool getCards() {
|
||||||
return cards;
|
return cards;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,47 +81,71 @@ public class AdventurePlayer implements Serializable, Disposable, SaveFileConten
|
|||||||
this.worldPosY = worldPosY;
|
this.worldPosY = worldPosY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeToSaveFile(java.io.ObjectOutputStream out) throws IOException {
|
|
||||||
|
|
||||||
|
|
||||||
out.writeUTF(name);
|
|
||||||
out.writeFloat(worldPosX);
|
|
||||||
out.writeFloat(worldPosY);
|
|
||||||
out.writeInt(avatarIndex);
|
|
||||||
out.writeInt(heroRace);
|
|
||||||
out.writeBoolean(isFemale);
|
|
||||||
out.writeInt(gold);
|
|
||||||
out.writeInt(life);
|
|
||||||
out.writeInt(maxLife);
|
|
||||||
out.writeObject(deck);
|
|
||||||
out.writeObject(cards);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readFromSaveFile(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
public void load(SaveFileData data) {
|
||||||
name = in.readUTF();
|
|
||||||
worldPosX = in.readFloat();
|
|
||||||
worldPosY = in.readFloat();
|
|
||||||
|
|
||||||
avatarIndex = in.readInt();
|
this.difficultyData.startingLife=data.readInt("startingLife");
|
||||||
heroRace = in.readInt();
|
this.difficultyData.staringMoney=data.readInt("staringMoney");
|
||||||
isFemale = in.readBoolean();
|
this.difficultyData.startingDifficulty=data.readBool("startingDifficulty");
|
||||||
gold = in.readInt();
|
this.difficultyData.name=data.readString("difficultyName");
|
||||||
life = in.readInt();
|
this.difficultyData.enemyLifeFactor=data.readFloat("enemyLifeFactor");
|
||||||
maxLife = in.readInt();
|
|
||||||
deck = (Deck) in.readObject();
|
|
||||||
cards = (List) in.readObject();
|
|
||||||
|
|
||||||
|
|
||||||
|
name = data.readString("name");
|
||||||
|
worldPosX = data.readFloat("worldPosX");
|
||||||
|
worldPosY = data.readFloat("worldPosY");
|
||||||
|
|
||||||
|
avatarIndex = data.readInt("avatarIndex");
|
||||||
|
heroRace = data.readInt("heroRace");
|
||||||
|
isFemale = data.readBool("isFemale");
|
||||||
|
gold = data.readInt("gold");
|
||||||
|
life = data.readInt("life");
|
||||||
|
maxLife = data.readInt("maxLife");
|
||||||
|
|
||||||
|
deck = new Deck(data.readString("deckName"));
|
||||||
|
deck.getMain().addAll(CardPool.fromCardList(Lists.newArrayList((String[])data.readObject("deckCards"))));
|
||||||
|
|
||||||
|
cards.clear();
|
||||||
|
cards.addAll(CardPool.fromCardList(Lists.newArrayList((String[])data.readObject("cards"))));
|
||||||
|
|
||||||
onLifeTotalChangeList.emit();
|
onLifeTotalChangeList.emit();
|
||||||
onGoldChangeList.emit();
|
onGoldChangeList.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
@Override
|
||||||
|
public SaveFileData save() {
|
||||||
|
SaveFileData data= new SaveFileData();
|
||||||
|
|
||||||
|
|
||||||
|
data.store("startingLife",this.difficultyData.startingLife);
|
||||||
|
data.store("staringMoney",this.difficultyData.staringMoney);
|
||||||
|
data.store("startingDifficulty",this.difficultyData.startingDifficulty);
|
||||||
|
data.store("difficultyName",this.difficultyData.name);
|
||||||
|
data.store("enemyLifeFactor",this.difficultyData.enemyLifeFactor);
|
||||||
|
|
||||||
|
|
||||||
|
data.store("name",name);
|
||||||
|
data.store("worldPosX",worldPosX);
|
||||||
|
data.store("worldPosY",worldPosY);
|
||||||
|
data.store("avatarIndex",avatarIndex);
|
||||||
|
data.store("heroRace",heroRace);
|
||||||
|
data.store("isFemale",isFemale);
|
||||||
|
data.store("gold",gold);
|
||||||
|
data.store("life",life);
|
||||||
|
data.store("maxLife",maxLife);
|
||||||
|
data.store("deckName",deck.getName());
|
||||||
|
|
||||||
|
|
||||||
|
data.storeObject("deckCards",deck.getMain().toCardList("\n").split("\n"));
|
||||||
|
data.storeObject("cards",cards.toCardList("\n").split("\n"));
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public String spriteName() {
|
public String spriteName() {
|
||||||
return HeroListData.getHero(heroRace, isFemale);
|
return HeroListData.getHero(heroRace, isFemale);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,8 @@ import com.badlogic.gdx.utils.Array;
|
|||||||
import forge.adventure.data.PointOfInterestData;
|
import forge.adventure.data.PointOfInterestData;
|
||||||
import forge.adventure.util.Config;
|
import forge.adventure.util.Config;
|
||||||
import forge.adventure.util.SaveFileContent;
|
import forge.adventure.util.SaveFileContent;
|
||||||
import forge.adventure.util.Serializer;
|
import forge.adventure.util.SaveFileData;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,23 +18,28 @@ public class PointOfInterest implements SaveFileContent {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToSaveFile(ObjectOutputStream saveFile) throws IOException {
|
public void load(SaveFileData saveFileData) {
|
||||||
saveFile.writeUTF(data.name);
|
|
||||||
Serializer.writeVector(saveFile,position);
|
data=PointOfInterestData.getPointOfInterest(saveFileData.readString("name"));
|
||||||
Serializer.writeRectangle(saveFile,rectangle);
|
position.set(saveFileData.readVector2("position"));
|
||||||
saveFile.writeInt(spriteIndex);
|
rectangle.set(saveFileData.readRectangle("rectangle"));
|
||||||
|
spriteIndex=saveFileData.readInt("spriteIndex");
|
||||||
|
|
||||||
|
|
||||||
|
oldMapId="";
|
||||||
|
Array<Sprite> textureAtlas = Config.instance().getAtlas(this.data.spriteAtlas).createSprites(this.data.sprite);
|
||||||
|
sprite = textureAtlas.get(spriteIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readFromSaveFile(ObjectInputStream saveFile) throws IOException {
|
public SaveFileData save() {
|
||||||
String name= saveFile.readUTF();
|
|
||||||
data=PointOfInterestData.getPointOfInterest(name);
|
SaveFileData data=new SaveFileData();
|
||||||
Serializer.readVector(saveFile,position);
|
data.store("name",this.data.name);
|
||||||
Serializer.readRectangle(saveFile,rectangle);
|
data.store("position",position);
|
||||||
spriteIndex=saveFile.readInt();
|
data.store("rectangle",rectangle);
|
||||||
oldMapId="";
|
data.store("spriteIndex",spriteIndex);
|
||||||
Array<Sprite> textureAtlas = Config.instance().getAtlas(data.spriteAtlas).createSprites(data.sprite);
|
return data;
|
||||||
sprite = textureAtlas.get(spriteIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PointOfInterestData data;
|
PointOfInterestData data;
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package forge.adventure.world;
|
package forge.adventure.world;
|
||||||
|
|
||||||
import forge.adventure.util.SaveFileContent;
|
import forge.adventure.util.SaveFileContent;
|
||||||
|
import forge.adventure.util.SaveFileData;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -48,42 +46,48 @@ public class PointOfInterestMap implements SaveFileContent {
|
|||||||
return mapObjects[chunkX][chunkY];
|
return mapObjects[chunkX][chunkY];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeToSaveFile(ObjectOutputStream saveFile) throws IOException {
|
|
||||||
saveFile.writeInt(numberOfChunksX);
|
|
||||||
saveFile.writeInt(numberOfChunksY);
|
|
||||||
saveFile.writeInt(tileSize);
|
|
||||||
saveFile.writeInt(chunkSize);
|
|
||||||
for (int x = 0; x < numberOfChunksX; x++) {
|
|
||||||
for (int y = 0; y < numberOfChunksY; y++) {
|
|
||||||
saveFile.writeInt(mapObjects[x][y].size());
|
|
||||||
for(PointOfInterest poi:mapObjects[x][y])
|
|
||||||
{
|
|
||||||
poi.writeToSaveFile(saveFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readFromSaveFile(ObjectInputStream saveFile) throws IOException, ClassNotFoundException {
|
public void load(SaveFileData data) {
|
||||||
numberOfChunksX=saveFile.readInt();
|
numberOfChunksX=data.readInt("numberOfChunksX");
|
||||||
numberOfChunksY=saveFile.readInt();
|
numberOfChunksY=data.readInt("numberOfChunksY");
|
||||||
tileSize=saveFile.readInt();
|
tileSize=data.readInt("tileSize");
|
||||||
chunkSize=saveFile.readInt();
|
chunkSize=data.readInt("chunkSize");
|
||||||
|
|
||||||
mapObjects = new List[numberOfChunksX][numberOfChunksY];
|
mapObjects = new List[numberOfChunksX][numberOfChunksY];
|
||||||
for (int x = 0; x < numberOfChunksX; x++) {
|
for (int x = 0; x < numberOfChunksX; x++) {
|
||||||
for (int y = 0; y < numberOfChunksY; y++) {
|
for (int y = 0; y < numberOfChunksY; y++) {
|
||||||
mapObjects[x][y] = new ArrayList();
|
mapObjects[x][y] = new ArrayList();
|
||||||
int arraySize=saveFile.readInt();
|
int arraySize=data.readInt("mapObjects["+x +"]["+y+"]");
|
||||||
for(int i=0;i<arraySize;i++)
|
for(int i=0;i<arraySize;i++)
|
||||||
{
|
{
|
||||||
PointOfInterest pointsOfInterest=new PointOfInterest();
|
PointOfInterest pointsOfInterest=new PointOfInterest();
|
||||||
pointsOfInterest.readFromSaveFile(saveFile);
|
pointsOfInterest.load(data.readSubData("mapObjects["+x +"]["+y+"]["+i+"]"));
|
||||||
mapObjects[x][y].add(pointsOfInterest);
|
mapObjects[x][y].add(pointsOfInterest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SaveFileData save() {
|
||||||
|
SaveFileData data=new SaveFileData();
|
||||||
|
|
||||||
|
data.store("numberOfChunksX",numberOfChunksX);
|
||||||
|
data.store("numberOfChunksY",numberOfChunksY);
|
||||||
|
data.store("tileSize",tileSize);
|
||||||
|
data.store("chunkSize",chunkSize);
|
||||||
|
data.store("numberOfChunksX",numberOfChunksX);
|
||||||
|
|
||||||
|
for (int x = 0; x < numberOfChunksX; x++) {
|
||||||
|
for (int y = 0; y < numberOfChunksY; y++) {
|
||||||
|
data.store("mapObjects["+x +"]["+y+"]",mapObjects[x][y].size());
|
||||||
|
for(int i=0;i<mapObjects[x][y].size();i++)
|
||||||
|
{
|
||||||
|
data.store("mapObjects["+x +"]["+y+"]["+i+"]",mapObjects[x][y].get(i).save());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package forge.adventure.world;
|
|||||||
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
import forge.adventure.data.BiomeSpriteData;
|
import forge.adventure.data.BiomeSpriteData;
|
||||||
|
import forge.adventure.util.SaveFileContent;
|
||||||
|
import forge.adventure.util.SaveFileData;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -13,10 +13,37 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Class that hold all sprites as a list for each chunk
|
* Class that hold all sprites as a list for each chunk
|
||||||
*/
|
*/
|
||||||
public class SpritesDataMap implements Serializable {
|
public class SpritesDataMap implements SaveFileContent {
|
||||||
|
public class BiomeSpriteDataMap extends HashMap<Integer, BiomeSpriteData> implements SaveFileContent
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void load(SaveFileData data) {
|
||||||
|
clear();
|
||||||
|
List<Integer> keyList=(List<Integer>)data.readObject("keyList");
|
||||||
|
for(Integer key:keyList)
|
||||||
|
{
|
||||||
|
BiomeSpriteData biomeData=new BiomeSpriteData();
|
||||||
|
biomeData.load(data.readSubData(key.toString()));
|
||||||
|
put(key,biomeData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SaveFileData save() {
|
||||||
|
|
||||||
|
SaveFileData data = new SaveFileData();
|
||||||
|
List<Integer> keyList=new ArrayList<>();
|
||||||
|
for(Entry<Integer, BiomeSpriteData> entry:this.entrySet())
|
||||||
|
{
|
||||||
|
keyList.add(entry.getKey());
|
||||||
|
data.store(entry.getKey().toString(),entry.getValue().save());
|
||||||
|
}
|
||||||
|
data.storeObject("keyList",keyList);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
private final int numberOfChunks;
|
private final int numberOfChunks;
|
||||||
HashMap<Integer, BiomeSpriteData> objectData = new HashMap<>();
|
BiomeSpriteDataMap objectData = new BiomeSpriteDataMap();
|
||||||
HashMap<String, Integer> objectKeys = new HashMap<>();
|
HashMap<String, Integer> objectKeys = new HashMap<>();
|
||||||
int tileSize;
|
int tileSize;
|
||||||
int chunkSize;
|
int chunkSize;
|
||||||
@@ -34,25 +61,7 @@ public class SpritesDataMap implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
|
|
||||||
|
|
||||||
out.writeObject(mapObjects);
|
|
||||||
out.writeObject(objectData);
|
|
||||||
out.writeObject(objectKeys);
|
|
||||||
out.writeInt(tileSize);
|
|
||||||
out.writeInt(chunkSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
|
|
||||||
mapObjects = (List<Pair<Vector2, Integer>>[][]) in.readObject();
|
|
||||||
objectData = (HashMap<Integer, BiomeSpriteData>) in.readObject();
|
|
||||||
objectKeys = (HashMap<String, Integer>) in.readObject();
|
|
||||||
tileSize = in.readInt();
|
|
||||||
chunkSize = in.readInt();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public BiomeSpriteData get(int id) {
|
public BiomeSpriteData get(int id) {
|
||||||
return objectData.get(id);
|
return objectData.get(id);
|
||||||
@@ -86,4 +95,28 @@ public class SpritesDataMap implements Serializable {
|
|||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
return mapObjects[chunkX][chunkY];
|
return mapObjects[chunkX][chunkY];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(SaveFileData data) {
|
||||||
|
|
||||||
|
objectData.load(data.readSubData("objectData"));
|
||||||
|
mapObjects = (List<Pair<Vector2, Integer>>[][])data.readObject("mapObjects");
|
||||||
|
objectKeys = (HashMap<String, Integer>)data.readObject("objectKeys");
|
||||||
|
tileSize = data.readInt("tileSize");
|
||||||
|
chunkSize = data.readInt("chunkSize");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SaveFileData save() {
|
||||||
|
SaveFileData data=new SaveFileData();
|
||||||
|
data.store("objectData",objectData.save());
|
||||||
|
data.storeObject("mapObjects",mapObjects);
|
||||||
|
data.storeObject("objectKeys",objectKeys);
|
||||||
|
data.store("tileSize",tileSize);
|
||||||
|
data.store("chunkSize",chunkSize);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ import forge.adventure.scene.Scene;
|
|||||||
import forge.adventure.util.Config;
|
import forge.adventure.util.Config;
|
||||||
import forge.adventure.util.Paths;
|
import forge.adventure.util.Paths;
|
||||||
import forge.adventure.util.SaveFileContent;
|
import forge.adventure.util.SaveFileContent;
|
||||||
import forge.adventure.util.Serializer;
|
import forge.adventure.util.SaveFileData;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -39,6 +38,7 @@ public class World implements Disposable, SaveFileContent {
|
|||||||
private BiomeTexture[] biomeTexture;
|
private BiomeTexture[] biomeTexture;
|
||||||
private long seed;
|
private long seed;
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
|
private boolean worldDataLoaded=false;
|
||||||
|
|
||||||
public Random getRandom()
|
public Random getRandom()
|
||||||
{
|
{
|
||||||
@@ -48,49 +48,65 @@ public class World implements Disposable, SaveFileContent {
|
|||||||
return (int) (Math.log(Long.highestOneBit(biome)) / Math.log(2));
|
return (int) (Math.log(Long.highestOneBit(biome)) / Math.log(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void loadWorldData()
|
||||||
public void writeToSaveFile(java.io.ObjectOutputStream out) throws IOException {
|
{
|
||||||
|
if(worldDataLoaded)
|
||||||
|
return;
|
||||||
Serializer.WritePixmap(out, biomeImage);
|
|
||||||
out.writeObject(biomeMap);
|
|
||||||
out.writeObject(terrainMap);
|
|
||||||
out.writeInt(width);
|
|
||||||
out.writeInt(height);
|
|
||||||
out.writeObject(mapObjectIds);
|
|
||||||
mapPoiIds.writeToSaveFile(out);
|
|
||||||
out.writeLong(seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readFromSaveFile(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
|
|
||||||
FileHandle handle = Config.instance().getFile(Paths.WORLD);
|
FileHandle handle = Config.instance().getFile(Paths.WORLD);
|
||||||
String rawJson = handle.readString();
|
String rawJson = handle.readString();
|
||||||
data = (new Json()).fromJson(WorldData.class, rawJson);
|
this.data = (new Json()).fromJson(WorldData.class, rawJson);
|
||||||
|
|
||||||
if (biomeImage != null) biomeImage.dispose();
|
|
||||||
biomeImage = Serializer.ReadPixmap(in);
|
|
||||||
biomeMap = (long[][]) in.readObject();
|
|
||||||
terrainMap = (int[][]) in.readObject();
|
|
||||||
width = in.readInt();
|
|
||||||
height = in.readInt();
|
|
||||||
mapObjectIds = (SpritesDataMap) in.readObject();
|
|
||||||
if(mapPoiIds==null)mapPoiIds=new PointOfInterestMap(1,1,1,1);
|
|
||||||
mapPoiIds.readFromSaveFile(in);
|
|
||||||
seed = in.readLong();
|
|
||||||
|
|
||||||
biomeTexture = new BiomeTexture[data.GetBiomes().size() + 1];
|
biomeTexture = new BiomeTexture[data.GetBiomes().size() + 1];
|
||||||
for(int i = 0; i<data.GetBiomes().size(); i++)
|
|
||||||
{
|
int biomeIndex=0;
|
||||||
biomeTexture[i] = new BiomeTexture(data.GetBiomes().get(i), data.tileSize);
|
for (BiomeData biome : data.GetBiomes()) {
|
||||||
|
|
||||||
|
biomeTexture[biomeIndex] = new BiomeTexture(biome, data.tileSize);
|
||||||
|
biomeIndex++;
|
||||||
}
|
}
|
||||||
biomeTexture[data.GetBiomes().size()] = new BiomeTexture(data.roadTileset, data.tileSize);
|
biomeTexture[biomeIndex] = new BiomeTexture(data.roadTileset, data.tileSize);
|
||||||
|
worldDataLoaded=true;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(SaveFileData saveFileData) {
|
||||||
|
|
||||||
|
if(biomeImage!=null)
|
||||||
|
biomeImage.dispose();
|
||||||
|
|
||||||
|
loadWorldData();
|
||||||
|
|
||||||
|
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());
|
||||||
|
mapObjectIds.load(saveFileData.readSubData("mapObjectIds"));
|
||||||
|
mapPoiIds = new PointOfInterestMap(getChunkSize(), this.data.tileSize, this.data.width / getChunkSize(),this.data.height / getChunkSize());
|
||||||
|
mapPoiIds.load(saveFileData.readSubData("mapPoiIds"));
|
||||||
|
seed=saveFileData.readLong("seed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SaveFileData save() {
|
||||||
|
|
||||||
|
SaveFileData data=new SaveFileData();
|
||||||
|
|
||||||
|
data.store("biomeImage",biomeImage);
|
||||||
|
data.storeObject("biomeMap",biomeMap);
|
||||||
|
data.storeObject("terrainMap",terrainMap);
|
||||||
|
data.store("width",width);
|
||||||
|
data.store("height",height);
|
||||||
|
data.store("mapObjectIds",mapObjectIds.save());
|
||||||
|
data.store("mapPoiIds",mapPoiIds.save());
|
||||||
|
data.store("seed",seed);
|
||||||
|
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public BiomeSpriteData getObject(int id) {
|
public BiomeSpriteData getObject(int id) {
|
||||||
return mapObjectIds.get(id);
|
return mapObjectIds.get(id);
|
||||||
}
|
}
|
||||||
@@ -201,9 +217,7 @@ public class World implements Disposable, SaveFileContent {
|
|||||||
|
|
||||||
public World generateNew(long seed) {
|
public World generateNew(long seed) {
|
||||||
|
|
||||||
FileHandle handle = Config.instance().getFile(Paths.WORLD);
|
loadWorldData();
|
||||||
String rawJson = handle.readString();
|
|
||||||
data = (new Json()).fromJson(WorldData.class, rawJson);
|
|
||||||
if(seed==0)
|
if(seed==0)
|
||||||
{
|
{
|
||||||
seed=random.nextLong();
|
seed=random.nextLong();
|
||||||
@@ -231,11 +245,9 @@ public class World implements Disposable, SaveFileContent {
|
|||||||
pix.fill();
|
pix.fill();
|
||||||
|
|
||||||
int biomeIndex = -1;
|
int biomeIndex = -1;
|
||||||
biomeTexture = new BiomeTexture[data.GetBiomes().size() + 1];
|
|
||||||
for (BiomeData biome : data.GetBiomes()) {
|
for (BiomeData biome : data.GetBiomes()) {
|
||||||
|
|
||||||
biomeIndex++;
|
biomeIndex++;
|
||||||
biomeTexture[biomeIndex] = new BiomeTexture(biome, data.tileSize);
|
|
||||||
int biomeXStart = (int) Math.round(biome.startPointX * (double) width);
|
int biomeXStart = (int) Math.round(biome.startPointX * (double) width);
|
||||||
int biomeYStart = (int) Math.round(biome.startPointY * (double) height);
|
int biomeYStart = (int) Math.round(biome.startPointY * (double) height);
|
||||||
int biomeWidth = (int) Math.round(biome.width * (double) width);
|
int biomeWidth = (int) Math.round(biome.width * (double) width);
|
||||||
@@ -380,7 +392,6 @@ public class World implements Disposable, SaveFileContent {
|
|||||||
|
|
||||||
biomeIndex++;
|
biomeIndex++;
|
||||||
pix.setColor(1, 1, 1, 1);
|
pix.setColor(1, 1, 1, 1);
|
||||||
biomeTexture[biomeIndex] = new BiomeTexture(data.roadTileset, data.tileSize);
|
|
||||||
for (Pair<PointOfInterest, PointOfInterest> townPair : allSortedTowns) {
|
for (Pair<PointOfInterest, PointOfInterest> townPair : allSortedTowns) {
|
||||||
|
|
||||||
Vector2 currentPoint = townPair.getKey().getTilePosition(data.tileSize);
|
Vector2 currentPoint = townPair.getKey().getTilePosition(data.tileSize);
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package forge.adventure.world;
|
package forge.adventure.world;
|
||||||
|
|
||||||
import forge.adventure.data.DifficultyData;
|
import forge.adventure.data.DifficultyData;
|
||||||
|
import forge.adventure.stage.WorldStage;
|
||||||
import forge.adventure.util.Config;
|
import forge.adventure.util.Config;
|
||||||
|
import forge.adventure.util.SaveFileData;
|
||||||
|
import forge.adventure.util.SignalList;
|
||||||
import forge.deck.Deck;
|
import forge.deck.Deck;
|
||||||
import forge.localinstance.properties.ForgeProfileProperties;
|
import forge.localinstance.properties.ForgeProfileProperties;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -16,16 +19,17 @@ import java.util.zip.InflaterInputStream;
|
|||||||
*/
|
*/
|
||||||
public class WorldSave {
|
public class WorldSave {
|
||||||
|
|
||||||
static final int AUTO_SAVE_SLOT =-1;
|
static final public int AUTO_SAVE_SLOT =-1;
|
||||||
static final int QUICK_SAVE_SLOT =-2;
|
static final public int QUICK_SAVE_SLOT =-2;
|
||||||
static final int INVALID_SAVE_SLOT =-3;
|
static final public int INVALID_SAVE_SLOT =-3;
|
||||||
static WorldSave currentSave=new WorldSave();
|
static final WorldSave currentSave=new WorldSave();
|
||||||
public WorldSaveHeader header = new WorldSaveHeader();
|
public WorldSaveHeader header = new WorldSaveHeader();
|
||||||
private final AdventurePlayer player=new AdventurePlayer();
|
private final AdventurePlayer player=new AdventurePlayer();
|
||||||
private final World world=new World();
|
private final World world=new World();
|
||||||
private final HashMap<String,PointOfInterestChanges> pointOfInterestChanges=new HashMap<>();
|
private final HashMap<String,PointOfInterestChanges> pointOfInterestChanges=new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
private final SignalList onLoadList=new SignalList();
|
||||||
|
|
||||||
public final World getWorld()
|
public final World getWorld()
|
||||||
{
|
{
|
||||||
@@ -36,6 +40,10 @@ public class WorldSave {
|
|||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onLoad(Runnable run)
|
||||||
|
{
|
||||||
|
onLoadList.add(run);
|
||||||
|
}
|
||||||
public PointOfInterestChanges getPointOfInterestChanges(String id)
|
public PointOfInterestChanges getPointOfInterestChanges(String id)
|
||||||
{
|
{
|
||||||
if(!pointOfInterestChanges.containsKey(id))
|
if(!pointOfInterestChanges.containsKey(id))
|
||||||
@@ -53,8 +61,13 @@ public class WorldSave {
|
|||||||
ObjectInputStream oos = new ObjectInputStream(inf))
|
ObjectInputStream oos = new ObjectInputStream(inf))
|
||||||
{
|
{
|
||||||
currentSave.header = (WorldSaveHeader) oos.readObject();
|
currentSave.header = (WorldSaveHeader) oos.readObject();
|
||||||
currentSave.player.readFromSaveFile(oos);
|
SaveFileData mainData=(SaveFileData)oos.readObject();
|
||||||
currentSave.world.readFromSaveFile(oos);
|
currentSave.player.load(mainData.readSubData("player"));
|
||||||
|
currentSave.world.load(mainData.readSubData("world"));
|
||||||
|
WorldStage.getInstance().load(mainData.readSubData("worldStage"));
|
||||||
|
|
||||||
|
currentSave.onLoadList.emit();
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (ClassNotFoundException | IOException e) {
|
} catch (ClassNotFoundException | IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -105,10 +118,19 @@ public class WorldSave {
|
|||||||
currentSave.player.create(name, starterDeck, male, race, avatarIndex,diff);
|
currentSave.player.create(name, starterDeck, male, race, avatarIndex,diff);
|
||||||
currentSave.player.setWorldPosY((int) (currentSave.world.getData().playerStartPosY * currentSave.world.getData().height * currentSave.world.getTileSize()));
|
currentSave.player.setWorldPosY((int) (currentSave.world.getData().playerStartPosY * currentSave.world.getData().height * currentSave.world.getTileSize()));
|
||||||
currentSave.player.setWorldPosX((int) (currentSave.world.getData().playerStartPosX * currentSave.world.getData().width * currentSave.world.getTileSize()));
|
currentSave.player.setWorldPosX((int) (currentSave.world.getData().playerStartPosX * currentSave.world.getData().width * currentSave.world.getTileSize()));
|
||||||
|
currentSave.onLoadList.emit();
|
||||||
return currentSave;
|
return currentSave;
|
||||||
//return currentSave = ret;
|
//return currentSave = ret;
|
||||||
}
|
}
|
||||||
|
public boolean autoSave() {
|
||||||
|
return save("auto save",AUTO_SAVE_SLOT);
|
||||||
|
}
|
||||||
|
public boolean quickSave() {
|
||||||
|
return save("quick save",QUICK_SAVE_SLOT);
|
||||||
|
}
|
||||||
|
public boolean quickLoad() {
|
||||||
|
return load(QUICK_SAVE_SLOT);
|
||||||
|
}
|
||||||
public boolean save(String text, int currentSlot) {
|
public boolean save(String text, int currentSlot) {
|
||||||
header.name = text;
|
header.name = text;
|
||||||
|
|
||||||
@@ -121,8 +143,12 @@ public class WorldSave {
|
|||||||
ObjectOutputStream oos = new ObjectOutputStream(def))
|
ObjectOutputStream oos = new ObjectOutputStream(def))
|
||||||
{
|
{
|
||||||
oos.writeObject(header);
|
oos.writeObject(header);
|
||||||
player.writeToSaveFile(oos);
|
SaveFileData mainData=new SaveFileData();
|
||||||
world.writeToSaveFile(oos);
|
mainData.store("player",currentSave.player.save());
|
||||||
|
mainData.store("world",currentSave.world.save());
|
||||||
|
mainData.store("worldStage", WorldStage.getInstance().save());
|
||||||
|
|
||||||
|
oos.writeObject(mainData);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -132,11 +158,4 @@ public class WorldSave {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dispose() {
|
|
||||||
|
|
||||||
header.dispose();
|
|
||||||
player.dispose();
|
|
||||||
world.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package forge.adventure.world;
|
package forge.adventure.world;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.graphics.Pixmap;
|
import com.badlogic.gdx.graphics.Pixmap;
|
||||||
import com.badlogic.gdx.utils.Disposable;
|
import com.badlogic.gdx.utils.Disposable;
|
||||||
|
import forge.adventure.scene.Scene;
|
||||||
import forge.adventure.util.Serializer;
|
import forge.adventure.util.Serializer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -27,6 +29,8 @@ public class WorldSaveHeader implements java.io.Serializable, Disposable {
|
|||||||
|
|
||||||
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
name = in.readUTF();
|
name = in.readUTF();
|
||||||
|
if(preview!=null)
|
||||||
|
preview.dispose();
|
||||||
preview = Serializer.ReadPixmap(in);
|
preview = Serializer.ReadPixmap(in);
|
||||||
saveDate = (Date) in.readObject();
|
saveDate = (Date) in.readObject();
|
||||||
|
|
||||||
@@ -35,4 +39,16 @@ public class WorldSaveHeader implements java.io.Serializable, Disposable {
|
|||||||
public void dispose() {
|
public void dispose() {
|
||||||
preview.dispose();
|
preview.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void createPreview() {
|
||||||
|
Pixmap pixmap = Pixmap.createFromFrameBuffer(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||||
|
Pixmap scaled = new Pixmap(WorldSaveHeader.previewImageWidth, (int) (WorldSaveHeader.previewImageWidth / (Scene.GetIntendedWidth() / (float) Scene.GetIntendedHeight())), Pixmap.Format.RGB888);
|
||||||
|
scaled.drawPixmap(pixmap,
|
||||||
|
0, 0, pixmap.getWidth(), pixmap.getHeight(),
|
||||||
|
0, 0, scaled.getWidth(), scaled.getHeight());
|
||||||
|
pixmap.dispose();
|
||||||
|
if (preview != null)
|
||||||
|
preview.dispose();
|
||||||
|
preview = scaled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -712,6 +712,30 @@ public class AiController {
|
|||||||
return AiPlayDecision.CantPlaySa;
|
return AiPlayDecision.CantPlaySa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check a predefined condition
|
||||||
|
if (sa.hasParam("AICheckSVar")) {
|
||||||
|
final Card host = sa.getHostCard();
|
||||||
|
final String svarToCheck = sa.getParam("AICheckSVar");
|
||||||
|
String comparator = "GE";
|
||||||
|
int compareTo = 1;
|
||||||
|
|
||||||
|
if (sa.hasParam("AISVarCompare")) {
|
||||||
|
final String fullCmp = sa.getParam("AISVarCompare");
|
||||||
|
comparator = fullCmp.substring(0, 2);
|
||||||
|
final String strCmpTo = fullCmp.substring(2);
|
||||||
|
try {
|
||||||
|
compareTo = Integer.parseInt(strCmpTo);
|
||||||
|
} catch (final Exception ignored) {
|
||||||
|
compareTo = AbilityUtils.calculateAmount(host, host.getSVar(strCmpTo), sa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int left = AbilityUtils.calculateAmount(host, svarToCheck, sa);
|
||||||
|
if (!Expressions.compare(left, comparator, compareTo)) {
|
||||||
|
return AiPlayDecision.AnotherTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int oldCMC = -1;
|
int oldCMC = -1;
|
||||||
boolean xCost = sa.getPayCosts().hasXInAnyCostPart() || sa.getHostCard().hasStartOfKeyword("Strive");
|
boolean xCost = sa.getPayCosts().hasXInAnyCostPart() || sa.getHostCard().hasStartOfKeyword("Strive");
|
||||||
if (!xCost) {
|
if (!xCost) {
|
||||||
@@ -746,7 +770,7 @@ public class AiController {
|
|||||||
// one is warded and can't be paid for.
|
// one is warded and can't be paid for.
|
||||||
if (sa.usesTargeting()) {
|
if (sa.usesTargeting()) {
|
||||||
for (Card tgt : sa.getTargets().getTargetCards()) {
|
for (Card tgt : sa.getTargets().getTargetCards()) {
|
||||||
if (tgt.hasKeyword(Keyword.WARD) && tgt.getController().isOpponentOf(sa.getHostCard().getController())) {
|
if (tgt.hasKeyword(Keyword.WARD) && tgt.isInPlay() && tgt.getController().isOpponentOf(sa.getHostCard().getController())) {
|
||||||
int amount = 0;
|
int amount = 0;
|
||||||
Cost wardCost = ComputerUtilCard.getTotalWardCost(tgt);
|
Cost wardCost = ComputerUtilCard.getTotalWardCost(tgt);
|
||||||
if (wardCost.hasManaCost()) {
|
if (wardCost.hasManaCost()) {
|
||||||
|
|||||||
@@ -1746,12 +1746,12 @@ public class ComputerUtilCard {
|
|||||||
int att = 0;
|
int att = 0;
|
||||||
if (stAb.hasParam("AddPower")) {
|
if (stAb.hasParam("AddPower")) {
|
||||||
String addP = stAb.getParam("AddPower");
|
String addP = stAb.getParam("AddPower");
|
||||||
att = AbilityUtils.calculateAmount(addP.startsWith("Affected") ? vCard : c, addP, stAb, true);
|
att = AbilityUtils.calculateAmount(addP.contains("Affected") ? vCard : c, addP, stAb, true);
|
||||||
}
|
}
|
||||||
int def = 0;
|
int def = 0;
|
||||||
if (stAb.hasParam("AddToughness")) {
|
if (stAb.hasParam("AddToughness")) {
|
||||||
String addT = stAb.getParam("AddToughness");
|
String addT = stAb.getParam("AddToughness");
|
||||||
def = AbilityUtils.calculateAmount(addT.startsWith("Affected") ? vCard : c, addT, stAb, true);
|
def = AbilityUtils.calculateAmount(addT.contains("Affected") ? vCard : c, addT, stAb, true);
|
||||||
}
|
}
|
||||||
vCard.addPTBoost(att, def, c.getTimestamp(), stAb.getId());
|
vCard.addPTBoost(att, def, c.getTimestamp(), stAb.getId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -592,7 +592,7 @@ public class ComputerUtilCost {
|
|||||||
// Ward - will be accounted for when rechecking a targeted ability
|
// Ward - will be accounted for when rechecking a targeted ability
|
||||||
if (sa.usesTargeting()) {
|
if (sa.usesTargeting()) {
|
||||||
for (Card tgt : sa.getTargets().getTargetCards()) {
|
for (Card tgt : sa.getTargets().getTargetCards()) {
|
||||||
if (tgt.hasKeyword(Keyword.WARD) && tgt.getController().isOpponentOf(sa.getHostCard().getController())) {
|
if (tgt.hasKeyword(Keyword.WARD) && tgt.isInPlay() && tgt.getController().isOpponentOf(sa.getHostCard().getController())) {
|
||||||
Cost wardCost = ComputerUtilCard.getTotalWardCost(tgt);
|
Cost wardCost = ComputerUtilCard.getTotalWardCost(tgt);
|
||||||
if (wardCost.hasManaCost()) {
|
if (wardCost.hasManaCost()) {
|
||||||
extraManaNeeded += wardCost.getTotalMana().getCMC();
|
extraManaNeeded += wardCost.getTotalMana().getCMC();
|
||||||
|
|||||||
@@ -1745,6 +1745,10 @@ public class AttachAi extends SpellAbilityAi {
|
|||||||
sa.getTargets().add(tgt);
|
sa.getTargets().add(tgt);
|
||||||
}
|
}
|
||||||
return sa.isTargetNumberValid();
|
return sa.isTargetNumberValid();
|
||||||
|
} else if ("Remembered".equals(sa.getParam("Defined")) && sa.getParent() != null
|
||||||
|
&& sa.getParent().getApi() == ApiType.Token && sa.getParent().hasParam("RememberTokens")) {
|
||||||
|
// Living Weapon or similar
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package forge.ai.ability;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import forge.game.card.*;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
@@ -32,14 +34,7 @@ import forge.game.GlobalRuleChange;
|
|||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.card.Card;
|
|
||||||
import forge.game.card.CardCollection;
|
|
||||||
import forge.game.card.CardCollectionView;
|
|
||||||
import forge.game.card.CardLists;
|
|
||||||
import forge.game.card.CardPredicates;
|
|
||||||
import forge.game.card.CardPredicates.Presets;
|
import forge.game.card.CardPredicates.Presets;
|
||||||
import forge.game.card.CardUtil;
|
|
||||||
import forge.game.card.CounterEnumType;
|
|
||||||
import forge.game.combat.Combat;
|
import forge.game.combat.Combat;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
import forge.game.cost.CostDiscard;
|
import forge.game.cost.CostDiscard;
|
||||||
@@ -1397,6 +1392,57 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Reload Undying and Persist, get rid of -1/-1 counters, get rid of enemy auras if able
|
||||||
|
Card bestChoice = null;
|
||||||
|
int bestEval = 0;
|
||||||
|
for (Card c : aiPermanents) {
|
||||||
|
if (c.isCreature()) {
|
||||||
|
boolean hasValuableAttachments = false;
|
||||||
|
boolean hasOppAttachments = false;
|
||||||
|
int numNegativeCounters = 0;
|
||||||
|
int numTotalCounters = 0;
|
||||||
|
for (Card attached : c.getAttachedCards()) {
|
||||||
|
if (attached.isAura()) {
|
||||||
|
if (attached.getController() == c.getController()) {
|
||||||
|
hasValuableAttachments = true;
|
||||||
|
} else if (attached.getController().isOpponentOf(c.getController())) {
|
||||||
|
hasOppAttachments = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<CounterType, Integer> counters = c.getCounters();
|
||||||
|
for (CounterType ct : counters.keySet()) {
|
||||||
|
int amount = counters.get(ct);
|
||||||
|
if (ComputerUtil.isNegativeCounter(ct, c)) {
|
||||||
|
numNegativeCounters += amount;
|
||||||
|
}
|
||||||
|
numTotalCounters += amount;
|
||||||
|
}
|
||||||
|
if (hasValuableAttachments || (ComputerUtilCard.isUselessCreature(ai, c) && !hasOppAttachments)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Card considered = null;
|
||||||
|
if ((c.hasKeyword(Keyword.PERSIST) || c.hasKeyword(Keyword.UNDYING))
|
||||||
|
&& !ComputerUtilCard.hasActiveUndyingOrPersist(c)) {
|
||||||
|
considered = c;
|
||||||
|
} else if (hasOppAttachments || (numTotalCounters > 0 && numNegativeCounters > numTotalCounters / 2)) {
|
||||||
|
considered = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (considered != null) {
|
||||||
|
int eval = ComputerUtilCard.evaluateCreature(c);
|
||||||
|
if (eval > bestEval) {
|
||||||
|
bestEval = eval;
|
||||||
|
bestChoice = considered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bestChoice != null) {
|
||||||
|
return bestChoice;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,10 @@ public final class ImageKeys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<String, File> cachedCards = new HashMap<>(50000);
|
private static final Map<String, File> cachedCards = new HashMap<>(50000);
|
||||||
|
private static HashSet<String> missingCards = new HashSet<>();
|
||||||
|
public static void clearMissingCards() {
|
||||||
|
missingCards.clear();
|
||||||
|
}
|
||||||
public static File getCachedCardsFile(String key) {
|
public static File getCachedCardsFile(String key) {
|
||||||
return cachedCards.get(key);
|
return cachedCards.get(key);
|
||||||
}
|
}
|
||||||
@@ -101,6 +105,9 @@ public final class ImageKeys {
|
|||||||
dir = CACHE_CARD_PICS_DIR;
|
dir = CACHE_CARD_PICS_DIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (missingCards.contains(filename))
|
||||||
|
return null;
|
||||||
|
|
||||||
File cachedFile = cachedCards.get(filename);
|
File cachedFile = cachedCards.get(filename);
|
||||||
if (cachedFile != null) {
|
if (cachedFile != null) {
|
||||||
return cachedFile;
|
return cachedFile;
|
||||||
@@ -237,6 +244,8 @@ public final class ImageKeys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// System.out.println("File not found, no image created: " + key);
|
// System.out.println("File not found, no image created: " + key);
|
||||||
|
//add missing cards
|
||||||
|
missingCards.add(filename);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -178,7 +178,13 @@ public final class GameActionUtil {
|
|||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final Cost disturbCost = new Cost(k[1], true);
|
final Cost disturbCost = new Cost(k[1], true);
|
||||||
|
|
||||||
final SpellAbility newSA = sa.copyWithManaCostReplaced(activator, disturbCost);
|
SpellAbility newSA;
|
||||||
|
if (source.getAlternateState().getType().hasSubtype("Aura")) {
|
||||||
|
newSA = source.getAlternateState().getFirstAbility().copyWithManaCostReplaced(activator,
|
||||||
|
disturbCost);
|
||||||
|
} else {
|
||||||
|
newSA = sa.copyWithManaCostReplaced(activator, disturbCost);
|
||||||
|
}
|
||||||
newSA.setActivatingPlayer(activator);
|
newSA.setActivatingPlayer(activator);
|
||||||
|
|
||||||
newSA.putParam("PrecostDesc", "Disturb —");
|
newSA.putParam("PrecostDesc", "Disturb —");
|
||||||
@@ -190,11 +196,6 @@ public final class GameActionUtil {
|
|||||||
desc.append("(").append(inst.getReminderText()).append(")");
|
desc.append("(").append(inst.getReminderText()).append(")");
|
||||||
newSA.setDescription(desc.toString());
|
newSA.setDescription(desc.toString());
|
||||||
newSA.putParam("AfterDescription", "(Disturbed)");
|
newSA.putParam("AfterDescription", "(Disturbed)");
|
||||||
final String type = source.getAlternateState().getType().toString();
|
|
||||||
if (!type.contains("Creature")) {
|
|
||||||
final String name = source.getAlternateState().getName();
|
|
||||||
newSA.putParam("StackDescription", name + " — " + type + " (Disturbed)");
|
|
||||||
}
|
|
||||||
|
|
||||||
newSA.setAlternativeCost(AlternativeCost.Disturb);
|
newSA.setAlternativeCost(AlternativeCost.Disturb);
|
||||||
newSA.getRestrictions().setZone(ZoneType.Graveyard);
|
newSA.getRestrictions().setZone(ZoneType.Graveyard);
|
||||||
@@ -733,7 +734,7 @@ public final class GameActionUtil {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
CardCollection completeList = new CardCollection();
|
CardCollection completeList = new CardCollection();
|
||||||
PlayerCollection players = game.getPlayers();
|
PlayerCollection players = new PlayerCollection(game.getPlayers());
|
||||||
// CR 613.7k use APNAP
|
// CR 613.7k use APNAP
|
||||||
int indexAP = players.indexOf(game.getPhaseHandler().getPlayerTurn());
|
int indexAP = players.indexOf(game.getPhaseHandler().getPlayerTurn());
|
||||||
if (indexAP != -1) {
|
if (indexAP != -1) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public final class GameObjectPredicates {
|
|||||||
return new Predicate<GameObject>() {
|
return new Predicate<GameObject>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(final GameObject c) {
|
public boolean apply(final GameObject c) {
|
||||||
return (c != null) && c.isValid(restrictions, sourceController, source, spellAbility);
|
return c != null && c.isValid(restrictions, sourceController, source, spellAbility);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,6 +197,15 @@ public final class CardPredicates {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Predicate<Card> sharesLandTypeWith(final Card card) {
|
||||||
|
return new Predicate<Card>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(final Card c) {
|
||||||
|
return c.sharesLandTypeWith(card);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static final Predicate<Card> possibleBlockers(final Card attacker) {
|
public static final Predicate<Card> possibleBlockers(final Card attacker) {
|
||||||
return new Predicate<Card>() {
|
return new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -825,6 +825,11 @@ public class CardProperty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (property.startsWith("sharesLandTypeWith")) {
|
||||||
|
final String restriction = property.split("sharesLandTypeWith ")[1];
|
||||||
|
if (!Iterables.any(AbilityUtils.getDefinedCards(source, restriction, spellAbility), CardPredicates.sharesLandTypeWith(card))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else if (property.equals("sharesPermanentTypeWith")) {
|
} else if (property.equals("sharesPermanentTypeWith")) {
|
||||||
if (!card.sharesPermanentTypeWith(source)) {
|
if (!card.sharesPermanentTypeWith(source)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -832,12 +832,7 @@ public class Cost implements Serializable {
|
|||||||
sb.append(Cost.NUM_NAMES[i]);
|
sb.append(Cost.NUM_NAMES[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.append(" ");
|
sb.append(" ").append(type);
|
||||||
char firstChar = type.charAt(0);
|
|
||||||
if (Character.isUpperCase(firstChar)) { //fix case of type before appending
|
|
||||||
type = Character.toLowerCase(firstChar) + type.substring(1);
|
|
||||||
}
|
|
||||||
sb.append(type);
|
|
||||||
if (1 != i) {
|
if (1 != i) {
|
||||||
sb.append("s");
|
sb.append("s");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,7 +199,9 @@ public class CostDiscard extends CostPartWithList {
|
|||||||
// discard itself for cycling cost
|
// discard itself for cycling cost
|
||||||
runParams.put(AbilityKey.Cycling, true);
|
runParams.put(AbilityKey.Cycling, true);
|
||||||
}
|
}
|
||||||
return targetCard.getController().discard(targetCard, null, null, runParams);
|
// if this is caused by 118.12 it's also an effect
|
||||||
|
SpellAbility cause = targetCard.getGame().getStack().isResolving(ability.getHostCard()) ? ability : null;
|
||||||
|
return targetCard.getController().discard(targetCard, cause, null, runParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -226,8 +228,7 @@ public class CostDiscard extends CostPartWithList {
|
|||||||
protected void handleChangeZoneTrigger(Player payer, SpellAbility ability, CardCollectionView targetCards) {
|
protected void handleChangeZoneTrigger(Player payer, SpellAbility ability, CardCollectionView targetCards) {
|
||||||
super.handleChangeZoneTrigger(payer, ability, targetCards);
|
super.handleChangeZoneTrigger(payer, ability, targetCards);
|
||||||
|
|
||||||
if (!targetCards.isEmpty())
|
if (!targetCards.isEmpty()) {
|
||||||
{
|
|
||||||
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||||
runParams.put(AbilityKey.Player, payer);
|
runParams.put(AbilityKey.Player, payer);
|
||||||
runParams.put(AbilityKey.Cards, new CardCollection(targetCards));
|
runParams.put(AbilityKey.Cards, new CardCollection(targetCards));
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ public class CostExert extends CostPartWithList {
|
|||||||
public final boolean canPay(final SpellAbility ability, final Player payer) {
|
public final boolean canPay(final SpellAbility ability, final Player payer) {
|
||||||
final Card source = ability.getHostCard();
|
final Card source = ability.getHostCard();
|
||||||
|
|
||||||
|
|
||||||
if (!this.payCostFromSource()) {
|
if (!this.payCostFromSource()) {
|
||||||
boolean needsAnnoucement = ability.hasParam("Announce") && this.getType().contains(ability.getParam("Announce"));
|
boolean needsAnnoucement = ability.hasParam("Announce") && this.getType().contains(ability.getParam("Announce"));
|
||||||
|
|
||||||
@@ -94,7 +93,6 @@ public class CostExert extends CostPartWithList {
|
|||||||
|
|
||||||
|
|
||||||
return needsAnnoucement || (amount == null) || (typeList.size() >= amount);
|
return needsAnnoucement || (amount == null) || (typeList.size() >= amount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ public class CostGainLife extends CostPart {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public <T> T accept(ICostVisitor<T> visitor) {
|
public <T> T accept(ICostVisitor<T> visitor) {
|
||||||
return visitor.visit(this);
|
return visitor.visit(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ public class CostPutCounter extends CostPartWithList {
|
|||||||
|
|
||||||
return !typeList.isEmpty();
|
return !typeList.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -204,7 +203,6 @@ public class CostPutCounter extends CostPartWithList {
|
|||||||
tempTable.triggerCountersPutAll(ability.getHostCard().getGame());
|
tempTable.triggerCountersPutAll(ability.getHostCard().getGame());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see forge.game.cost.CostPartWithList#resetLists()
|
* @see forge.game.cost.CostPartWithList#resetLists()
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ public class CostTap extends CostPart {
|
|||||||
@Override
|
@Override
|
||||||
public boolean isUndoable() { return true; }
|
public boolean isUndoable() { return true; }
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReusable() { return true; }
|
public boolean isReusable() { return true; }
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ public class CostUntap extends CostPart {
|
|||||||
@Override
|
@Override
|
||||||
public boolean isRenewable() { return true; }
|
public boolean isRenewable() { return true; }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ public class Mana {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (!(other instanceof Mana)) {
|
if (!(other instanceof Mana)) {
|
||||||
@@ -89,12 +88,10 @@ public class Mana {
|
|||||||
return this.manaAbility != null && (!manaAbility.getManaRestrictions().isEmpty() || !manaAbility.getExtraManaRestriction().isEmpty());
|
return this.manaAbility != null && (!manaAbility.getManaRestrictions().isEmpty() || !manaAbility.getExtraManaRestriction().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public final boolean addsNoCounterMagic(SpellAbility saBeingPaid) {
|
public final boolean addsNoCounterMagic(SpellAbility saBeingPaid) {
|
||||||
return this.manaAbility != null && manaAbility.cannotCounterPaidWith(saBeingPaid);
|
return this.manaAbility != null && manaAbility.cannotCounterPaidWith(saBeingPaid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public final boolean addsCounters(SpellAbility saBeingPaid) {
|
public final boolean addsCounters(SpellAbility saBeingPaid) {
|
||||||
return this.manaAbility != null && manaAbility.addsCounters(saBeingPaid);
|
return this.manaAbility != null && manaAbility.addsCounters(saBeingPaid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,8 +154,7 @@ public class ManaCostBeingPaid {
|
|||||||
for (ManaCostShard shard : manaCost) {
|
for (ManaCostShard shard : manaCost) {
|
||||||
if (shard == ManaCostShard.X) {
|
if (shard == ManaCostShard.X) {
|
||||||
cntX++;
|
cntX++;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
increaseShard(shard, 1, false);
|
increaseShard(shard, 1, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -588,8 +587,7 @@ public class ManaCostBeingPaid {
|
|||||||
for (ManaCostShard shard : extra) {
|
for (ManaCostShard shard : extra) {
|
||||||
if (shard == ManaCostShard.X) {
|
if (shard == ManaCostShard.X) {
|
||||||
cntX++;
|
cntX++;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
increaseShard(shard, 1, false);
|
increaseShard(shard, 1, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,4 +119,4 @@ public class ExtraTurn {
|
|||||||
this.cantSetSchemesInMotion = noSchemes;
|
this.cantSetSchemesInMotion = noSchemes;
|
||||||
}
|
}
|
||||||
|
|
||||||
} //end class Untap
|
}
|
||||||
|
|||||||
@@ -227,7 +227,6 @@ public class Untap extends Phase {
|
|||||||
for (final Card c : game.getCardsInGame()) {
|
for (final Card c : game.getCardsInGame()) {
|
||||||
c.removeExertedBy(player);
|
c.removeExertedBy(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end doUntap
|
} // end doUntap
|
||||||
|
|
||||||
private static void optionalUntap(final Card c) {
|
private static void optionalUntap(final Card c) {
|
||||||
@@ -261,7 +260,7 @@ public class Untap extends Phase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(final Card c) {
|
public boolean apply(final Card c) {
|
||||||
return ((c.isPhasedOut() && c.isDirectlyPhasedOut()) || c.hasKeyword(Keyword.PHASING));
|
return (c.isPhasedOut() && c.isDirectlyPhasedOut()) || c.hasKeyword(Keyword.PHASING);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ public final class PlayerPredicates {
|
|||||||
return Predicates.not(isCardInPlay(cardName));
|
return Predicates.not(isCardInPlay(cardName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static final Predicate<Player> hasCounters() {
|
public static final Predicate<Player> hasCounters() {
|
||||||
return new Predicate<Player>() {
|
return new Predicate<Player>() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -350,7 +350,6 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (sa.getHostCard() != null) {
|
if (sa.getHostCard() != null) {
|
||||||
if (sa.getHostCard().isValid(restriction, this.getSourceCard().getController(), this.getSourceCard(), null)) {
|
if (sa.getHostCard().isValid(restriction, this.getSourceCard().getController(), this.getSourceCard(), null)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -583,7 +582,6 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
public Card getSourceCard() {
|
public Card getSourceCard() {
|
||||||
return sourceCard;
|
return sourceCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSourceCard(final Card host) {
|
public void setSourceCard(final Card host) {
|
||||||
sourceCard = host;
|
sourceCard = host;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -682,12 +682,12 @@ public final class StaticAbilityContinuous {
|
|||||||
|
|
||||||
// set P/T
|
// set P/T
|
||||||
if (layer == StaticAbilityLayer.SETPT) {
|
if (layer == StaticAbilityLayer.SETPT) {
|
||||||
if ((setPower != null) || (setToughness != null)) {
|
if (setPower != null || setToughness != null) {
|
||||||
// non CharacteristicDefining
|
// non CharacteristicDefining
|
||||||
if (setP.startsWith("Affected")) {
|
if (setP.contains("Affected")) {
|
||||||
setPower = AbilityUtils.calculateAmount(affectedCard, setP, stAb, true);
|
setPower = AbilityUtils.calculateAmount(affectedCard, setP, stAb, true);
|
||||||
}
|
}
|
||||||
if (setT.startsWith("Affected")) {
|
if (setT.contains("Affected")) {
|
||||||
setToughness = AbilityUtils.calculateAmount(affectedCard, setT, stAb, true);
|
setToughness = AbilityUtils.calculateAmount(affectedCard, setT, stAb, true);
|
||||||
}
|
}
|
||||||
affectedCard.addNewPT(setPower, setToughness,
|
affectedCard.addNewPT(setPower, setToughness,
|
||||||
@@ -697,10 +697,10 @@ public final class StaticAbilityContinuous {
|
|||||||
|
|
||||||
// add P/T bonus
|
// add P/T bonus
|
||||||
if (layer == StaticAbilityLayer.MODIFYPT) {
|
if (layer == StaticAbilityLayer.MODIFYPT) {
|
||||||
if (addP.startsWith("Affected")) {
|
if (addP.contains("Affected")) {
|
||||||
powerBonus = AbilityUtils.calculateAmount(affectedCard, addP, stAb, true);
|
powerBonus = AbilityUtils.calculateAmount(affectedCard, addP, stAb, true);
|
||||||
}
|
}
|
||||||
if (addT.startsWith("Affected")) {
|
if (addT.contains("Affected")) {
|
||||||
toughnessBonus = AbilityUtils.calculateAmount(affectedCard, addT, stAb, true);
|
toughnessBonus = AbilityUtils.calculateAmount(affectedCard, addT, stAb, true);
|
||||||
}
|
}
|
||||||
affectedCard.addPTBoost(powerBonus, toughnessBonus, se.getTimestamp(), stAb.getId());
|
affectedCard.addPTBoost(powerBonus, toughnessBonus, se.getTimestamp(), stAb.getId());
|
||||||
@@ -709,7 +709,7 @@ public final class StaticAbilityContinuous {
|
|||||||
// add keywords
|
// add keywords
|
||||||
// TODO regular keywords currently don't try to use keyword multiplier
|
// TODO regular keywords currently don't try to use keyword multiplier
|
||||||
// (Although nothing uses it at this time)
|
// (Although nothing uses it at this time)
|
||||||
if ((addKeywords != null) || (removeKeywords != null) || removeAllAbilities) {
|
if (addKeywords != null || removeKeywords != null || removeAllAbilities) {
|
||||||
List<String> newKeywords = null;
|
List<String> newKeywords = null;
|
||||||
if (addKeywords != null) {
|
if (addKeywords != null) {
|
||||||
newKeywords = Lists.newArrayList(addKeywords);
|
newKeywords = Lists.newArrayList(addKeywords);
|
||||||
|
|||||||
@@ -85,5 +85,4 @@ public abstract class Expressions {
|
|||||||
return " ? ";
|
return " ? ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
} // end class AllZoneUtil
|
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ public class GuiDesktop implements IGuiBase {
|
|||||||
@Override
|
@Override
|
||||||
public void clearImageCache() {
|
public void clearImageCache() {
|
||||||
ImageCache.clear();
|
ImageCache.clear();
|
||||||
|
ImageKeys.clearMissingCards();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public class ImageCache {
|
|||||||
public static void clear() {
|
public static void clear() {
|
||||||
_CACHE.invalidateAll();
|
_CACHE.invalidateAll();
|
||||||
_missingIconKeys.clear();
|
_missingIconKeys.clear();
|
||||||
|
ImageKeys.clearMissingCards();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import forge.model.FModel;
|
|||||||
import forge.player.GamePlayerUtil;
|
import forge.player.GamePlayerUtil;
|
||||||
import forge.screens.deckeditor.CDeckEditorUI;
|
import forge.screens.deckeditor.CDeckEditorUI;
|
||||||
import forge.screens.deckeditor.controllers.CEditorTokenViewer;
|
import forge.screens.deckeditor.controllers.CEditorTokenViewer;
|
||||||
|
import forge.sound.MusicPlaylist;
|
||||||
import forge.sound.SoundSystem;
|
import forge.sound.SoundSystem;
|
||||||
import forge.toolbox.*;
|
import forge.toolbox.*;
|
||||||
import forge.util.Localizer;
|
import forge.util.Localizer;
|
||||||
@@ -27,6 +28,8 @@ import org.apache.commons.lang3.tuple.Pair;
|
|||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -262,6 +265,8 @@ public enum CSubmenuPreferences implements ICDoc {
|
|||||||
initializeAutoUpdaterComboBox();
|
initializeAutoUpdaterComboBox();
|
||||||
initializeMulliganRuleComboBox();
|
initializeMulliganRuleComboBox();
|
||||||
initializeAiProfilesComboBox();
|
initializeAiProfilesComboBox();
|
||||||
|
initializeSoundSetsComboBox();
|
||||||
|
initializeMusicSetsComboBox();
|
||||||
initializeStackAdditionsComboBox();
|
initializeStackAdditionsComboBox();
|
||||||
initializeLandPlayedComboBox();
|
initializeLandPlayedComboBox();
|
||||||
initializeColorIdentityCombobox();
|
initializeColorIdentityCombobox();
|
||||||
@@ -466,6 +471,35 @@ public enum CSubmenuPreferences implements ICDoc {
|
|||||||
panel.setComboBox(comboBox, selectedItem);
|
panel.setComboBox(comboBox, selectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initializeSoundSetsComboBox() {
|
||||||
|
final FPref userSetting = FPref.UI_CURRENT_SOUND_SET;
|
||||||
|
final FComboBoxPanel<String> panel = this.view.getSoundSetsComboBoxPanel();
|
||||||
|
final FComboBox<String> comboBox = createComboBox(SoundSystem.instance.getAvailableSoundSets(), userSetting);
|
||||||
|
final String selectedItem = this.prefs.getPref(userSetting);
|
||||||
|
panel.setComboBox(comboBox, selectedItem);
|
||||||
|
comboBox.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent actionEvent) {
|
||||||
|
SoundSystem.instance.invalidateSoundCache();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeMusicSetsComboBox() {
|
||||||
|
final FPref userSetting = FPref.UI_CURRENT_MUSIC_SET;
|
||||||
|
final FComboBoxPanel<String> panel = this.view.getMusicSetsComboBoxPanel();
|
||||||
|
final FComboBox<String> comboBox = createComboBox(SoundSystem.instance.getAvailableMusicSets(), userSetting);
|
||||||
|
final String selectedItem = this.prefs.getPref(userSetting);
|
||||||
|
panel.setComboBox(comboBox, selectedItem);
|
||||||
|
comboBox.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent actionEvent) {
|
||||||
|
MusicPlaylist.invalidateMusicPlaylist();
|
||||||
|
SoundSystem.instance.changeBackgroundTrack();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void initializeCardArtPreference() {
|
private void initializeCardArtPreference() {
|
||||||
final String latestOpt = Localizer.getInstance().getMessage("latestArtOpt");
|
final String latestOpt = Localizer.getInstance().getMessage("latestArtOpt");
|
||||||
final String originalOpt = Localizer.getInstance().getMessage("originalArtOpt");
|
final String originalOpt = Localizer.getInstance().getMessage("originalArtOpt");
|
||||||
|
|||||||
@@ -128,6 +128,8 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
|||||||
private final FComboBoxPanel<String> cbpCardArtFormat = new FComboBoxPanel<>(localizer.getMessage("cbpCardArtFormat")+":");
|
private final FComboBoxPanel<String> cbpCardArtFormat = new FComboBoxPanel<>(localizer.getMessage("cbpCardArtFormat")+":");
|
||||||
private final FComboBoxPanel<String> cbpCardArtPreference = new FComboBoxPanel<>(localizer.getMessage("lblPreferredArt")+":");
|
private final FComboBoxPanel<String> cbpCardArtPreference = new FComboBoxPanel<>(localizer.getMessage("lblPreferredArt")+":");
|
||||||
private final FComboBoxPanel<String> cbpMulliganRule = new FComboBoxPanel<>(localizer.getMessage("cbpMulliganRule")+":");
|
private final FComboBoxPanel<String> cbpMulliganRule = new FComboBoxPanel<>(localizer.getMessage("cbpMulliganRule")+":");
|
||||||
|
private final FComboBoxPanel<String> cbpSoundSets = new FComboBoxPanel<>(localizer.getMessage("cbpSoundSets")+":");
|
||||||
|
private final FComboBoxPanel<String> cbpMusicSets = new FComboBoxPanel<>(localizer.getMessage("cbpMusicSets")+":");
|
||||||
private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<>(localizer.getMessage("cbpAiProfiles")+":");
|
private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<>(localizer.getMessage("cbpAiProfiles")+":");
|
||||||
private final FComboBoxPanel<String> cbpStackAdditions = new FComboBoxPanel<>(localizer.getMessage("cbpStackAdditions")+":");
|
private final FComboBoxPanel<String> cbpStackAdditions = new FComboBoxPanel<>(localizer.getMessage("cbpStackAdditions")+":");
|
||||||
private final FComboBoxPanel<String> cbpLandPlayed = new FComboBoxPanel<>(localizer.getMessage("cbpLandPlayed")+":");
|
private final FComboBoxPanel<String> cbpLandPlayed = new FComboBoxPanel<>(localizer.getMessage("cbpLandPlayed")+":");
|
||||||
@@ -414,9 +416,15 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
|||||||
pnlPrefs.add(cbEnableSounds, titleConstraints);
|
pnlPrefs.add(cbEnableSounds, titleConstraints);
|
||||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnableSounds")), descriptionConstraints);
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnableSounds")), descriptionConstraints);
|
||||||
|
|
||||||
|
pnlPrefs.add(cbpSoundSets, comboBoxConstraints);
|
||||||
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlpSoundSets")), descriptionConstraints);
|
||||||
|
|
||||||
pnlPrefs.add(cbEnableMusic, titleConstraints);
|
pnlPrefs.add(cbEnableMusic, titleConstraints);
|
||||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnableMusic")), descriptionConstraints);
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnableMusic")), descriptionConstraints);
|
||||||
|
|
||||||
|
pnlPrefs.add(cbpMusicSets, comboBoxConstraints);
|
||||||
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlpMusicSets")), descriptionConstraints);
|
||||||
|
|
||||||
pnlPrefs.add(cbAltSoundSystem, titleConstraints);
|
pnlPrefs.add(cbAltSoundSystem, titleConstraints);
|
||||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlAltSoundSystem")), descriptionConstraints);
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlAltSoundSystem")), descriptionConstraints);
|
||||||
pnlPrefs.add(cbSROptimize, titleConstraints);
|
pnlPrefs.add(cbSROptimize, titleConstraints);
|
||||||
@@ -740,6 +748,14 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
|||||||
return cbpMulliganRule;
|
return cbpMulliganRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FComboBoxPanel<String> getSoundSetsComboBoxPanel() {
|
||||||
|
return cbpSoundSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FComboBoxPanel<String> getMusicSetsComboBoxPanel() {
|
||||||
|
return cbpMusicSets;
|
||||||
|
}
|
||||||
|
|
||||||
public FComboBoxPanel<String> getAiProfilesComboBoxPanel() {
|
public FComboBoxPanel<String> getAiProfilesComboBoxPanel() {
|
||||||
return cbpAiProfiles;
|
return cbpAiProfiles;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,9 +40,6 @@ import javax.sound.sampled.UnsupportedAudioFileException;
|
|||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import com.sipgate.mp3wav.Converter;
|
import com.sipgate.mp3wav.Converter;
|
||||||
|
|
||||||
import forge.localinstance.properties.ForgeConstants;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SoundSystem - a simple sound playback system for Forge.
|
* SoundSystem - a simple sound playback system for Forge.
|
||||||
* Do not use directly. Instead, use the {@link forge.sound.SoundEffectType} enumeration.
|
* Do not use directly. Instead, use the {@link forge.sound.SoundEffectType} enumeration.
|
||||||
@@ -64,7 +61,7 @@ public class AudioClip implements IAudioClip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean fileExists(String fileName) {
|
public static boolean fileExists(String fileName) {
|
||||||
File fSound = new File(ForgeConstants.SOUND_DIR, fileName);
|
File fSound = new File(SoundSystem.instance.getSoundDirectory(), fileName);
|
||||||
return fSound.exists();
|
return fSound.exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +192,7 @@ public class AudioClip implements IAudioClip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Clip createClip(String filename) {
|
private Clip createClip(String filename) {
|
||||||
File fSound = new File(ForgeConstants.SOUND_DIR, filename);
|
File fSound = new File(SoundSystem.instance.getSoundDirectory(), filename);
|
||||||
if (!fSound.exists()) {
|
if (!fSound.exists()) {
|
||||||
throw new IllegalArgumentException("Sound file " + fSound.toString() + " does not exist, cannot make a clip of it");
|
throw new IllegalArgumentException("Sound file " + fSound.toString() + " does not exist, cannot make a clip of it");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,8 +133,8 @@ public class FCheckBoxTree extends JTree {
|
|||||||
this.enabledChildrenCount = enabledChildrenCount;
|
this.enabledChildrenCount = enabledChildrenCount;
|
||||||
}
|
}
|
||||||
public boolean hasChildren() { return this.numberOfChildren > 0; }
|
public boolean hasChildren() { return this.numberOfChildren > 0; }
|
||||||
public boolean allChildrenSelected(){ return this.numberOfChildren == this.selectedChildrenCount; };
|
public boolean allChildrenSelected() { return this.numberOfChildren == this.selectedChildrenCount; }
|
||||||
public boolean allChildrenEnabled(){ return this.enabledChildrenCount == this.numberOfChildren; };
|
public boolean allChildrenEnabled() { return this.enabledChildrenCount == this.numberOfChildren; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// == Fields of the FCheckboxTree class ==
|
// == Fields of the FCheckboxTree class ==
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ public class Forge implements ApplicationListener {
|
|||||||
public static String CJK_Font = "";
|
public static String CJK_Font = "";
|
||||||
public static int hoveredCount = 0;
|
public static int hoveredCount = 0;
|
||||||
public static boolean afterDBloaded = false;
|
public static boolean afterDBloaded = false;
|
||||||
|
public static int mouseButtonID = 0;
|
||||||
|
|
||||||
public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation, int totalRAM, boolean isTablet, int AndroidAPI, String AndroidRelease, String deviceName) {
|
public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation, int totalRAM, boolean isTablet, int AndroidAPI, String AndroidRelease, String deviceName) {
|
||||||
if (GuiBase.getInterface() == null) {
|
if (GuiBase.getInterface() == null) {
|
||||||
@@ -771,6 +772,7 @@ public class Forge implements ApplicationListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mouseButtonID = button;
|
||||||
return super.touchDown(x, y, pointer, button);
|
return super.touchDown(x, y, pointer, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ import forge.screens.LoadingOverlay;
|
|||||||
import forge.screens.match.MatchController;
|
import forge.screens.match.MatchController;
|
||||||
import forge.screens.quest.QuestMenu;
|
import forge.screens.quest.QuestMenu;
|
||||||
import forge.screens.settings.GuiDownloader;
|
import forge.screens.settings.GuiDownloader;
|
||||||
import forge.sound.AudioClip;
|
import forge.sound.*;
|
||||||
import forge.sound.AudioMusic;
|
|
||||||
import forge.sound.IAudioClip;
|
|
||||||
import forge.sound.IAudioMusic;
|
|
||||||
import forge.toolbox.FOptionPane;
|
import forge.toolbox.FOptionPane;
|
||||||
import forge.toolbox.GuiChoose;
|
import forge.toolbox.GuiChoose;
|
||||||
import forge.util.*;
|
import forge.util.*;
|
||||||
@@ -272,7 +269,7 @@ public class GuiMobile implements IGuiBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAudioClip createAudioClip(final String filename) {
|
public IAudioClip createAudioClip(final String filename) {
|
||||||
return AudioClip.createClip(ForgeConstants.SOUND_DIR + filename);
|
return AudioClip.createClip(SoundSystem.instance.getSoundDirectory() + filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -288,6 +285,7 @@ public class GuiMobile implements IGuiBase {
|
|||||||
@Override
|
@Override
|
||||||
public void clearImageCache() {
|
public void clearImageCache() {
|
||||||
ImageCache.clear();
|
ImageCache.clear();
|
||||||
|
ImageKeys.clearMissingCards();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ public class ImageCache {
|
|||||||
|
|
||||||
public static void clear() {
|
public static void clear() {
|
||||||
missingIconKeys.clear();
|
missingIconKeys.clear();
|
||||||
|
ImageKeys.clearMissingCards();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void disposeTexture(){
|
public static void disposeTexture(){
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class NewGauntletScreen extends LaunchScreen {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
chooser.show(null, true);
|
chooser.show(null, false); /*setting selectMax to true will select all available option*/
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
|
||||||
|
import forge.Forge;
|
||||||
import forge.Graphics;
|
import forge.Graphics;
|
||||||
import forge.card.CardRenderer.CardStackPosition;
|
import forge.card.CardRenderer.CardStackPosition;
|
||||||
import forge.card.CardZoom;
|
import forge.card.CardZoom;
|
||||||
@@ -324,7 +326,15 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH
|
|||||||
ThreadUtil.invokeInGameThread(new Runnable() { //must invoke in game thread in case a dialog needs to be shown
|
ThreadUtil.invokeInGameThread(new Runnable() { //must invoke in game thread in case a dialog needs to be shown
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!selectCard(false)) {
|
if (GuiBase.getInterface().isRunningOnDesktop() && Forge.mouseButtonID == Input.Buttons.RIGHT) {
|
||||||
|
FThreads.invokeInEdtLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
showZoom();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else if (!selectCard(false)) {
|
||||||
//if no cards in stack can be selected, just show zoom/details for card
|
//if no cards in stack can be selected, just show zoom/details for card
|
||||||
FThreads.invokeInEdtLater(new Runnable() {
|
FThreads.invokeInEdtLater(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import forge.screens.TabPageScreen;
|
|||||||
import forge.screens.TabPageScreen.TabPage;
|
import forge.screens.TabPageScreen.TabPage;
|
||||||
import forge.screens.home.HomeScreen;
|
import forge.screens.home.HomeScreen;
|
||||||
import forge.screens.match.MatchController;
|
import forge.screens.match.MatchController;
|
||||||
|
import forge.sound.MusicPlaylist;
|
||||||
import forge.sound.SoundSystem;
|
import forge.sound.SoundSystem;
|
||||||
import forge.toolbox.FCheckBox;
|
import forge.toolbox.FCheckBox;
|
||||||
import forge.toolbox.FGroupList;
|
import forge.toolbox.FGroupList;
|
||||||
@@ -612,6 +613,29 @@ public class SettingsPage extends TabPage<SettingsScreen> {
|
|||||||
localizer.getMessage("nlVibrateAfterLongPress")),
|
localizer.getMessage("nlVibrateAfterLongPress")),
|
||||||
6);
|
6);
|
||||||
//Sound Options
|
//Sound Options
|
||||||
|
lstSettings.addItem(new CustomSelectSetting(FPref.UI_CURRENT_SOUND_SET,
|
||||||
|
localizer.getMessage("cbpSoundSets"),
|
||||||
|
localizer.getMessage("nlpSoundSets"),
|
||||||
|
SoundSystem.instance.getAvailableSoundSets()) {
|
||||||
|
@Override
|
||||||
|
public void valueChanged(String newValue) {
|
||||||
|
super.valueChanged(newValue);
|
||||||
|
SoundSystem.instance.invalidateSoundCache();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
7);
|
||||||
|
lstSettings.addItem(new CustomSelectSetting(FPref.UI_CURRENT_MUSIC_SET,
|
||||||
|
localizer.getMessage("cbpMusicSets"),
|
||||||
|
localizer.getMessage("nlpMusicSets"),
|
||||||
|
SoundSystem.getAvailableMusicSets()) {
|
||||||
|
@Override
|
||||||
|
public void valueChanged(String newValue) {
|
||||||
|
super.valueChanged(newValue);
|
||||||
|
MusicPlaylist.invalidateMusicPlaylist();
|
||||||
|
SoundSystem.instance.changeBackgroundTrack();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
7);
|
||||||
lstSettings.addItem(new CustomSelectSetting(FPref.UI_VOL_SOUNDS,
|
lstSettings.addItem(new CustomSelectSetting(FPref.UI_VOL_SOUNDS,
|
||||||
localizer.getMessage("cbAdjustSoundsVolume"),
|
localizer.getMessage("cbAdjustSoundsVolume"),
|
||||||
localizer.getMessage("nlAdjustSoundsVolume"),
|
localizer.getMessage("nlAdjustSoundsVolume"),
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#Add one announcement per line
|
#Add one announcement per line
|
||||||
Get in the discord if you aren't yet. https://discord.gg/3v9JCVr
|
Get in the discord if you aren't yet. https://discord.gg/3v9JCVr
|
||||||
The Throne of Eldraine quest world is the largest and most meticulously developed quest world to date, combining fascinating fairytales and interesting interactions. If you've never baked a pie into a pie, have you really played Magic?
|
Forge now supports 100% of core and expansion set cards from Limited Edition Alpha to Innistrad: Midnight Hunt. This includes Equinox, Chaos Orb, and Falling Star.
|
||||||
Innistrad: Midnight Hunt (MID) and Innistrad: Midnight Hunt Commander (MIC) are 100% supported
|
Planar Conquest now features a new plane - Forgotten Realms, based on the AFR and AFC sets.
|
||||||
Various improvements have been made to the desktop and mobile user interface to enhance the experience
|
Several planes are now available in Planar Conquest in their Classic form, as originally intended by the author, without support for the newer sets and with the original events not modified with newer cards. These planes are available in addition to the contemporary versions of the planes and are marked as "Classic".
|
||||||
|
Sound sets are now configurable - you can place your sound sets under "sound" in your Forge cache (as subfolders) and then select them with the "Sound set" option.
|
||||||
|
Music sets are now configurable - you can place your music sets under "music" in your Forge cache (as subfolders) and then select them with the "Music set" option. The music set folder must have the same structure as "res/music", with "match" and "menus" subfolders containing relevant music tracks.
|
||||||
*** Android 7 & 8 support is now deprecated. Support will be dropped in an upcoming release. ***
|
*** Android 7 & 8 support is now deprecated. Support will be dropped in an upcoming release. ***
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name":"Djinni",
|
"name":"Djinn",
|
||||||
"template":
|
"template":
|
||||||
{
|
{
|
||||||
"count":60,
|
"count":60,
|
||||||
"colors":["Blue","Red"],
|
"colors":["Blue","Red"],
|
||||||
"tribe":"Djinni",
|
"tribe":"Djinn",
|
||||||
"tribeCards":0.7,
|
"tribeCards":0.7,
|
||||||
"tribeSynergyCards":0.0,
|
"tribeSynergyCards":0.0,
|
||||||
"rares":0.5
|
"rares":0.5
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"activeFile": "map/swamp_town.tmx",
|
"activeFile": "map/island_town.tmx",
|
||||||
"expandedProjectPaths": [
|
"expandedProjectPaths": [
|
||||||
"map",
|
|
||||||
"tileset",
|
"tileset",
|
||||||
|
"map",
|
||||||
"obj"
|
"obj"
|
||||||
],
|
],
|
||||||
"file.lastUsedOpenFilter": "Alle Dateien (*)",
|
"file.lastUsedOpenFilter": "Alle Dateien (*)",
|
||||||
@@ -33,10 +33,10 @@
|
|||||||
},
|
},
|
||||||
"map/island_town.tmx": {
|
"map/island_town.tmx": {
|
||||||
"scale": 3,
|
"scale": 3,
|
||||||
"selectedLayer": 2,
|
"selectedLayer": 1,
|
||||||
"viewCenter": {
|
"viewCenter": {
|
||||||
"x": 240,
|
"x": 251,
|
||||||
"y": 136
|
"y": 73
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"map/mountain_town.tmx": {
|
"map/mountain_town.tmx": {
|
||||||
@@ -100,9 +100,9 @@
|
|||||||
"tileset/buildings.tsx",
|
"tileset/buildings.tsx",
|
||||||
"tileset/main.tsx",
|
"tileset/main.tsx",
|
||||||
"map/forest_town.tmx",
|
"map/forest_town.tmx",
|
||||||
"map/island_town.tmx",
|
"map/swamp_town.tmx",
|
||||||
"map/mountain_town.tmx",
|
|
||||||
"map/plains_town.tmx",
|
"map/plains_town.tmx",
|
||||||
"map/swamp_town.tmx"
|
"map/mountain_town.tmx",
|
||||||
|
"map/island_town.tmx"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="30" height="17" tilewidth="16" tileheight="16" infinite="0" nextlayerid="6" nextobjectid="48">
|
<map version="1.5" tiledversion="1.7.1" orientation="orthogonal" renderorder="right-down" width="30" height="17" tilewidth="16" tileheight="16" infinite="0" nextlayerid="6" nextobjectid="48">
|
||||||
<editorsettings>
|
<editorsettings>
|
||||||
<export target="wastetown..tmx" format="tmx"/>
|
<export target="wastetown..tmx" format="tmx"/>
|
||||||
</editorsettings>
|
</editorsettings>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
</layer>
|
</layer>
|
||||||
<layer id="2" name="Ground" width="30" height="17">
|
<layer id="2" name="Ground" width="30" height="17">
|
||||||
<data encoding="base64" compression="zlib">
|
<data encoding="base64" compression="zlib">
|
||||||
eJxjYBgFowA/KOWljz2T2BgYJkOxETtCXB8HmxxQRsAvZ9kJs2kBzrEj/J7LgWDncUDkCbmbXEArf2FLM/o4whNX/FIa19jsIpVNCchBisfzOOIXW1xTE9A63SKDEl4ETU97kcGovcQBAKfZHlY=
|
eJxjYBgFowA/KOWljz2T2BgYJkOxETtCXB8HmxxQRsAvZ9kJs2kBzrEj/J7LgWDncUDkCbmbXEArf2FLM/o4whMmjk5TCxCKU3SaWiAHKR7PY4lfGA2LY1oAWqdbZFDCi6DpaS8yGLWXOAAAywwdJA==
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
<layer id="3" name="Foreground" width="30" height="17">
|
<layer id="3" name="Foreground" width="30" height="17">
|
||||||
@@ -20,22 +20,22 @@
|
|||||||
<property name="spriteLayer" type="bool" value="true"/>
|
<property name="spriteLayer" type="bool" value="true"/>
|
||||||
</properties>
|
</properties>
|
||||||
<data encoding="base64" compression="zlib">
|
<data encoding="base64" compression="zlib">
|
||||||
eJxjYKAfKORgYCgC4mIOOloKBPycDAwCQCzISV97KQVzBRgY5gnQ396dQDt3AbHeIAkvdyEGBg8hTDalIJeLPLlRQB7AFXe44peacY0MRuN2FKCDK+wMDFfZ6W/vQNSHIAAACK8NIg==
|
eJxjYKAfKORgYCgC4mIOOloKBPycDAwCQCzISV97KQVzBRgY5gnQ396dQDt3AbHeIAkvdyEGBg8hTDalIJeLPLlRQB7AFXcwcXSaVmA0bkcBOrjCzsBwlZ3+9g5EfQgCABETDSI=
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
<layer id="5" name="AboveSprites" width="30" height="17">
|
<layer id="5" name="AboveSprites" width="30" height="17">
|
||||||
<data encoding="base64" compression="zlib">
|
<data encoding="base64" compression="zlib">
|
||||||
eJxjYBgFgxXMFWBgmCcw0K5AAG0hBgYdIUz2KBhaAFfc4Yrf0bgeBaNgeAEArncEPg==
|
eJxjYBgFgxXMFWBgmCcw0K5AAG0hBgYdIUz2KBhaAFfcwcTR6VEwCkbB8AIAtDsEPg==
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
<objectgroup id="4" name="Objects">
|
<objectgroup id="4" name="Objects">
|
||||||
<object id="38" template="../obj/entry_up.tx" x="256" y="271"/>
|
<object id="38" template="../obj/entry_up.tx" x="256" y="271"/>
|
||||||
<object id="41" template="../obj/shop.tx" x="304" y="98"/>
|
<object id="41" template="../obj/shop.tx" x="304" y="98"/>
|
||||||
<object id="42" template="../obj/shop.tx" x="400" y="162"/>
|
<object id="42" template="../obj/shop.tx" x="368" y="162"/>
|
||||||
<object id="43" template="../obj/shop.tx" x="353" y="98"/>
|
<object id="43" template="../obj/shop.tx" x="353" y="98"/>
|
||||||
<object id="44" template="../obj/shop.tx" x="208" y="162"/>
|
<object id="44" template="../obj/shop.tx" x="208" y="162"/>
|
||||||
<object id="45" template="../obj/shop.tx" x="304" y="162"/>
|
<object id="45" template="../obj/shop.tx" x="304" y="162"/>
|
||||||
<object id="46" template="../obj/shop.tx" x="352" y="162"/>
|
<object id="46" template="../obj/shop.tx" x="336" y="162"/>
|
||||||
<object id="47" template="../obj/inn.tx" x="215" y="82"/>
|
<object id="47" template="../obj/inn.tx" x="215" y="82"/>
|
||||||
</objectgroup>
|
</objectgroup>
|
||||||
</map>
|
</map>
|
||||||
|
|||||||
@@ -23,6 +23,6 @@
|
|||||||
"height": 0.7,
|
"height": 0.7,
|
||||||
"color": "10a2e0",
|
"color": "10a2e0",
|
||||||
"spriteNames":["IslandTree","Coral","Shell"] ,
|
"spriteNames":["IslandTree","Coral","Shell"] ,
|
||||||
"enemies":[ "Merfok","Merfok warrior","Merfok Avatar","Djinn","Blue Wiz1"] ,
|
"enemies":[ "Merfolk","Merfolk warrior","Merfolk Avatar","Djinn","Blue Wiz1"] ,
|
||||||
"pointsOfInterest":[ "Island Town"]
|
"pointsOfInterest":[ "Island Town"]
|
||||||
}
|
}
|
||||||
@@ -872,7 +872,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Djinn",
|
"name": "Djinn",
|
||||||
"sprite": "sprites/djinn.atlas",
|
"sprite": "sprites/djinn.atlas",
|
||||||
"deck": "decks/Djinni.json",
|
"deck": "decks/Djinn.json",
|
||||||
"spawnRate": 0.2,
|
"spawnRate": 0.2,
|
||||||
"difficulty": 0.1,
|
"difficulty": 0.1,
|
||||||
"speed": 30,
|
"speed": 30,
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
"maleAvatar":"Viashino_m"
|
"maleAvatar":"Viashino_m"
|
||||||
} ,
|
} ,
|
||||||
{
|
{
|
||||||
"name":"Drawf",
|
"name":"Dwarf",
|
||||||
"female":"sprites/heroes/dwarf_f.atlas",
|
"female":"sprites/heroes/dwarf_f.atlas",
|
||||||
"male":"sprites/heroes/dwarf_m.atlas",
|
"male":"sprites/heroes/dwarf_m.atlas",
|
||||||
"femaleAvatar":"Dwarf_f",
|
"femaleAvatar":"Dwarf_f",
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ Types:Creature Cat Cleric
|
|||||||
PT:2/3
|
PT:2/3
|
||||||
K:Lifelink
|
K:Lifelink
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPutCounters | TriggerDescription$ When CARDNAME enters the battlefield, put a +1/+1 counter on each of up to two other target creatures you control.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPutCounters | TriggerDescription$ When CARDNAME enters the battlefield, put a +1/+1 counter on each of up to two other target creatures you control.
|
||||||
SVar:TrigPutCounters:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 | TargetMin$ 0 | TargetMax$ 2 | ValidTgts$ Creature.YouCtrl+Other | TgtPrompt$ Select target creature you control
|
SVar:TrigPutCounters:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 | TargetMin$ 0 | TargetMax$ 2 | ValidTgts$ Creature.YouCtrl+Other | TgtPrompt$ Select up to two other target creatures you control
|
||||||
DeckHas:Ability$LifeGain & Ability$Counters
|
DeckHas:Ability$LifeGain & Ability$Counters
|
||||||
Oracle:Lifelink (Damage dealt by this creature also causes you to gain that much life.)\nWhen Basri's Acolyte enters the battlefield, put a +1/+1 counter on each of up to two other target creatures you control.
|
Oracle:Lifelink (Damage dealt by this creature also causes you to gain that much life.)\nWhen Basri's Acolyte enters the battlefield, put a +1/+1 counter on each of up to two other target creatures you control.
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
Name:Demonic Tutor
|
Name:Demonic Tutor
|
||||||
ManaCost:1 B
|
ManaCost:1 B
|
||||||
Types:Sorcery
|
Types:Sorcery
|
||||||
A:SP$ ChangeZone | Cost$ 1 B | Origin$ Library | Destination$ Hand | ChangeType$ Card | ChangeNum$ 1 | Mandatory$ True | SpellDescription$ Search your library for a card, put that card into your hand, then shuffle.
|
A:SP$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Card | ChangeNum$ 1 | Mandatory$ True | StackDescription$ SpellDescription | SpellDescription$ Search your library for a card, put that card into your hand, then shuffle.
|
||||||
#TODO: Improve the tutoring logic for the AI. Currently will generally look for the most expensive castable thing in the library (which can, of course, be used to advantage in properly constructed AI decks).
|
#TODO: Improve the tutoring logic for the AI. Currently will generally look for the most expensive castable thing in the library (which can, of course, be used to advantage in properly constructed AI decks).
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:Picture:http://resources.wizards.com/magic/cards/3e/en-us/card1155.jpg
|
|
||||||
Oracle:Search your library for a card, put that card into your hand, then shuffle.
|
Oracle:Search your library for a card, put that card into your hand, then shuffle.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:G
|
|||||||
Types:Creature Human Druid
|
Types:Creature Human Druid
|
||||||
PT:1/1
|
PT:1/1
|
||||||
A:AB$ ChangeZone | Cost$ 1 G Sac<1/CARDNAME> | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ 1 | SpellDescription$ Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.
|
A:AB$ ChangeZone | Cost$ 1 G Sac<1/CARDNAME> | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ 1 | SpellDescription$ Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.
|
||||||
S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Graveyard | AddHiddenKeyword$ CARDNAME count as Muscle Burst. | Description$ If CARDNAME is in a graveyard, effects from spells named Muscle Burst count it as a card named Muscle Burst.
|
S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Graveyard | AffectedZone$ Graveyard | AddHiddenKeyword$ CARDNAME count as Muscle Burst. | Description$ If CARDNAME is in a graveyard, effects from spells named Muscle Burst count it as a card named Muscle Burst.
|
||||||
DeckHints:Name$Diligent Farmhand|Muscle Burst
|
DeckHints:Name$Diligent Farmhand|Muscle Burst
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/diligent_farmhand.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/diligent_farmhand.jpg
|
||||||
Oracle:{1}{G}, Sacrifice Diligent Farmhand: Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle.\nIf Diligent Farmhand is in a graveyard, effects from spells named Muscle Burst count it as a card named Muscle Burst.
|
Oracle:{1}{G}, Sacrifice Diligent Farmhand: Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle.\nIf Diligent Farmhand is in a graveyard, effects from spells named Muscle Burst count it as a card named Muscle Burst.
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ Name:Followed Footsteps
|
|||||||
ManaCost:3 U U
|
ManaCost:3 U U
|
||||||
Types:Enchantment Aura
|
Types:Enchantment Aura
|
||||||
K:Enchant creature
|
K:Enchant creature
|
||||||
A:SP$ Attach | Cost$ 3 U U | ValidTgts$ Creature | AILogic$ Curse
|
A:SP$ Attach | ValidTgts$ Creature | AILogic$ HighestEvaluation
|
||||||
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, create a token that's a copy of enchanted creature.
|
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, create a token that's a copy of enchanted creature.
|
||||||
SVar:TrigCopy:DB$ CopyPermanent | Defined$ Enchanted | SpellDescription$ At the beginning of your upkeep, put a token that's a copy of enchanted creature onto the battlefield.
|
SVar:TrigCopy:DB$ CopyPermanent | Defined$ Enchanted | SpellDescription$ At the beginning of your upkeep, create a token that's a copy of enchanted creature.
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/followed_footsteps.jpg
|
|
||||||
Oracle:Enchant creature\nAt the beginning of your upkeep, create a token that's a copy of enchanted creature.
|
Oracle:Enchant creature\nAt the beginning of your upkeep, create a token that's a copy of enchanted creature.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ PT:2/1
|
|||||||
S:Mode$ Continuous | Affected$ Dwarf.Other+YouCtrl | AddPower$ 1 | Description$ Other Dwarves you control get +1/+0.
|
S:Mode$ Continuous | Affected$ Dwarf.Other+YouCtrl | AddPower$ 1 | Description$ Other Dwarves you control get +1/+0.
|
||||||
T:Mode$ Taps | ValidCard$ Dwarf.YouCtrl | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever a Dwarf you control becomes tapped, create a Treasure token.
|
T:Mode$ Taps | ValidCard$ Dwarf.YouCtrl | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever a Dwarf you control becomes tapped, create a Treasure token.
|
||||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_treasure_sac | TokenOwner$ You
|
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_treasure_sac | TokenOwner$ You
|
||||||
A:AB$ ChangeZone | Cost$ Sac<5/Treasure> | CostDesc$ Sacrifice five Treasures: | Origin$ Library | Destination$ Battlefield | ChangeType$ Card.Artifact,Card.Dragon | ChangeNum$ 1 | Mandatory$ True | StackDescription$ {p:You} searches their library for an Artifact or Dragon card, puts that card onto the battlefield, then shuffles their library. | SpellDescription$ Search your library for an artifact or Dragon card, put that card onto the battlefield, then shuffle.
|
A:AB$ ChangeZone | Cost$ Sac<5/Treasure> | Origin$ Library | Destination$ Battlefield | ChangeType$ Card.Artifact,Card.Dragon | ChangeNum$ 1 | Mandatory$ True | StackDescription$ {p:You} searches their library for an Artifact or Dragon card, puts that card onto the battlefield, then shuffles their library. | SpellDescription$ Search your library for an artifact or Dragon card, put that card onto the battlefield, then shuffle.
|
||||||
SVar:BuffedBy:Dwarf
|
SVar:BuffedBy:Dwarf
|
||||||
SVar:PlayMain1:TRUE
|
SVar:PlayMain1:TRUE
|
||||||
DeckNeeds:Type$Dwarf
|
DeckNeeds:Type$Dwarf
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ Name:Nahiri, the Harbinger
|
|||||||
ManaCost:2 R W
|
ManaCost:2 R W
|
||||||
Types:Legendary Planeswalker Nahiri
|
Types:Legendary Planeswalker Nahiri
|
||||||
Loyalty:4
|
Loyalty:4
|
||||||
A:AB$ Discard | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | NumCards$ 1 | Optional$ True | Mode$ TgtChoose | RememberDiscarded$ True | SubAbility$ DBDraw | SpellDescription$ You may discard a card. If you do, draw a card.
|
A:AB$ Draw | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | Defined$ You | NumCards$ 1 | UnlessCost$ Discard<1/Card> | UnlessSwitched$ True | UnlessPayer$ You | SpellDescription$ You may discard a card. If you do, draw a card.
|
||||||
SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 1 | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SubAbility$ DBCleanup
|
|
||||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
|
||||||
A:AB$ ChangeZone | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | ValidTgts$ Enchantment,Artifact.tapped,Creature.tapped | TgtPrompt$ Select target enchantment, tapped artifact, or tapped creature | Origin$ Battlefield | Destination$ Exile | SpellDescription$ Exile target enchantment, tapped artifact, or tapped creature.
|
A:AB$ ChangeZone | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | ValidTgts$ Enchantment,Artifact.tapped,Creature.tapped | TgtPrompt$ Select target enchantment, tapped artifact, or tapped creature | Origin$ Battlefield | Destination$ Exile | SpellDescription$ Exile target enchantment, tapped artifact, or tapped creature.
|
||||||
A:AB$ ChangeZone | Cost$ SubCounter<8/LOYALTY> | Planeswalker$ True | Ultimate$ True | Origin$ Library | Destination$ Battlefield | ChangeType$ Artifact,Creature | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ DBPump | SpellDescription$ Search your library for an artifact or creature card, put it onto the battlefield, then shuffle. It gains haste. Return it to your hand at the beginning of the next end step.
|
A:AB$ ChangeZone | Cost$ SubCounter<8/LOYALTY> | Planeswalker$ True | Ultimate$ True | Origin$ Library | Destination$ Battlefield | ChangeType$ Artifact,Creature | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ DBPump | SpellDescription$ Search your library for an artifact or creature card, put it onto the battlefield, then shuffle. It gains haste. Return it to your hand at the beginning of the next end step.
|
||||||
SVar:DBPump:DB$ Animate | Keywords$ Haste | Duration$ Permanent | AtEOT$ Hand | Defined$ Remembered | SubAbility$ DBCleanup
|
SVar:DBPump:DB$ Animate | Keywords$ Haste | Duration$ Permanent | AtEOT$ Hand | Defined$ Remembered | SubAbility$ DBCleanup
|
||||||
|
|||||||
@@ -3,11 +3,9 @@ ManaCost:1 B R
|
|||||||
Types:Legendary Creature Vampire Knight
|
Types:Legendary Creature Vampire Knight
|
||||||
PT:3/3
|
PT:3/3
|
||||||
K:Flying
|
K:Flying
|
||||||
T:Mode$ ChangesZone | ValidCard$ Creature.Other+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigDiscard | TriggerZones$ Battlefield | OptionalDecider$ You | TriggerDescription$ Whenever another creature enters the battlefield under your control, you may discard a card. If you do, put a +1/+1 counter on that creature, it gains haste until end of turn, and it becomes a vampire in addition to its other types.
|
T:Mode$ ChangesZone | ValidCard$ Creature.Other+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigDiscard | TriggerZones$ Battlefield | TriggerDescription$ Whenever another creature enters the battlefield under your control, you may discard a card. If you do, put a +1/+1 counter on that creature, it gains haste until end of turn, and it becomes a vampire in addition to its other types.
|
||||||
SVar:TrigDiscard:DB$ Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose | RememberDiscarded$ True | SubAbility$ DBPutCounter
|
SVar:TrigDiscard:AB$ PutCounter | Cost$ Discard<1/Card> | Defined$ TriggeredCardLKICopy | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBPump
|
||||||
SVar:DBPutCounter:DB$ PutCounter | Defined$ TriggeredCardLKICopy | CounterType$ P1P1 | CounterNum$ 1 | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SubAbility$ DBPump
|
SVar:DBPump:DB$ Pump | Defined$ TriggeredCard | KW$ Haste | SubAbility$ DBAnimate
|
||||||
SVar:DBPump:DB$ Pump | Defined$ TriggeredCard | KW$ Haste | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SubAbility$ DBAnimate
|
SVar:DBAnimate:DB$ Animate | Defined$ TriggeredCard | Types$ Vampire | Duration$ Permanent
|
||||||
SVar:DBAnimate:DB$ Animate | Defined$ TriggeredCard | Types$ Vampire | Duration$ Permanent | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SubAbility$ DBCleanup
|
|
||||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/olivia_mobilized_for_war.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/olivia_mobilized_for_war.jpg
|
||||||
Oracle:Flying\nWhenever another creature enters the battlefield under your control, you may discard a card. If you do, put a +1/+1 counter on that creature, it gains haste until end of turn, and it becomes a Vampire in addition to its other types.
|
Oracle:Flying\nWhenever another creature enters the battlefield under your control, you may discard a card. If you do, put a +1/+1 counter on that creature, it gains haste until end of turn, and it becomes a Vampire in addition to its other types.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:3 R
|
|||||||
Types:Creature Elemental Cat
|
Types:Creature Elemental Cat
|
||||||
PT:2/3
|
PT:2/3
|
||||||
K:Haste
|
K:Haste
|
||||||
S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Graveyard | AddHiddenKeyword$ CARDNAME count as Flame Burst. | Description$ If CARDNAME is in a graveyard, effects from spells named Flame Burst count it as a card named Flame Burst.
|
S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Graveyard | AffectedZone$ Graveyard | AddHiddenKeyword$ CARDNAME count as Flame Burst. | Description$ If CARDNAME is in a graveyard, effects from spells named Flame Burst count it as a card named Flame Burst.
|
||||||
DeckHints:Name$Flame Burst|Pardic Firecat
|
DeckHints:Name$Flame Burst|Pardic Firecat
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/pardic_firecat.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/pardic_firecat.jpg
|
||||||
Oracle:Haste\nIf Pardic Firecat is in a graveyard, effects from spells named Flame Burst count it as a card named Flame Burst.
|
Oracle:Haste\nIf Pardic Firecat is in a graveyard, effects from spells named Flame Burst count it as a card named Flame Burst.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ PT:3/4
|
|||||||
K:Flash
|
K:Flash
|
||||||
K:Flying
|
K:Flying
|
||||||
T:Mode$ ChangesZone | ValidCard$ Creature.Self | Origin$ Any | Destination$ Battlefield | Execute$ RestorationExile | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may exile target non-Angel creature you control, then return that creature to the battlefield under your control.
|
T:Mode$ ChangesZone | ValidCard$ Creature.Self | Origin$ Any | Destination$ Battlefield | Execute$ RestorationExile | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may exile target non-Angel creature you control, then return that creature to the battlefield under your control.
|
||||||
SVar:RestorationExile:DB$ ChangeZone | ValidTgts$ Creature.nonAngel+YouCtrl | TgtPrompt$ Select target non-Angel creature you control | Origin$ Battlefield | Destination$ Exile | RememberTargets$ True | ForgetOtherTargets$ True | AILogic$ BounceOnce | SubAbility$ RestorationReturn
|
SVar:RestorationExile:DB$ ChangeZone | ValidTgts$ Creature.nonAngel+YouCtrl | TgtPrompt$ Select target non-Angel creature you control | Origin$ Battlefield | Destination$ Exile | RememberTargets$ True | ForgetOtherTargets$ True | SubAbility$ RestorationReturn
|
||||||
SVar:RestorationReturn:DB$ ChangeZone | Defined$ Remembered | Origin$ Exile | Destination$ Battlefield | GainControl$ True
|
SVar:RestorationReturn:DB$ ChangeZone | Defined$ Remembered | Origin$ Exile | Destination$ Battlefield | GainControl$ True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/restoration_angel.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/restoration_angel.jpg
|
||||||
Oracle:Flash\nFlying\nWhen Restoration Angel enters the battlefield, you may exile target non-Angel creature you control, then return that card to the battlefield under your control.
|
Oracle:Flash\nFlying\nWhen Restoration Angel enters the battlefield, you may exile target non-Angel creature you control, then return that card to the battlefield under your control.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Colors:green
|
|||||||
Types:Creature Werewolf
|
Types:Creature Werewolf
|
||||||
PT:2/1
|
PT:2/1
|
||||||
K:Unblockable
|
K:Unblockable
|
||||||
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDrawN | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, draw a card, then discard a card.
|
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDrawN | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, draw a card.
|
||||||
SVar:TrigDrawN:DB$ Draw | NumCards$ 1 | Defined$ You
|
SVar:TrigDrawN:DB$ Draw | NumCards$ 1 | Defined$ You
|
||||||
K:Nightbound
|
K:Nightbound
|
||||||
Oracle:Seafaring Werewolf can't be blocked.\nWhenever Seafaring Werewolf deals combat damage to a player, draw a card.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)
|
Oracle:Seafaring Werewolf can't be blocked.\nWhenever Seafaring Werewolf deals combat damage to a player, draw a card.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
Name:Alluring Suitor
|
||||||
|
ManaCost:2 R
|
||||||
|
Types:Creature Vampire
|
||||||
|
PT:2/3
|
||||||
|
T:Mode$ AttackersDeclared | Execute$ TrigTransform | IsPresent$ Creature.attacking | PresentCompare$ EQ2 | NoResolvingCheck$ True | TriggerZones$ Battlefield | AttackingPlayer$ You | TriggerDescription$ When you attack with exactly two creatures, transform CARDNAME.
|
||||||
|
SVar:TrigTransform:DB$ SetState | Defined$ Self | Mode$ Transform
|
||||||
|
AlternateMode:DoubleFaced
|
||||||
|
Oracle:When you attack with exactly two creatures, transform Alluring Suitor.
|
||||||
|
|
||||||
|
ALTERNATE
|
||||||
|
|
||||||
|
Name:Deadly Dancer
|
||||||
|
ManaCost:no cost
|
||||||
|
Colors:red
|
||||||
|
Types:Creature Vampire
|
||||||
|
PT:3/3
|
||||||
|
K:Trample
|
||||||
|
T:Mode$ Transformed | ValidCard$ Card.Self | Execute$ TrigMana | TriggerDescription$ When this creature transforms into CARDNAME, add {R}{R}. Until end of turn, you don't lose this mana as steps and phases end.
|
||||||
|
SVar:TrigMana:DB$ Mana | Produced$ R | Amount$ 2 | PersistentMana$ True
|
||||||
|
A:AB$ Pump | Cost$ R R | Defined$ Self | NumAtt$ +1 | SubAbility$ DBPump | StackDescription$ CARDNAME and | SpellDescription$ CARDNAME and another target creature each get +1/+0 until end of turn.
|
||||||
|
SVar:DBPump:DB$ Pump | ValidTgts$ Creature.Other | TgtPrompt$ Select another target creature | NumAtt$ +1 | StackDescription$ {c:Targeted} each get +1/+0 until end of turn.
|
||||||
|
Oracle:Trample\nWhen this creature transforms into Deadly Dancer, add {R}{R}. Until end of turn, you don't lose this mana as steps and phases end.\n{R}{R}: Deadly Dancer and another target creature each get +1/+0 until end of turn.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
Name:Ancient Lumberknot
|
||||||
|
ManaCost:2 B G
|
||||||
|
Types:Creature Treefolk
|
||||||
|
PT:1/4
|
||||||
|
S:Mode$ Continuous | Affected$ Creature.powerLTtoughness+YouCtrl | AddHiddenKeyword$ CARDNAME assigns combat damage equal to its toughness rather than its power | Description$ Each creature you control with toughness greater than its power assigns combat damage equal to its toughness rather than its power.
|
||||||
|
Oracle:Each creature you control with toughness greater than its power assigns combat damage equal to its toughness rather than its power.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Angelic Quartermaster
|
||||||
|
ManaCost:3 W W
|
||||||
|
Types:Creature Angel Soldier
|
||||||
|
PT:3/3
|
||||||
|
K:Flying
|
||||||
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPutCounters | TriggerDescription$ When CARDNAME enters the battlefield, put a +1/+1 counter on each of up to two other target creatures.
|
||||||
|
SVar:TrigPutCounters:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 | TargetMin$ 0 | TargetMax$ 2 | ValidTgts$ Creature.Other | TgtPrompt$ Select up to two other target creatures
|
||||||
|
DeckHas:Ability$Counters
|
||||||
|
Oracle:Flying\nWhen Angelic Quartermaster enters the battlefield, put a +1/+1 counter on each of up to two other target creatures.
|
||||||
8
forge-gui/res/cardsfolder/upcoming/arm_the_cathars.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/arm_the_cathars.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Name:Arm the Cathars
|
||||||
|
ManaCost:1 W W
|
||||||
|
Types:Sorcery
|
||||||
|
A:SP$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature (+3/+3) | NumAtt$ 3 | NumDef$ 3 | KW$ Vigilance | SubAbility$ DBPump | StackDescription$ Until end of turn, {c:ThisTargetedCard} gets +3/+3, | SpellDescription$ Until end of turn, target creature gets +3/+3,
|
||||||
|
SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select up to one other target creature (+2/+2) | TargetMin$ 0 | TargetMax$ 1 | NumAtt$ 2 | NumDef$ 2 | KW$ Vigilance | TargetUnique$ True | SubAbility$ DBPump2 | StackDescription$ SpellDescription | SpellDescription$ up to one other target creature gets +2/+2,
|
||||||
|
SVar:DBPump2:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select up to one other target creature (+1/+1) | TargetMin$ 0 | TargetMax$ 1 | NumAtt$ 1 | NumDef$ 1 | KW$ Vigilance | TargetUnique$ True | SubAbility$ DBPump3 | StackDescription$ SpellDescription | SpellDescription$ and up to one other target creature gets +1/1.
|
||||||
|
SVar:DBPump3:DB$ Pump | Defined$ Targeted | KW$ Vigilance | StackDescription$ SpellDescription | SpellDescription$ Those creatures gain vigilance until end of turn.
|
||||||
|
Oracle:Until end of turn, target creature gets +3/+3, up to one other target creature gets +2/+2, and up to one other target creature gets +1/+1. Those creatures gain vigilance until end of turn.
|
||||||
10
forge-gui/res/cardsfolder/upcoming/ascendant_packleader.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/ascendant_packleader.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Name:Ascendant Packleader
|
||||||
|
ManaCost:G
|
||||||
|
Types:Creature Wolf
|
||||||
|
PT:2/1
|
||||||
|
K:etbCounter:P1P1:1:IsPresent$ Permanent.YouCtrl+cmcGE4:CARDNAME enters the battlefield with a +1/+1 counter on it if you control a permanent with mana value 4 or greater.
|
||||||
|
T:Mode$ SpellCast | ValidCard$ Card.cmcGE4 | ValidActivatingPlayer$ You | Execute$ TrigCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a spell with mana value 4 or greater, put a +1/+1 counter on CARDNAME.
|
||||||
|
SVar:TrigCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||||
|
DeckHas:Ability$Counters
|
||||||
|
SVar:BuffedBy:Permanent.cmcGE4
|
||||||
|
Oracle:Ascendant Packleader enters the battlefield with a +1/+1 counter on it if you control a permanent with mana value 4 or greater.\nWhenever you cast a spell with mana value 4 or greater, put a +1/+1 counter on Ascendant Packleader.
|
||||||
9
forge-gui/res/cardsfolder/upcoming/belligerent_guest.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/belligerent_guest.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Belligerent Guest
|
||||||
|
ManaCost:2 R
|
||||||
|
Types:Creature Vampire
|
||||||
|
PT:3/2
|
||||||
|
K:Trample
|
||||||
|
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, create a Blood token. (It's an artifact with "{1}, {T}, Discard a card, Sacrifice this artifact: Draw a card.")
|
||||||
|
SVar:TrigToken:DB$ Token | TokenScript$ c_a_blood_draw
|
||||||
|
DeckHas:Ability$Token & Ability$Sacrifice & Type$Blood
|
||||||
|
Oracle:Trample\nWhenever Belligerent Guest deals combat damage to a player, create a Blood token. (It's an artifact with "{1}, {T}, Discard a card, Sacrifice this artifact: Draw a card.")
|
||||||
9
forge-gui/res/cardsfolder/upcoming/blood_hypnotist.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/blood_hypnotist.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Blood Hypnotist
|
||||||
|
ManaCost:2 R
|
||||||
|
Types:Creature Vampire
|
||||||
|
PT:3/3
|
||||||
|
K:CARDNAME can't block.
|
||||||
|
T:Mode$ Sacrificed | ValidCard$ Blood.token+YouCtrl | TriggerZone$ Battlefield | Execute$ TrigPump | ActivationLimit$ 1 | TriggerDescription$ Whenever you sacrifice one or more Blood tokens, target creature can't block this turn. This ability triggers only once each turn.
|
||||||
|
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME can't block. | IsCurse$ True
|
||||||
|
DeckNeeds:Type$Blood
|
||||||
|
Oracle:Blood Hypnotist can't block.\nWhenever you sacrifice one or more Blood tokens, target creature can't block this turn. This ability triggers only once each turn.
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
Name:Bloodsworn Squire
|
||||||
|
ManaCost:3 B
|
||||||
|
Types:Creature Vampire Soldier
|
||||||
|
PT:3/3
|
||||||
|
A:AB$ Pump | Cost$ 1 B Discard<1/Card> | Defined$ Self | KW$ Indestructible | SubAbility$ DBTap | SpellDescription$ CARDNAME gains indestructible until end of turn.
|
||||||
|
SVar:DBTap:DB$ Tap | Defined$ Self | SubAbility$ DBTransform | StackDescription$ SpellDescription | SpellDescription$ Tap it.
|
||||||
|
SVar:DBTransform:DB$ SetState | Defined$ Self | Mode$ Transform | ConditionPresent$ Creature.YouOwn | ConditionCompare$ GE4 | ConditionZone$ Graveyard | StackDescription$ SpellDescription | SpellDescription$ Then if there are four or more creature cards in your graveyard, transform CARDNAME.
|
||||||
|
AlternateMode:DoubleFaced
|
||||||
|
SVar:AIPreference:DiscardCost$Creature
|
||||||
|
DeckHints:Ability$Graveyard
|
||||||
|
DeckHas:Ability$Discard
|
||||||
|
Oracle:{1}{B}, Discard a card: Bloodsworn Squire gains indestructible until end of turn. Tap it. Then if there are four or more creature cards in your graveyard, transform Bloodsworn Squire. (Damage and effects that say "destroy" don't destroy it.)
|
||||||
|
|
||||||
|
ALTERNATE
|
||||||
|
|
||||||
|
Name:Bloodsworn Knight
|
||||||
|
ManaCost:no cost
|
||||||
|
Colors:black
|
||||||
|
Types:Creature Vampire Knight
|
||||||
|
PT:*/*
|
||||||
|
S:Mode$ Continuous | Affected$ Card.Self | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ CARDNAME's power and toughness are each equal to the number of creature cards in your graveyard.
|
||||||
|
SVar:X:Count$TypeInYourYard.Creature
|
||||||
|
A:AB$ Pump | Cost$ 1 B Discard<1/Card> | Defined$ Self | KW$ Indestructible | SubAbility$ DBTap | SpellDescription$ CARDNAME gains indestructible until end of turn.
|
||||||
|
SVar:DBTap:DB$ Tap | Defined$ Self | StackDescription$ SpellDescription | SpellDescription$ Tap it.
|
||||||
|
SVar:AIPreference:DiscardCost$Creature
|
||||||
|
DeckHints:Ability$Graveyard
|
||||||
|
DeckHas:Ability$Discard
|
||||||
|
Oracle:Bloodsworn Knight's power and toughness are each equal to the number of creature cards in your graveyard.\n{1}{B}, Discard a card: Bloodsworn Knight gains indestructible until end of turn. Tap it. (Damage and effects that say "destroy" don't destroy it.)
|
||||||
10
forge-gui/res/cardsfolder/upcoming/bloodtithe_harvester.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/bloodtithe_harvester.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Name:Bloodtithe Harvester
|
||||||
|
ManaCost:B R
|
||||||
|
Types:Creature Vampire
|
||||||
|
PT:3/2
|
||||||
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create a Blood token. (It's an artifact with "{1}, {T}, Discard a card, Sacrifice this artifact: Draw a card.")
|
||||||
|
SVar:TrigToken:DB$ Token | TokenScript$ c_a_blood_draw
|
||||||
|
A:AB$ Pump | Cost$ T Sac<1/CARDNAME> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -X | NumDef$ -X | SorcerySpeed$ True | AILogic$ Curse | SpellDescription$ Target creature gets -X/-X until end of turn, where X is twice the number of Blood tokens you control. Activate only as a sorcery.
|
||||||
|
SVar:X:Count$Valid Blood.token+YouCtrl/Twice
|
||||||
|
DeckHas:Ability$Token & Ability$Sacrifice & Type$Blood
|
||||||
|
Oracle:When Bloodtithe Harvester enters the battlefield, create a Blood token. (It's an artifact with "{1}, {T}, Discard a card, Sacrifice this artifact: Draw a card.")\n{T}, Sacrifice Bloodtithe Harvester: Target creature gets -X/-X until end of turn, where X is twice the number of Blood tokens you control. Activate only as a sorcery.
|
||||||
13
forge-gui/res/cardsfolder/upcoming/bloodvial_purveyor.txt
Normal file
13
forge-gui/res/cardsfolder/upcoming/bloodvial_purveyor.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Name:Bloodvial Purveyor
|
||||||
|
ManaCost:2 B B
|
||||||
|
Types:Creature Vampire
|
||||||
|
PT:5/6
|
||||||
|
K:Flying
|
||||||
|
K:Trample
|
||||||
|
T:Mode$ SpellCast | ValidActivatingPlayer$ Opponent | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever an opponent casts a spell, that player creates a Blood token. (It's an artifact with "{1}, {T}, Discard a card, Sacrifice this artifact: Draw a card.")
|
||||||
|
SVar:TrigToken:DB$ Token | TokenScript$ c_a_blood_draw | TokenOwner$ TriggeredActivator
|
||||||
|
T:Mode$ Attacks | ValidCard$ Card.Self | IsPresent$ Blood.token+DefendingPlayerCtrl | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, it gets +1/+0 until end of turn for each Blood token defending player controls.
|
||||||
|
SVar:TrigPump:DB$ Pump | Defined$ Self | NumAtt$ X
|
||||||
|
SVar:X:Count$Valid Blood.token+DefendingPlayerCtrl
|
||||||
|
SVar:HasAttackEffect:TRUE
|
||||||
|
Oracle:Flying, trample\nWhenever an opponent casts a spell, that player creates a Blood token. (It's an artifact with "{1}, {T}, Discard a card, Sacrifice this artifact: Draw a card.")\nWhenever Bloodvial Purveyor attacks, it gets +1/+0 until end of turn for each Blood token defending player controls.
|
||||||
8
forge-gui/res/cardsfolder/upcoming/boarded_window.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/boarded_window.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Name:Boarded Window
|
||||||
|
ManaCost:3
|
||||||
|
Types:Artifact
|
||||||
|
S:Mode$ Continuous | Affected$ Creature.attackingYou | AddPower$ -1 | Description$ Creatures attacking you get -1/-0.
|
||||||
|
T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield | CheckSVar$ X | SVarCompare$ GE4 | Execute$ TrigExile | TriggerDescription$ At the beginning of each end step, if you were dealt 4 or more damage this turn, exile CARDNAME.
|
||||||
|
SVar:TrigExile:DB$ ChangeZone | Defined$ Self | Origin$ Battlefield | Destination$ Exile
|
||||||
|
SVar:X:Count$LifeYouLostThisTurn
|
||||||
|
Oracle:Creatures attacking you get -1/-0.\nAt the beginning of each end step, if you were dealt 4 or more damage this turn, exile Boarded Window.
|
||||||
11
forge-gui/res/cardsfolder/upcoming/bramble_wurm.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/bramble_wurm.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Name:Bramble Wurm
|
||||||
|
ManaCost:6 G
|
||||||
|
Types:Creature Wurm
|
||||||
|
PT:7/6
|
||||||
|
K:Reach
|
||||||
|
K:Trample
|
||||||
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigGainLife | TriggerDescription$ When CARDNAME enters the battlefield, you gain 5 life.
|
||||||
|
SVar:TrigGainLife:DB$ GainLife | LifeAmount$ 5
|
||||||
|
A:AB$ GainLife | Cost$ 2 G ExileFromGrave<1/CARDNAME> | ActivationZone$ Graveyard | LifeAmount$ 5 | SpellDescription$ You gain 5 life.
|
||||||
|
DeckHas:Ability$LifeGain
|
||||||
|
Oracle:Reach, trample\nWhen Bramble Wurm enters the battlefield, you gain 5 life.\n{2}{G}, Exile Bramble Wurm from your graveyard: You gain 5 life.
|
||||||
11
forge-gui/res/cardsfolder/upcoming/breathkeeper_seraph.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/breathkeeper_seraph.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Name:Breathkeeper Seraph
|
||||||
|
ManaCost:4 W W
|
||||||
|
Types:Creature Angel
|
||||||
|
PT:4/4
|
||||||
|
K:Flying
|
||||||
|
K:Soulbond
|
||||||
|
S:Mode$ Continuous | Affected$ Creature.PairedWith,Creature.Self+Paired | AddTrigger$ DeathTrigger | AddSVar$ DelayedReturn,TrigReturn | Description$ As long as CARDNAME is paired with another creature, each of those creatures have "When this creature dies, you may return it to the battlefield under its owner's control at the beginning of your next upkeep."
|
||||||
|
SVar:DeathTrigger:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ DelayedReturn | TriggerDescription$ When this creature dies, you may return it to the battlefield under its owner's control at the beginning of your next upkeep.
|
||||||
|
SVar:DelayedReturn:DB$ DelayedTrigger | Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | OptionalDecider$ You | Execute$ TrigReturn | RememberObjects$ TriggeredNewCardLKICopy | TriggerDescription$ You may return it to the battlefield under its owner's control at the beginning of your next upkeep.
|
||||||
|
SVar:TrigReturn:DB$ ChangeZone | Defined$ DelayTriggerRememberedLKI | Origin$ Graveyard | Destination$ Battlefield
|
||||||
|
Oracle:Flying, soulbond (You may pair this creature with another unpaired creature when either enters the battlefield. They remain paired for as long as you control both of them.)\nAs long as Breathkeeper Seraph is paired with another creature, each of those creatures has "When this creature dies, you may return it to the battlefield under its owner's control at the beginning of your next upkeep."
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
Name:Brine Comber
|
||||||
|
ManaCost:1 W U
|
||||||
|
Types:Creature Spirit
|
||||||
|
PT:1/1
|
||||||
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield or becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying.
|
||||||
|
T:Mode$ BecomesTarget | ValidTarget$ Card.Self | ValidSource$ Aura | SourceType$ Spell | TriggerZones$ Battlefield | Execute$ TrigToken | Secondary$ True | TriggerDescription$ When CARDNAME enters the battlefield or becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying.
|
||||||
|
SVar:TrigToken:DB$ Token | TokenScript$ w_1_1_spirit_flying
|
||||||
|
K:Disturb:W U
|
||||||
|
AlternateMode:DoubleFaced
|
||||||
|
SVar:EnchantMe:Multiple
|
||||||
|
DeckHas:Ability$Graveyard & Ability$Token
|
||||||
|
DeckHints:Type$Enchantment
|
||||||
|
Oracle:Whenever Brine Comber enters the battlefield or becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying.\nDisturb {W}{U} (You may cast this card from your graveyard transformed for its disturb cost.)
|
||||||
|
|
||||||
|
ALTERNATE
|
||||||
|
|
||||||
|
Name:Brinebound Gift
|
||||||
|
ManaCost:no cost
|
||||||
|
Colors:white,blue
|
||||||
|
Types:Enchantment Aura
|
||||||
|
K:Enchant creature
|
||||||
|
A:SP$ Attach | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Pump
|
||||||
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield or enchanted creature becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying.
|
||||||
|
T:Mode$ BecomesTarget | ValidTarget$ Creature.EnchantedBy | ValidSource$ Aura | SourceType$ Spell | TriggerZones$ Battlefield | Execute$ TrigToken | Secondary$ True | TriggerDescription$ When CARDNAME enters the battlefield or enchanted creature becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying.
|
||||||
|
SVar:TrigToken:DB$ Token | TokenScript$ w_1_1_spirit_flying
|
||||||
|
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Graveyard | ReplaceWith$ Exile | Description$ If CARDNAME would be put into a graveyard from anywhere, exile it instead.
|
||||||
|
SVar:Exile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard
|
||||||
|
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddSVar$ EnchantTarget | Secondary$ True
|
||||||
|
SVar:EnchantTarget:SVar:EnchantMe:Multiple
|
||||||
|
DeckHas:Ability$Token
|
||||||
|
DeckHints:Type$Enchantment
|
||||||
|
Oracle:Enchant creature\nWhenever Brinebound Gift enters the battlefield or enchanted creature becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying.\nIf Brinebound Gift would be put into a graveyard from anywhere, exile it instead.
|
||||||
15
forge-gui/res/cardsfolder/upcoming/cemetery_protector.txt
Normal file
15
forge-gui/res/cardsfolder/upcoming/cemetery_protector.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
Name:Cemetery Protector
|
||||||
|
ManaCost:2 W W
|
||||||
|
Types:Creature Human Soldier
|
||||||
|
PT:3/4
|
||||||
|
K:Flash
|
||||||
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile a card from a graveyard.
|
||||||
|
SVar:TrigExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | ChangeType$ Card | ChangeNum$ 1 | SelectPrompt$ Select a card from a graveyard | Mandatory$ True | Hidden$ True | Imprint$ True
|
||||||
|
T:Mode$ LandPlayed | ValidCard$ Land.YouOwn+sharesCardTypeWith Imprinted.ExiledWithSource | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever you play a land or cast a spell, if it shares a card type with the exiled card, create a 1/1 white Human creature token.
|
||||||
|
T:Mode$ SpellCast | ValidCard$ Card.sharesCardTypeWith Imprinted.ExiledWithSource | ValidActivatingPlayer$ You | Execute$ TrigToken | TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ Whenever you play a land or cast a spell, if it shares a card type with the exiled card, create a 1/1 white Human creature token.
|
||||||
|
SVar:TrigToken:DB$ Token | TokenScript$ w_1_1_human
|
||||||
|
T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Card.Self | Destination$ Any | Execute$ DBCleanup | Static$ True
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True
|
||||||
|
DeckHas:Ability$Token
|
||||||
|
DeckHints:Ability$Graveyard & Ability$Discard
|
||||||
|
Oracle:Flash\nWhen Cemetery Protector enters the battlefield, exile a card from a graveyard.\nWhenever you play a land or cast a spell, if it shares a card type with the exiled card, create a 1/1 white Human creature token.
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
Name:Chandra, Dressed to Kill
|
||||||
|
ManaCost:1 R R
|
||||||
|
Types:Legendary Planeswalker Chandra
|
||||||
|
Loyalty:3
|
||||||
|
A:AB$ Mana | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | Produced$ R | SubAbility$ DBDealDamage | SpellDescription$ Add {R}. CARDNAME deals 1 damage to up to one target player or planeswalker.
|
||||||
|
SVar:DBDealDamage:DB$ DealDamage | ValidTgts$ Player,Planeswalker | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select up to one target player or planeswalker | NumDmg$ 1
|
||||||
|
A:AB$ Dig | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | Defined$ You | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | StackDescription$ SpellDescription | SpellDescription$ Exile the top card of your library. If it's red, you may cast it this turn.
|
||||||
|
SVar:DBEffect:DB$ Effect | ConditionDefined$ Remembered | ConditionPresent$ Card.Red | ConditionCompare$ GE1 | RememberObjects$ RememberedCard | StaticAbilities$ STPlay | SubAbility$ DBCleanup | ForgetOnMoved$ Exile
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
|
SVar:STPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonLand | AffectedZone$ Exile | Description$ You may cast the exiled card this turn.
|
||||||
|
A:AB$ Dig | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | Defined$ You | DigNum$ 5 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect2 | StackDescription$ SpellDescription | SpellDescription$ Exile the top five cards of your library. You may cast red spells from among them this turn. You get an emblem with "Whenever you cast a red spell, this emblem deals X damage to any target, where X is the amount of mana spent to cast that spell."
|
||||||
|
SVar:DBEffect2:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ STPlay2 | SubAbility$ DBEffect3 | ForgetOnMoved$ Exile
|
||||||
|
SVar:DBEffect3:DB$ Effect | Name$ Emblem - Chandra, Dressed to Kill | Triggers$ TRSpellCast | Duration$ Permanent | SubAbility$ DBCleanup
|
||||||
|
SVar:STPlay2:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+Red+nonLand | AffectedZone$ Exile | Description$ You may cast red spells from among the exiled cards this turn.
|
||||||
|
SVar:TRSpellCast:Mode$ SpellCast | ValidCard$ Card.Red | ValidActivatingPlayer$ You | TriggerZones$ Command | Execute$ TrigDealDamage | TriggerDescription$ Whenever you cast a red spell, this emblem deals X damage to any target, where X is the amount of mana spent to cast that spell."
|
||||||
|
SVar:TrigDealDamage:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ X
|
||||||
|
SVar:X:Count$TriggeredManaSpent
|
||||||
|
SVar:BuffedBy:Card.Red
|
||||||
|
Oracle:[+1]: Add {R}. Chandra, Dressed to Kill deals 1 damage to up to one target player or planeswalker.\n[+1]: Exile the top card of your library. If it's red, you may cast it this turn.\n[-7]: Exile the top five cards of your library. You may cast red spells from among them this turn. You get an emblem with "Whenever you cast a red spell, this emblem deals X damage to any target, where X is the amount of mana spent to cast that spell."
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
Name:Child of the Pack
|
||||||
|
ManaCost:2 R G
|
||||||
|
Types:Creature Human Werewolf
|
||||||
|
PT:2/5
|
||||||
|
A:AB$ Token | Cost$ 2 R G | TokenScript$ g_2_2_wolf | StackDescription$ SpellDescription | SpellDescription$ Create a 2/2 green Wolf creature token.
|
||||||
|
K:Daybound
|
||||||
|
AlternateMode:DoubleFaced
|
||||||
|
DeckHas:Ability$Token & Type$Wolf
|
||||||
|
Oracle:{2}{R}{G}: Create a 2/2 green Wolf creature token.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
|
||||||
|
|
||||||
|
ALTERNATE
|
||||||
|
|
||||||
|
Name:Savage Packmate
|
||||||
|
ManaCost:no cost
|
||||||
|
Colors:red,green
|
||||||
|
Types:Creature Werewolf
|
||||||
|
PT:5/5
|
||||||
|
K:Trample
|
||||||
|
S:Mode$ Continuous | Affected$ Creature.Other+YouCtrl | AddPower$ 1 | Description$ Other creatures you control get +1/+0.
|
||||||
|
K:Nightbound
|
||||||
|
Oracle:Trample\nOther creatures you control get +1/+0.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)
|
||||||
9
forge-gui/res/cardsfolder/upcoming/cloaked_cadet.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/cloaked_cadet.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Cloaked Cadet
|
||||||
|
ManaCost:4 G
|
||||||
|
Types:Creature Human Ranger
|
||||||
|
PT:2/4
|
||||||
|
K:Training
|
||||||
|
T:Mode$ CounterAddedAll | CounterType$ P1P1 | Valid$ Human.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDraw | ActivationLimit$ 1 | TriggerDescription$ Whenever one or more +1/+1 counters are put on one or more Humans you control, draw a card. This ability triggers only once each turn.
|
||||||
|
SVar:TrigDraw:DB$ Draw | NumCards$ 1
|
||||||
|
DeckHas:Ability$Counters
|
||||||
|
Oracle:Training (Whenever this creature attacks with another creature with greater power, put a +1/+1 counter on this creature.)\nWhenever one or more +1/+1 counters are put on one or more Humans you control, draw a card. This ability triggers only once each turn.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
Name:Concealing Curtains
|
||||||
|
ManaCost:B
|
||||||
|
Types:Creature Wall
|
||||||
|
PT:0/4
|
||||||
|
K:Defender
|
||||||
|
A:AB$ SetState | Cost$ 2 B | Defined$ Self | Mode$ Transform | SorcerySpeed$ True | SpellDescription$ Transform CARDNAME. Activate only as a sorcery.
|
||||||
|
AlternateMode:DoubleFaced
|
||||||
|
Oracle:Defender\n{2}{B}: Transform Concealing Curtains. Activate only as a sorcery.
|
||||||
|
|
||||||
|
ALTERNATE
|
||||||
|
|
||||||
|
Name:Revealing Eye
|
||||||
|
ManaCost:no cost
|
||||||
|
Colors:black
|
||||||
|
Types:Creature Eye Horror
|
||||||
|
PT:3/4
|
||||||
|
K:Menace
|
||||||
|
T:Mode$ Transformed | ValidCard$ Card.Self | Execute$ TrigReveal | TriggerDescription$ When this creature transforms into CARDNAME, target opponent reveals their hand. You may choose a nonland card from it. If you do, that player discards that card, then draws a card.
|
||||||
|
SVar:TrigReveal:DB$ RevealHand | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | RememberRevealed$ True | SubAbility$ DBChoose
|
||||||
|
SVar:DBChoose:DB$ ChooseCard | ChoiceZone$ Hand | Amount$ 1 | Choices$ Card.nonLand+IsRemembered | SubAbility$ DBDiscard | ChoiceTitle$ You may choose a nonland card
|
||||||
|
SVar:DBDiscard:DB$ Discard | DefinedCards$ ChosenCard | Defined$ Targeted | Mode$ Defined | ConditionDefined$ ChosenCard | ConditionPresent$ Card | ConditionCompare$ EQ1 | SubAbility$ DBDraw
|
||||||
|
SVar:DBDraw:DB$ Draw | Defined$ Targeted | NumCards$ 1 | ConditionDefined$ ChosenCard | ConditionPresent$ Card | ConditionCompare$ EQ1 | SubAbility$ DBCleanup
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True
|
||||||
|
DeckHas:Ability$Discard
|
||||||
|
Oracle:Menace\nWhen this creature transforms into Revealing Eye, target opponent reveals their hand. You may choose a nonland card from it. If you do, that player discards that card, then draws a card.
|
||||||
11
forge-gui/res/cardsfolder/upcoming/consuming_tide.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/consuming_tide.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Name:Consuming Tide
|
||||||
|
ManaCost:2 U U
|
||||||
|
Types:Sorcery
|
||||||
|
A:SP$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBChooseCard | SubAbility$ DBReturnAll | SpellDescription$ Each player chooses a nonland permanent they control. Return all nonland permanents not chosen this way to their owners' hands. Then you draw a card for each opponent who has more cards in their hand than you.
|
||||||
|
SVar:DBChooseCard:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Permanent.nonLand+RememberedPlayerCtrl | ChoiceTitle$ Choose a nonland permanent you control | RememberChosen$ True | AILogic$ BestCard
|
||||||
|
SVar:DBReturnAll:DB$ ChangeZoneAll | ChangeType$ Permanent.nonLand+IsNotRemembered | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBDraw
|
||||||
|
SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ X | StackDescription$ None | SubAbility$ DBCleanup
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
|
SVar:X:PlayerCountOpponents$HasPropertyHasCardsInHand_Card_GTY
|
||||||
|
SVar:Y:Count$CardsInYourHand
|
||||||
|
Oracle:Each player chooses a nonland permanent they control. Return all nonland permanents not chosen this way to their owners' hands. Then you draw a card for each opponent who has more cards in their hand than you.
|
||||||
15
forge-gui/res/cardsfolder/upcoming/cultivator_colossus.txt
Normal file
15
forge-gui/res/cardsfolder/upcoming/cultivator_colossus.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
Name:Cultivator Colossus
|
||||||
|
ManaCost:4 G G G
|
||||||
|
Types:Creature Plant Beast
|
||||||
|
PT:*/*
|
||||||
|
K:Trample
|
||||||
|
S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ CARDNAME's power and toughness are each equal to the number of lands you control.
|
||||||
|
SVar:X:Count$Valid Land.YouCtrl
|
||||||
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Self | Execute$ TrigRepeat | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may put a land card from your hand onto the battlefield tapped. If you do, draw a card and repeat this process.
|
||||||
|
SVar:TrigRepeat:DB$ Repeat | RepeatSubAbility$ DBClear | RepeatDefined$ Remembered | RepeatPresent$ Card | RepeatSVarCompare$ EQ1 | SubAbility$ DBCleanup
|
||||||
|
SVar:DBClear:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBChangeZone
|
||||||
|
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.YouOwn | RememberChanged$ True | ForgetOtherRemembered$ True | SubAbility$ DBDraw
|
||||||
|
SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 1 | ConditionDefined$ Remembered | ConditionPresent$ Card
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
|
SVar:BuffedBy:Land
|
||||||
|
Oracle:Trample\nCultivator Colossus's power and toughness are each equal to the number of lands you control.\nWhen Cultivator Colossus enters the battlefield, you may put a land card from your hand onto the battlefield tapped. If you do, draw a card and repeat this process.
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user