diff --git a/forge-gui-mobile/src/forge/Graphics.java b/forge-gui-mobile/src/forge/Graphics.java index ee4b008766b..0183fc15070 100644 --- a/forge-gui-mobile/src/forge/Graphics.java +++ b/forge-gui-mobile/src/forge/Graphics.java @@ -4,9 +4,7 @@ import java.util.ArrayDeque; import java.util.Deque; import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.*; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.glutils.ShaderProgram; @@ -44,6 +42,8 @@ public class Graphics { private final ShaderProgram shaderWarp = new ShaderProgram(Gdx.files.internal("shaders").child("grayscale.vert"), Gdx.files.internal("shaders").child("warp.frag")); private final ShaderProgram shaderUnderwater = new ShaderProgram(Gdx.files.internal("shaders").child("grayscale.vert"), Gdx.files.internal("shaders").child("underwater.frag")); + private Texture dummyTexture = null; + public Graphics() { ShaderProgram.pedantic = false; } @@ -87,6 +87,7 @@ public class Graphics { shaderGrayscale.dispose(); shaderUnderwater.dispose(); shaderWarp.dispose(); + if(dummyTexture != null) dummyTexture.dispose(); } public SpriteBatch getBatch() { @@ -1124,4 +1125,14 @@ public class Graphics { int brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000; return brightness > 155 ? Color.valueOf("#171717") : Color.valueOf("#fffffd"); } + + public Texture getDummyTexture(){ + if (dummyTexture == null){ + Pixmap P = new Pixmap(1, 1, Pixmap.Format.RGBA8888); + P.setColor(1f,1f,1f,1f); + P.drawPixel(0, 0); + dummyTexture = new Texture(P); + } + return dummyTexture; + } } diff --git a/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java b/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java index 76a5b19c0e1..cfb58fc90f1 100644 --- a/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java @@ -1,9 +1,15 @@ package forge.adventure.character; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.utils.Array; +import forge.Forge; +import forge.adventure.data.EffectData; import forge.adventure.data.EnemyData; import forge.adventure.data.RewardData; import forge.adventure.util.Current; @@ -16,7 +22,10 @@ import forge.adventure.util.Reward; */ public class EnemySprite extends CharacterSprite { EnemyData data; - public MapDialog dialog; + public MapDialog dialog; //Dialog to show on contact. Overrides standard battle (can be started as an action) + public MapDialog defeatDialog; //Dialog to show on defeat. Overrides standard death (can be removed as an action) + public EffectData effect; //Battle effect for this enemy. Similar to a player's blessing. + public String nameOverride = ""; //Override name of this enemy in battles. public EnemySprite(EnemyData enemyData) { this(0,enemyData); @@ -43,7 +52,6 @@ public class EnemySprite extends CharacterSprite { return data; } - public Array getRewards() { Array ret=new Array(); if(data.rewards == null) @@ -54,5 +62,62 @@ public class EnemySprite extends CharacterSprite { return ret; } + private void drawColorHints(Batch batch){ + int size = Math.min(data.colors.length(), 6); + float DX = getX() - 2f; + float DY = getY(); + + for(int i = 0; i < size; i++){ + char C = data.colors.toUpperCase().charAt(i); + switch (C) { + default: break; + case 'C': { + batch.setColor(Color.DARK_GRAY); + batch.draw(Forge.getGraphics().getDummyTexture(), DX, DY, 2, 2); + DY += 2; break; + } + case 'B': { + batch.setColor(Color.PURPLE); + batch.draw(Forge.getGraphics().getDummyTexture(), DX, DY, 2, 2); + DY += 2; break; + } + case 'G': { + batch.setColor(Color.GREEN); + batch.draw(Forge.getGraphics().getDummyTexture(), DX, DY, 2, 2); + DY += 2; break; + } + case 'R': { + batch.setColor(Color.RED); + batch.draw(Forge.getGraphics().getDummyTexture(), DX, DY, 2, 2); + DY += 2; break; + } + case 'U': { + batch.setColor(Color.BLUE); + batch.draw(Forge.getGraphics().getDummyTexture(), DX, DY, 2, 2); + DY += 2; break; + } + case 'W': { + batch.setColor(Color.WHITE); + batch.draw(Forge.getGraphics().getDummyTexture(), DX, DY, 2, 2); + DY += 2; break; + } + } + } + batch.setColor(Color.WHITE); + } + + @Override + public void draw(Batch batch, float parentAlpha) { + super.draw(batch, parentAlpha); + if(Current.player().hasColorView() && !data.colors.isEmpty()) { + drawColorHints(batch); + } + if(dialog != null && dialog.canShow()){ //Draw a talk icon on top. + Texture T = Current.world().getGlobalTexture(); + TextureRegion TR = new TextureRegion(T, 0, 0, 16, 16); + batch.draw(TR, getX(), getY() + 16, 16, 16); + } + } + } diff --git a/forge-gui-mobile/src/forge/adventure/character/PlayerSprite.java b/forge-gui-mobile/src/forge/adventure/character/PlayerSprite.java index 7431fbaf1f4..eac20f7d387 100644 --- a/forge-gui-mobile/src/forge/adventure/character/PlayerSprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/PlayerSprite.java @@ -25,8 +25,9 @@ public class PlayerSprite extends CharacterSprite { PlayerSprite.this.updatePlayer(); } }); - playerSpeed=Config.instance().getConfigData().playerBaseSpeed; - Current.player().onEquipmentChanged(() -> playerSpeedEquipmentModifier=Current.player().equipmentSpeed()); + playerSpeed = Config.instance().getConfigData().playerBaseSpeed; + Current.player().onBlessing( () -> playerSpeedEquipmentModifier = Current.player().equipmentSpeed() ); + Current.player().onEquipmentChanged( () -> playerSpeedEquipmentModifier=Current.player().equipmentSpeed() ); } private void updatePlayer() { diff --git a/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java b/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java index 6eefb159969..f1f0584b085 100644 --- a/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java @@ -2,9 +2,8 @@ package forge.adventure.character; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.Json; -import com.badlogic.gdx.utils.SerializationException; import forge.adventure.data.RewardData; +import forge.adventure.util.JSONStringLoader; import forge.adventure.util.Reward; /** @@ -26,18 +25,11 @@ public class RewardSprite extends CharacterSprite { public RewardSprite(String data, String _sprite){ super(_sprite); - Json json = new Json(); if (data != null) { - try { rewards = json.fromJson(RewardData[].class, data); } - catch(SerializationException E){ - //JSON parsing could fail. Since this an user written part, assume failure is possible (it happens). - System.err.printf("[%s] while loading JSON file for reward actor. JSON:\n%s\nUsing a default reward.", E.getMessage(), data); - rewards = json.fromJson(RewardData[].class, default_reward); - } - + rewards = JSONStringLoader.parse(RewardData[].class, data, default_reward); } else { //Shouldn't happen, but make sure it doesn't fly by. System.err.printf("Reward data is null. Using a default reward."); - rewards = json.fromJson(RewardData[].class, default_reward); + rewards = JSONStringLoader.parse(RewardData[].class, default_reward, default_reward); } } diff --git a/forge-gui-mobile/src/forge/adventure/data/DialogData.java b/forge-gui-mobile/src/forge/adventure/data/DialogData.java index d85426ac6bf..b20c55ab2f5 100644 --- a/forge-gui-mobile/src/forge/adventure/data/DialogData.java +++ b/forge-gui-mobile/src/forge/adventure/data/DialogData.java @@ -5,7 +5,7 @@ package forge.adventure.data; * Carries all text, branches and effects of dialogs. */ public class DialogData { - public EffectData[] effect; //List of effects to cause when the dialog shows. + public ActionData[] effect; //List of effects to cause when the dialog shows. public ConditionData[] condition; //List of conditions for the action to show. public String name; //Text to display when action is listed as a button. public String locname; //References a localized string for the button labels. @@ -13,17 +13,41 @@ public class DialogData { public String loctext; //References a localized string for the text body. public DialogData[] options; // - static public class EffectData { + + + static public class ActionData { + static public class QuestFlag{ + public String key; + public int val; + } public String removeItem; //Remove item name from inventory. public String addItem; //Add item name to inventory. + public int addLife = 0; //Gives the player X health. Negative to take. + public int addGold = 0; //Gives the player X gold. Negative to take. public int deleteMapObject = 0; //Remove ID from the map. -1 for self. public int battleWithActorID = 0; //Start a battle with enemy ID. -1 for self if possible. + public EffectData giveBlessing; //Give a blessing to the player. + public String setColorIdentity; //Change player's color identity. + public String advanceQuestFlag; //Increase given quest flag by 1. + public EffectData setEffect; //Set or replace current effects on current actor. + public QuestFlag setQuestFlag; //Set quest flag {flag ID, value} } static public class ConditionData { + static public class QueryQuestFlag{ + public String key; + public String op; + public int val; + } public String item; - public int flag = 0; //Check for a local dungeon flag. - public int actorID = 0; //Check for an actor ID. - public boolean not = false; //Reverse the result of a condition ("actorID":"XX" + "not":true => true if XX is not in the map.) + public int flag = 0; //Check for a local dungeon flag. + public int actorID = 0; //Check for an actor ID. + public String hasBlessing = null; //Check for specific blessing, if named. + public int hasGold = 0; //Check for player gold. True if gold is equal or higher than X. + public int hasLife = 0; //Check for player life. True if life is equal or higher than X. + public String colorIdentity = null; //Check for player's current color identity. + public String checkQuestFlag = null; //Check if a quest flag is not 0. False if equals 0 (not started, not set). + public QueryQuestFlag getQuestFlag = null; //Check for value of a flag { , , } + public boolean not = false; //Reverse the result of a condition ("actorID":"XX" + "not":true => true if XX is not in the map.) } } diff --git a/forge-gui-mobile/src/forge/adventure/data/EffectData.java b/forge-gui-mobile/src/forge/adventure/data/EffectData.java index 0dd8ba17424..da8b0d99c78 100644 --- a/forge-gui-mobile/src/forge/adventure/data/EffectData.java +++ b/forge-gui-mobile/src/forge/adventure/data/EffectData.java @@ -6,12 +6,16 @@ import forge.item.PaperCard; import forge.item.PaperToken; import forge.model.FModel; -public class EffectData { +import java.io.Serializable; + +public class EffectData implements Serializable { + public String name = null; //Effect name. Can be checked for. //Duel effects. public int lifeModifier = 0; //Amount to add to starting Life. public int changeStartCards = 0; //Amount to add to starting hand size. public String[] startBattleWithCard; //Cards that start in the Battlefield. //Map only effects. + public boolean colorView = false; //Allows to display enemy colors on the map (TODO) public float moveSpeed = 1.0f; //Change of movement speed. Map only. //Opponent field. public EffectData opponent; //Effects to be applied to the opponent's side. @@ -45,6 +49,10 @@ public class EffectData { public String getDescription() { String description = ""; + if(this.name != null && !this.name.isEmpty()) + description += this.name + "\n"; + if(this.colorView) + description += "Manasight.\n"; if(this.lifeModifier != 0) description += "Life: " + ((this.lifeModifier > 0) ? "+" : "") + this.lifeModifier + "\n"; if(this.startBattleWithCard != null && this.startBattleWithCard.length != 0) @@ -54,9 +62,9 @@ public class EffectData { if(this.changeStartCards != 0) description+="Starting hand: " + this.changeStartCards + "\n"; if(this.opponent != null) { - String oppEffect=this.opponent.getDescription(); - if(oppEffect != "") { - description += "Gives Opponent:\n"; + String oppEffect = this.opponent.getDescription(); + description += "Gives Opponent:\n"; + if(!oppEffect.isEmpty()) { description += oppEffect; } } diff --git a/forge-gui-mobile/src/forge/adventure/data/EnemyData.java b/forge-gui-mobile/src/forge/adventure/data/EnemyData.java index 846d288aaa0..22154334a00 100644 --- a/forge-gui-mobile/src/forge/adventure/data/EnemyData.java +++ b/forge-gui-mobile/src/forge/adventure/data/EnemyData.java @@ -19,29 +19,25 @@ public class EnemyData { public int life; public RewardData[] rewards; public String[] equipment; + public String colors = ""; - public EnemyData() - { - - } + public EnemyData() { } public EnemyData(EnemyData enemyData) { - name =enemyData.name; - sprite =enemyData.sprite; - deck =enemyData.deck; - ai =enemyData.ai; - spawnRate =enemyData.spawnRate; - difficulty =enemyData.difficulty ; - speed =enemyData.speed; - life =enemyData.life; - equipment =enemyData.equipment; - if(enemyData.rewards==null) - { + name = enemyData.name; + sprite = enemyData.sprite; + deck = enemyData.deck; + ai = enemyData.ai; + spawnRate = enemyData.spawnRate; + difficulty = enemyData.difficulty; + speed = enemyData.speed; + life = enemyData.life; + equipment = enemyData.equipment; + colors = enemyData.colors; + if(enemyData.rewards == null) { rewards=null; - } - else - { - rewards =new RewardData[enemyData.rewards.length]; - for(int i=0;i(getAllEnemies())) - { + for(EnemyData data: new Array.ArrayIterator<>(getAllEnemies())) { if(data.name.equals(enemy)) return data; } @@ -89,5 +86,4 @@ public class WorldData implements Serializable { return biomes; } - } \ No newline at end of file diff --git a/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java b/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java index 8a7207a6991..ef951f00fc1 100644 --- a/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java +++ b/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java @@ -3,10 +3,9 @@ package forge.adventure.player; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Null; import com.google.common.collect.Lists; -import forge.adventure.data.DifficultyData; -import forge.adventure.data.HeroListData; -import forge.adventure.data.ItemData; +import forge.adventure.data.*; import forge.adventure.util.*; import forge.adventure.world.WorldSave; import forge.deck.CardPool; @@ -17,39 +16,38 @@ import forge.item.PaperCard; import forge.util.ItemPool; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; /** * Class that represents the player (not the player sprite) */ public class AdventurePlayer implements Serializable, SaveFileContent { + private enum ColorID { COLORLESS, WHITE, BLACK, BLUE, RED, GREEN } public static final int NUMBER_OF_DECKS=10; - private Deck deck; - private int avatarIndex; - private int heroRace; - private boolean isFemale; + + private Deck deck; + private int avatarIndex; + private int heroRace; + private boolean isFemale; private float worldPosX; private float worldPosY; private String name; + private ColorID colorIdentity = ColorID.COLORLESS; private int gold=0; private int maxLife=20; private int life=20; private int selectedDeckIndex=0; - private PlayerStatistic statistic=new PlayerStatistic(); - private Deck[] decks=new Deck[NUMBER_OF_DECKS]; + private Map questFlags = new HashMap<>(); + private EffectData blessing; //Blessing to apply for next battle. + private PlayerStatistic statistic = new PlayerStatistic(); + private Deck[] decks=new Deck[NUMBER_OF_DECKS]; private final DifficultyData difficultyData=new DifficultyData(); private final Array inventoryItems=new Array<>(); private final HashMap equippedItems=new HashMap<>(); - public AdventurePlayer() - { - - for(int i=0;i newCards=new ItemPool<>(InventoryItem.class); - public void create(String n, Deck startingDeck, boolean male, int race, int avatar,DifficultyData difficultyData) { + public void create(String n, int startingColorIdentity, Deck startingDeck, boolean male, int race, int avatar,DifficultyData difficultyData) { inventoryItems.clear(); equippedItems.clear(); deck = startingDeck; @@ -83,12 +81,14 @@ public class AdventurePlayer implements Serializable, SaveFileContent { heroRace = race; isFemale = !male; name = n; + setColorIdentity(startingColorIdentity + 1); //+1 because index 0 is colorless. statistic.clear(); newCards.clear(); onGoldChangeList.emit(); onLifeTotalChangeList.emit(); - + blessing = null; inventoryItems.addAll(difficultyData.startItems); + questFlags.clear(); } public void setSelectedDeckSlot(int slot) { @@ -135,12 +135,41 @@ public class AdventurePlayer implements Serializable, SaveFileContent { this.worldPosY = worldPosY; } + public void setColorIdentity(String C){ + switch (C.toUpperCase()){ + case "B": this.colorIdentity = ColorID.BLACK; break; + case "G": this.colorIdentity = ColorID.GREEN; break; + case "R": this.colorIdentity = ColorID.RED; break; + case "U": this.colorIdentity = ColorID.BLUE; break; + case "W": this.colorIdentity = ColorID.WHITE; break; + case "C": default: this.colorIdentity = ColorID.COLORLESS; break; + } + } + public void setColorIdentity(int C){ + switch (C){ + case 2: this.colorIdentity = ColorID.BLACK; break; + case 5: this.colorIdentity = ColorID.GREEN; break; + case 4: this.colorIdentity = ColorID.RED; break; + case 3: this.colorIdentity = ColorID.BLUE; break; + case 1: this.colorIdentity = ColorID.WHITE; break; + case 0: default: this.colorIdentity = ColorID.COLORLESS; break; + } + } + + public String getColorIdentity(){ + switch (colorIdentity){ + case BLUE : return "U"; + case GREEN : return "G"; + case RED : return "R"; + case BLACK : return "B"; + case WHITE : return "W"; + case COLORLESS: default: return "C"; //You are either Ugin or an Eldrazi. Nice. + } + } @Override public void load(SaveFileData data) { - - this.statistic.load(data.readSubData("statistic")); this.difficultyData.startingLife=data.readInt("startingLife"); this.difficultyData.staringMoney=data.readInt("staringMoney"); @@ -151,7 +180,6 @@ public class AdventurePlayer implements Serializable, SaveFileContent { if(this.difficultyData.sellFactor==0) this.difficultyData.sellFactor=0.2f; - name = data.readString("name"); worldPosX = data.readFloat("worldPosX"); worldPosY = data.readFloat("worldPosY"); @@ -159,25 +187,26 @@ public class AdventurePlayer implements Serializable, SaveFileContent { avatarIndex = data.readInt("avatarIndex"); heroRace = data.readInt("heroRace"); isFemale = data.readBool("isFemale"); + colorIdentity = ColorID.COLORLESS; + if(data.containsKey("colorIdentity")) + setColorIdentity(data.readString("colorIdentity")); gold = data.readInt("gold"); life = data.readInt("life"); maxLife = data.readInt("maxLife"); - + blessing = null; + if(data.containsKey("blessing")) blessing = (EffectData)data.readObject("blessing"); inventoryItems.clear(); equippedItems.clear(); - if(data.containsKey("inventory")) - { + if(data.containsKey("inventory")) { String[] inv=(String[])data.readObject("inventory"); inventoryItems.addAll(inv); } - if(data.containsKey("equippedSlots")&&data.containsKey("equippedItems")) - { + if(data.containsKey("equippedSlots") && data.containsKey("equippedItems")) { String[] slots=(String[])data.readObject("equippedSlots"); String[] items=(String[])data.readObject("equippedItems"); assert(slots.length==items.length); - for(int i=0;i slots=new ArrayList<>(); ArrayList items=new ArrayList<>(); @@ -248,6 +286,15 @@ public class AdventurePlayer implements Serializable, SaveFileContent { data.storeObject("equippedSlots",slots.toArray(new String[0])); data.storeObject("equippedItems",items.toArray(new String[0])); + //Save quest flags. + ArrayList questFlagsKey = new ArrayList<>(); + ArrayList questFlagsValue = new ArrayList<>(); + for(Map.Entry entry : questFlags.entrySet()){ + questFlagsKey.add(entry.getKey()); + questFlagsValue.add(entry.getValue()); + } + data.storeObject("questFlagsKey", questFlagsKey.toArray(new String[0])); + data.storeObject("questFlagsValue", questFlagsValue.toArray(new Byte[0])); data.storeObject("deckCards",deck.getMain().toCardList("\n").split("\n")); if(deck.get(DeckSection.Sideboard)!=null) @@ -266,8 +313,6 @@ public class AdventurePlayer implements Serializable, SaveFileContent { return data; } - - public String spriteName() { return HeroListData.getHero(heroRace, isFemale); } @@ -281,15 +326,12 @@ public class AdventurePlayer implements Serializable, SaveFileContent { } public void addCard(PaperCard card) { - cards.add(card); newCards.add(card); - } - public void addReward(Reward reward) { - switch (reward.getType()) - { + public void addReward(Reward reward) { + switch (reward.getType()) { case Card: cards.add(reward.getCard()); newCards.add(reward.getCard()); @@ -304,13 +346,13 @@ public class AdventurePlayer implements Serializable, SaveFileContent { addMaxLife(reward.getCount()); break; } - } SignalList onLifeTotalChangeList=new SignalList(); SignalList onGoldChangeList=new SignalList(); SignalList onPlayerChangeList=new SignalList(); SignalList onEquipmentChange=new SignalList(); + SignalList onBlessing=new SignalList(); private void addGold(int goldCount) { gold+=goldCount; @@ -340,6 +382,11 @@ public class AdventurePlayer implements Serializable, SaveFileContent { o.run(); } + public void onBlessing(Runnable o) { + onBlessing.add(o); + o.run(); + } + public int getLife() { return life; } @@ -348,8 +395,13 @@ public class AdventurePlayer implements Serializable, SaveFileContent { return maxLife; } - public void heal() { - life=maxLife; + public void heal(int amount) { + life = Math.min(life + amount, maxLife); + onLifeTotalChangeList.emit(); + } + + public void fullHeal() { + life = maxLife; onLifeTotalChangeList.emit(); } public void defeated() { @@ -371,6 +423,37 @@ public class AdventurePlayer implements Serializable, SaveFileContent { onGoldChangeList.emit(); } + public void addBlessing(EffectData bless){ + blessing = bless; + onBlessing.emit(); + } + + public void clearBlessing() { + blessing = null; + onBlessing.emit(); + } + + public @Null EffectData getBlessing(){ return blessing; } + + public boolean hasBlessing(String name){ //Checks for a named blessing. + //It is not necessary to name all blessings, only the ones you'd want to check for. + if(blessing == null) return false; + if(blessing.name.equals(name)) return true; + return false; + } + + public boolean hasColorView() { + for(String name:equippedItems.values()) { + ItemData data=ItemData.getItem(name); + if(data != null && data.effect.colorView) return true; + } + if(blessing != null) { + if(blessing.colorView) return true; + } + return false; + } + + public DifficultyData getDifficulty() { return difficultyData; } @@ -429,9 +512,12 @@ public class AdventurePlayer implements Serializable, SaveFileContent { float factor=1.0f; for(String name:equippedItems.values()) { ItemData data=ItemData.getItem(name); - if(data.effect.moveSpeed > 0.0) { //Avoid negative speeds. It would be silly. + if(data != null && data.effect.moveSpeed > 0.0) //Avoid negative speeds. It would be silly. factor*=data.effect.moveSpeed; - } + } + if(blessing != null) { //If a blessing gives speed, take it into account. + if(blessing.moveSpeed > 0.0) + factor *= blessing.moveSpeed; } return factor; } @@ -447,4 +533,24 @@ public class AdventurePlayer implements Serializable, SaveFileContent { inventoryItems.add(name); return true; } + + public void setQuestFlag(String key, int value){ + questFlags.put(key, (byte) value); + } + public void advanceQuestFlag(String key){ + if(questFlags.get(key) != null){ + questFlags.put(key, (byte) (questFlags.get(key) + 1)); + } else { + questFlags.put(key, (byte) 1); + } + } + public boolean checkQuestFlag(String key){ + return questFlags.get(key) != null; + } + public int getQuestFlag(String key){ + return (int) questFlags.getOrDefault(key, (byte) 0); + } + public void resetQuestFlags(){ + questFlags.clear(); + } } diff --git a/forge-gui-mobile/src/forge/adventure/scene/DuelScene.java b/forge-gui-mobile/src/forge/adventure/scene/DuelScene.java index b288d94b93e..eaeb4a3c2e7 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/DuelScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/DuelScene.java @@ -54,7 +54,8 @@ public class DuelScene extends ForgeScene { public void GameEnd() { boolean winner=humanPlayer == hostedMatch.getGame().getMatch().getWinner(); - String enemyName=enemy.getData().name; + String enemyName=(enemy.nameOverride.isEmpty() ? enemy.getData().name : enemy.nameOverride); + Current.player().clearBlessing(); Gdx.app.postRunnable(new Runnable() { @Override public void run() { @@ -97,6 +98,7 @@ public class DuelScene extends ForgeScene { public void enter() { Set appliedVariants = new HashSet<>(); appliedVariants.add(GameType.Constructed); + AdventurePlayer advPlayer = Current.player(); List players = new ArrayList<>(); Deck playerDeck=(Deck)AdventurePlayer.current().getSelectedDeck().copyTo("PlayerDeckCopy"); @@ -105,27 +107,25 @@ public class DuelScene extends ForgeScene { playerDeck.getMain().add("Wastes",missingCards); humanPlayer = RegisteredPlayer.forVariants(2, appliedVariants,playerDeck, null, false, null, null); LobbyPlayer playerObject = GamePlayerUtil.getGuiPlayer(); - FSkin.getAvatars().put(90001, Current.player().avatar()); + FSkin.getAvatars().put(90001, advPlayer.avatar()); playerObject.setAvatarIndex(90001); humanPlayer.setPlayer(playerObject); - humanPlayer.setStartingLife(Current.player().getLife()); + humanPlayer.setStartingLife(advPlayer.getLife()); Current.setLatestDeck(enemy.getData().generateDeck()); RegisteredPlayer aiPlayer = RegisteredPlayer.forVariants(2, appliedVariants, Current.latestDeck(), null, false, null, null); LobbyPlayer enemyPlayer = GamePlayerUtil.createAiPlayer(this.enemy.getData().name, selectAI(this.enemy.getData().ai)); - + if(!enemy.nameOverride.isEmpty()) enemyPlayer.setName(enemy.nameOverride); //Override name if defined in the map. FSkin.getAvatars().put(90000, this.enemy.getAvatar()); enemyPlayer.setAvatarIndex(90000); aiPlayer.setPlayer(enemyPlayer); - aiPlayer.setStartingLife(Math.round((float)enemy.getData().life*Current.player().getDifficulty().enemyLifeFactor)); - - + aiPlayer.setStartingLife(Math.round((float)enemy.getData().life*advPlayer.getDifficulty().enemyLifeFactor)); Array playerEffects = new Array<>(); Array oppEffects = new Array<>(); //Collect and add items effects first. - for(String playerItem:Current.player().getEquippedItems()) { + for(String playerItem:advPlayer.getEquippedItems()) { ItemData item=ItemData.getItem(playerItem); playerEffects.add(item.effect); if(item.effect.opponent != null) oppEffects.add(item.effect.opponent); @@ -139,13 +139,22 @@ public class DuelScene extends ForgeScene { } //Collect and add player blessings. + if(advPlayer.getBlessing() != null){ + playerEffects.add(advPlayer.getBlessing()); + if(advPlayer.getBlessing().opponent != null) oppEffects.add(advPlayer.getBlessing().opponent); + } //Collect and add enemy effects (same as blessings but for individual enemies). + if(enemy.effect != null){ + oppEffects.add(enemy.effect); + if(enemy.effect.opponent != null) + playerEffects.add(enemy.effect.opponent); + } //Collect and add dungeon-wide effects. if(dungeonEffect != null) { oppEffects.add(dungeonEffect); - if (dungeonEffect.opponent != null) + if(dungeonEffect.opponent != null) playerEffects.add(dungeonEffect.opponent); } diff --git a/forge-gui-mobile/src/forge/adventure/scene/InnScene.java b/forge-gui-mobile/src/forge/adventure/scene/InnScene.java index 1e6d902ca6c..f78b2df8f18 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/InnScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/InnScene.java @@ -24,7 +24,7 @@ public class InnScene extends UIScene { } public void heal() { - Current.player().heal(); + Current.player().fullHeal(); } @Override diff --git a/forge-gui-mobile/src/forge/adventure/scene/InventoryScene.java b/forge-gui-mobile/src/forge/adventure/scene/InventoryScene.java index 65aea1de226..dea63ec1147 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/InventoryScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/InventoryScene.java @@ -63,91 +63,92 @@ public class InventoryScene extends UIScene { @Override public void resLoaded() { super.resLoaded(); - equipOverlay = new Texture(Config.instance().getFile(Paths.ITEMS_EQUIP)); - ui.onButtonPress("return", () -> done()); - leave = ui.findActor("return"); - ui.onButtonPress("delete", () -> confirm.show(stage)); - ui.onButtonPress("equip", () -> equip()); - equipButton = ui.findActor("equip"); - deleteButton = ui.findActor("delete"); - itemDescription = ui.findActor("item_description"); - leave.getLabel().setText(Forge.getLocalizer().getMessage("lblBack")); + equipOverlay = new Texture(Config.instance().getFile(Paths.ITEMS_EQUIP)); + ui.onButtonPress("return", () -> done()); + leave = ui.findActor("return"); + ui.onButtonPress("delete", () -> confirm.show(stage)); + ui.onButtonPress("equip", () -> equip()); + equipButton = ui.findActor("equip"); + deleteButton = ui.findActor("delete"); + itemDescription = ui.findActor("item_description"); + itemDescription.setAlignment(Align.topLeft); + leave.getLabel().setText(Forge.getLocalizer().getMessage("lblBack")); - inventoryButtons=new Array<>(); - equipmentSlots=new HashMap<>(); + inventoryButtons=new Array<>(); + equipmentSlots=new HashMap<>(); - Array children = ui.getChildren(); - for (int i = 0, n = children.size; i < n; i++) + Array children = ui.getChildren(); + for (int i = 0, n = children.size; i < n; i++) + { + + if(children.get(i).getName()!=null&&children.get(i).getName().startsWith("Equipment")) { - - if(children.get(i).getName()!=null&&children.get(i).getName().startsWith("Equipment")) - { - String slotName=children.get(i).getName().split("_")[1]; - equipmentSlots.put(slotName, (Button) children.get(i)); - Actor slot=children.get(i); - slot.addListener(new ChangeListener() { - @Override - public void changed(ChangeEvent event, Actor actor) { - Button button=((Button) actor); - if(button.isChecked()) + String slotName=children.get(i).getName().split("_")[1]; + equipmentSlots.put(slotName, (Button) children.get(i)); + Actor slot=children.get(i); + slot.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + Button button=((Button) actor); + if(button.isChecked()) + { + for(Button otherButton:equipmentSlots.values()) { - for(Button otherButton:equipmentSlots.values()) - { - if(button!=otherButton&&otherButton.isChecked()){ - otherButton.setChecked(false); - } - } - String item=Current.player().itemInSlot(slotName); - if(item!=null&&item!="") - { - Button changeButton=null; - for(Button invButton:inventoryButtons) - { - if(itemLocation.get(invButton)!=null&&itemLocation.get(invButton).equals(item)) - { - changeButton=invButton; - break; - } - } - if(changeButton!=null) - changeButton.setChecked(true); - } - else - { - setSelected(null); + if(button!=otherButton&&otherButton.isChecked()){ + otherButton.setChecked(false); } } - + String item=Current.player().itemInSlot(slotName); + if(item!=null&&item!="") + { + Button changeButton=null; + for(Button invButton:inventoryButtons) + { + if(itemLocation.get(invButton)!=null&&itemLocation.get(invButton).equals(item)) + { + changeButton=invButton; + break; + } + } + if(changeButton!=null) + changeButton.setChecked(true); + } + else + { + setSelected(null); + } } - }); - } + + } + }); } - inventory = new Table(Controls.GetSkin()); - ScrollPane scrollPane = ui.findActor("inventory"); - scrollPane.setScrollingDisabled(true,false); - scrollPane.setActor(inventory); - columns= (int) (scrollPane.getWidth()/createInventorySlot().getWidth()); - columns-=1; - if(columns<=0)columns=1; - scrollPane.setActor(inventory); - confirm = new Dialog("\n "+Forge.getLocalizer().getMessage("lblDelete"), Controls.GetSkin()) + } + inventory = new Table(Controls.GetSkin()); + ScrollPane scrollPane = ui.findActor("inventory"); + scrollPane.setScrollingDisabled(true,false); + scrollPane.setActor(inventory); + columns= (int) (scrollPane.getWidth()/createInventorySlot().getWidth()); + columns-=1; + if(columns<=0)columns=1; + scrollPane.setActor(inventory); + confirm = new Dialog("\n "+Forge.getLocalizer().getMessage("lblDelete"), Controls.GetSkin()) + { + protected void result(Object object) { - protected void result(Object object) - { - if(object!=null&&object.equals(true)) - delete(); - confirm.hide(); - }; + if(object!=null&&object.equals(true)) + delete(); + confirm.hide(); }; + }; - confirm.button(Forge.getLocalizer().getMessage("lblYes"), true); - confirm.button(Forge.getLocalizer().getMessage("lblNo"), false); - ui.addActor(confirm); - confirm.hide(); + confirm.button(Forge.getLocalizer().getMessage("lblYes"), true); + confirm.button(Forge.getLocalizer().getMessage("lblNo"), false); + ui.addActor(confirm); + confirm.hide(); - itemDescription.setWrap(true); - //makes confirm dialog hidden immediately when you open inventory first time.. - confirm.getColor().a = 0; + itemDescription.setWrap(true); + //makes confirm dialog hidden immediately when you open inventory first time.. + confirm.getColor().a = 0; } private void setSelected(Button actor) { @@ -198,17 +199,15 @@ public class InventoryScene extends UIScene { } - private void updateInventory() - { + private void updateInventory() { inventoryButtons.clear(); inventory.clear(); - for(int i=0;i> entry : Current.player().getStatistic().getWinLossRecord().entrySet()) { EnemyData data = WorldData.getEnemy(entry.getKey()); @@ -121,38 +153,47 @@ public class PlayerStatisticScene extends UIScene { @Override public void resLoaded() { super.resLoaded(); - enemiesGroup = new Table(Controls.GetSkin()); - enemiesGroup.row(); - ui.onButtonPress("return", new Runnable() { - @Override - public void run() { - PlayerStatisticScene.this.back(); - } - }); - avatar = ui.findActor("avatar"); - avatarBorder = ui.findActor("avatarBorder"); - playerName = ui.findActor("playerName"); - life = ui.findActor("lifePoints"); - money = ui.findActor("money"); - lifeIcon = ui.findActor("lifeIcon"); - goldIcon = ui.findActor("goldIcon"); - wins = ui.findActor("wins"); - wins.setText(Forge.getLocalizer().getMessage("lblWinProper")+":"); - totalWins = ui.findActor("totalWins"); - loss = ui.findActor("loss"); - loss.setText(Forge.getLocalizer().getMessage("lblLossProper")+":"); - totalLoss = ui.findActor("totalLoss"); - winloss = ui.findActor("winloss"); - winloss.setText(Forge.getLocalizer().getMessage("lblWinProper")+"/"+Forge.getLocalizer().getMessage("lblLossProper")); - lossWinRatio = ui.findActor("lossWinRatio"); - back = ui.findActor("return"); - back.getLabel().setText(Forge.getLocalizer().getMessage("lblBack")); - ScrollPane scrollPane = ui.findActor("enemies"); - scrollPane.setActor(enemiesGroup); + enemiesGroup = new Table(Controls.GetSkin()); + enemiesGroup.row(); + blessingScroll = Controls.newLabel(""); + blessingScroll.setStyle(new Label.LabelStyle(Controls.getBitmapFont("default"), Color.BLACK)); + blessingScroll.setAlignment(Align.topLeft); + blessingScroll.setWrap(true); + ui.onButtonPress("return", new Runnable() { + @Override + public void run() { + PlayerStatisticScene.this.back(); + } + }); + + avatar = ui.findActor("avatar"); + avatarBorder = ui.findActor("avatarBorder"); + playerName = ui.findActor("playerName"); + life = ui.findActor("lifePoints"); + money = ui.findActor("money"); + lifeIcon = ui.findActor("lifeIcon"); + goldIcon = ui.findActor("goldIcon"); + wins = ui.findActor("wins"); + colorFrame = ui.findActor("colorFrame"); + wins.setText(Forge.getLocalizer().getMessage("lblWinProper")+":"); + totalWins = ui.findActor("totalWins"); + loss = ui.findActor("loss"); + loss.setText(Forge.getLocalizer().getMessage("lblLossProper")+":"); + totalLoss = ui.findActor("totalLoss"); + winloss = ui.findActor("winloss"); + winloss.setText(Forge.getLocalizer().getMessage("lblWinProper")+"/"+Forge.getLocalizer().getMessage("lblLossProper")); + lossWinRatio = ui.findActor("lossWinRatio"); + back = ui.findActor("return"); + back.getLabel().setText(Forge.getLocalizer().getMessage("lblBack")); + ScrollPane scrollPane = ui.findActor("enemies"); + scrollPane.setActor(enemiesGroup); + colorFrames = new Texture(Config.instance().getFile("ui/color_frames.png")); + ScrollPane blessing = ui.findActor("blessingInfo"); + blessing.setActor(blessingScroll); + } @Override public void create() { - } } diff --git a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java index 0a6dd1e6663..f319020557d 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java @@ -66,7 +66,7 @@ public class RewardScene extends UIScene { } } if (wait) { - flipCountDown = 3.0f; + flipCountDown = 1.5f; doneClicked = true; } else { Forge.switchToLast(); diff --git a/forge-gui-mobile/src/forge/adventure/stage/ConsoleCommandInterpreter.java b/forge-gui-mobile/src/forge/adventure/stage/ConsoleCommandInterpreter.java index 2ac3b863d1e..6b773e25f47 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/ConsoleCommandInterpreter.java +++ b/forge-gui-mobile/src/forge/adventure/stage/ConsoleCommandInterpreter.java @@ -1,9 +1,17 @@ package forge.adventure.stage; +import com.badlogic.gdx.utils.Array; import forge.StaticData; +import forge.adventure.data.EnemyData; +import forge.adventure.data.WorldData; import forge.adventure.pointofintrest.PointOfInterest; +import forge.adventure.scene.SceneType; import forge.adventure.util.Current; +import forge.card.ColorSet; +import forge.deck.Deck; +import forge.deck.DeckProxy; +import forge.game.GameType; import forge.item.PaperCard; import java.util.ArrayList; @@ -161,10 +169,49 @@ public class ConsoleCommandInterpreter { return "Added item "+s[0]; return "can not find item "+s[0]; }); - registerCommand(new String[]{"heal"}, s -> { - Current.player().heal(); + registerCommand(new String[]{"fullHeal"}, s -> { + Current.player().fullHeal(); return "Player life back to "+Current.player().getLife(); }); + registerCommand(new String[]{"setColorID"}, s -> { + if(s.length < 1) return "Please specify color ID: Valid choices: B, G, R, U, W, C. Example:\n\"setColorID G\""; + Current.player().setColorIdentity(s[0]); + return "Player color identity set to " + Current.player().getColorIdentity(); + }); + registerCommand(new String[]{"reloadScenes"}, s -> { + SceneType.InventoryScene.instance.resLoaded(); + SceneType.PlayerStatisticScene.instance.resLoaded(); + + return "Force reload status scenes. Might be unstable."; + }); + registerCommand(new String[]{"resetQuests"}, s -> { + Current.player().resetQuestFlags(); + return "All global quest flags have been reset."; + }); + registerCommand(new String[]{"dumpEnemyDeckColors"}, s -> { + for(EnemyData E : new Array.ArrayIterator<>(WorldData.getAllEnemies())){ + Deck D = E.generateDeck(); + DeckProxy DP = new DeckProxy(D, "Constructed", GameType.Constructed, null); + ColorSet colorSet = DP.getColor(); + System.out.printf("%s: Colors: %s (%s%s%s%s%s%s)\n", D.getName(), DP.getColor(), + (colorSet.hasBlack() ? "B" : ""), + (colorSet.hasGreen() ? "G" : ""), + (colorSet.hasRed() ? "R" : ""), + (colorSet.hasBlue() ? "U" : ""), + (colorSet.hasWhite() ? "W" : ""), + (colorSet.isColorless() ? "C" : "") + ); + } + return "Enemy deck color list dumped to stdout."; + }); + registerCommand(new String[]{"heal", "amount"}, s -> { + if(s.length<1) return "Command needs 1 parameter"; + int N = 0; + try { N = Integer.parseInt(s[0]); } + catch (Exception e) { return "Can not convert " + s[0] + " to integer"; } + Current.player().heal(N); + return "Player healed to " + Current.player().getLife() + "/" + Current.player().getMaxLife(); + }); registerCommand(new String[]{"debug","on"}, s -> { Current.setDebug(true); return "Debug mode on"; diff --git a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java index 71488a88042..5c872a227fd 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java @@ -15,10 +15,9 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Group; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Dialog; +import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.Json; import com.badlogic.gdx.utils.ScreenUtils; -import com.badlogic.gdx.utils.SerializationException; import forge.Forge; import forge.adventure.character.*; import forge.adventure.data.*; @@ -64,7 +63,12 @@ public class MapStage extends GameStage { private Stage dialogStage; private boolean dialogOnlyInput; - private EffectData effect; + + //Map properties. + //These maps are defined as embedded properties within the Tiled maps. + private EffectData effect; //"Dungeon Effect": Character Effect applied to all adversaries within the map. + private boolean preventEscape = false; //Prevents player from escaping the dungeon by any means that aren't an exit. + public boolean getDialogOnlyInput() { return dialogOnlyInput; @@ -73,16 +77,18 @@ public class MapStage extends GameStage { return dialog; } + public boolean canEscape() { return (preventEscape ? true : false); } //Check if escape is possible. + public void clearIsInMap() { isInMap = false; - effect = null; + effect = null; //Reset effect so battles outside the dungeon don't use the last visited dungeon's effects. + preventEscape = false; GameHUD.getInstance().showHideMap(true); } public void draw (Batch batch) { //Camera camera = getCamera() ; //camera.update(); //update camera after all layers got drawn - if (!getRoot().isVisible()) return; getRoot().draw(batch, 1); } @@ -125,7 +131,6 @@ public class MapStage extends GameStage { } } return false; - } final ArrayList currentCollidingRectangles = new ArrayList<>(); @@ -185,8 +190,10 @@ public class MapStage extends GameStage { dialog.getButtonTable().clear(); String text = "Strange magical energies flow within this place...\nAll opponents get:\n"; text += E.getDescription(); - dialog.text(text); - dialog.getButtonTable().add(Controls.newTextButton("OK", this::hideDialog)); + Label L = Controls.newLabel(text); + L.setWrap(true); + dialog.getContentTable().add(L).width(260f); + dialog.getButtonTable().add(Controls.newTextButton("OK", this::hideDialog)).width(260f); dialog.setKeepWithinStage(true); showDialog(); } @@ -199,8 +206,8 @@ public class MapStage extends GameStage { for (MapActor actor : new Array.ArrayIterator<>(actors)) { actor.remove(); foregroundSprites.removeActor(actor); - } + actors = new Array<>(); width = Float.parseFloat(map.getProperties().get("width").toString()); height = Float.parseFloat(map.getProperties().get("height").toString()); @@ -210,16 +217,17 @@ public class MapStage extends GameStage { collision = new ArrayList[(int) width][(int) height]; //Load dungeon effects. - if( map.getProperties().get("dungeonEffect") != null && !map.getProperties().get("dungeonEffect").toString().isEmpty()){ - Json json = new Json(); - try { effect = json.fromJson(EffectData.class, map.getProperties().get("dungeonEffect").toString()); } - catch(SerializationException E) { - //JSON parsing could fail. Since this an user written part, assume failure is possible (it happens). - System.err.printf("[%s] while loading JSON file for dialog actor. JSON:\n%s\nUsing a default dialog.", E.getMessage(), map.getProperties().get("dungeonEffect").toString()); - effect = json.fromJson(EffectData.class, ""); - } + MapProperties MP = map.getProperties(); + + if( MP.get("dungeonEffect") != null && !MP.get("dungeonEffect").toString().isEmpty()){ + JSONStringLoader J = new JSONStringLoader(); + effect = J.parse(EffectData.class, map.getProperties().get("dungeonEffect").toString(), ""); effectDialog(effect); } + if (MP.get("preventEscape") != null) preventEscape = (boolean)MP.get("preventEscape"); + if (MP.get("music") != null && !MP.get("music").toString().isEmpty()){ + //TODO: Add a way to play a music file directly without using a playlist. + } GetPlayer().stop(); @@ -258,7 +266,6 @@ public class MapStage extends GameStage { private void loadObjects(MapLayer layer, String sourceMap) { player.setMoveModifier(2); for (MapObject obj : layer.getObjects()) { - MapProperties prop = obj.getProperties(); Object typeObject = prop.get("type"); if (typeObject != null) { @@ -276,22 +283,52 @@ public class MapStage extends GameStage { addMapActor(obj, entry); break; case "reward": - if (prop.get("reward") != null) { - RewardSprite R = new RewardSprite(id, prop.get("reward").toString(), prop.get("sprite").toString()); - addMapActor(obj, R); + Object R = prop.get("reward"); + if(R != null && !R.toString().isEmpty()) { + Object S = prop.get("sprite"); + String Sp = "sprites/treasure.atlas"; + if(S != null && !S.toString().isEmpty()) Sp = S.toString(); + else System.err.printf("No sprite defined for reward (ID:%s), defaulting to \"sprites/treasure.atlas\"", id); + RewardSprite RW = new RewardSprite(id, R.toString(), Sp); + addMapActor(obj, RW); } break; case "enemy": - EnemySprite mob = new EnemySprite(id, WorldData.getEnemy(prop.get("enemy").toString())); - addMapActor(obj, mob); - if(prop.get("dialog") != null && !prop.get("dialog").toString().isEmpty()) { - mob.dialog = new MapDialog(prop.get("dialog").toString(), this, mob.getId()); + Object E = prop.get("enemy"); + if(E != null && !E.toString().isEmpty()) { + EnemyData EN = WorldData.getEnemy(E.toString()); + if(EN == null){ + System.err.printf("Enemy \"%s\" not found.", E.toString()); + break; + } + EnemySprite mob = new EnemySprite(id, EN); + Object D = prop.get("dialog"); //Check if the enemy has a dialogue attached to it. + if (D != null && !D.toString().isEmpty()) { + mob.dialog = new MapDialog(D.toString(), this, mob.getId()); + } + D = prop.get("defeatDialog"); //Check if the enemy has a defeat dialogue attached to it. + if (D != null && !D.toString().isEmpty()) { + mob.defeatDialog = new MapDialog(D.toString(), this, mob.getId()); + } + D = prop.get("name"); //Check for name override. + if (D != null && !D.toString().isEmpty()) { + mob.nameOverride = D.toString(); + } + D = prop.get("effect"); //Check for special effects. + if (D != null && !D.toString().isEmpty()) { + mob.effect = JSONStringLoader.parse(EffectData.class, D.toString(), ""); + } + //TODO: Additional rewards. + //TODO: Filter by difficulty. (Don't spawn if doesn't match) + addMapActor(obj, mob); } break; case "dummy": //Does nothing. Mostly obstacles to be removed by ID by switches or such. TiledMapTileMapObject obj2 = (TiledMapTileMapObject) obj; DummySprite D = new DummySprite(id, obj2.getTextureRegion(), this); addMapActor(obj, D); + //TODO: Ability to toggle their solid state. + //TODO: Ability to move them (using a sequence such as "UULU" for up, up, left, up). break; case "inn": addMapActor(obj, new OnCollide(new Runnable() { @@ -407,7 +444,8 @@ public class MapStage extends GameStage { return false; } - public boolean lookForID(int id){ + public boolean lookForID(int id){ //Search actor by ID. + for(MapActor A : new Array.ArrayIterator<>(actors)){ if(A.getId() == id) return true; @@ -415,7 +453,7 @@ public class MapStage extends GameStage { return false; } - public EnemySprite getEnemyByID(int id) { + public EnemySprite getEnemyByID(int id) { //Search actor by ID, enemies only. for(MapActor A : new Array.ArrayIterator<>(actors)){ if(A instanceof EnemySprite && A.getId() == id) return ((EnemySprite) A); @@ -426,11 +464,17 @@ public class MapStage extends GameStage { protected void getReward() { isLoadingMatch = false; ((RewardScene) SceneType.RewardScene.instance).loadRewards(currentMob.getRewards(), RewardScene.Type.Loot, null); - currentMob.remove(); - actors.removeValue(currentMob, true); - changes.deleteObject(currentMob.getId()); - currentMob = null; Forge.switchScene(SceneType.RewardScene.instance); + if(currentMob.defeatDialog == null) { + currentMob.remove(); + actors.removeValue(currentMob, true); + changes.deleteObject(currentMob.getId()); + } else { + currentMob.defeatDialog.activate(); + player.setAnimation(CharacterSprite.AnimationTypes.Idle); + currentMob.setAnimation(CharacterSprite.AnimationTypes.Idle); + } + currentMob = null; } public void removeAllEnemies() { @@ -455,9 +499,8 @@ public class MapStage extends GameStage { if (actor instanceof EnemySprite) { EnemySprite mob = (EnemySprite) actor; currentMob = mob; - if (mob.dialog != null){ //This enemy has something to say. Display a dialog like if it was a DialogActor. - resetPosition(); - showDialog(); + resetPosition(); + if(mob.dialog != null && mob.dialog.canShow()){ //This enemy has something to say. Display a dialog like if it was a DialogActor but only if dialogue is possible. mob.dialog.activate(); } else { //Duel the enemy. beginDuel(mob); @@ -499,7 +542,7 @@ public class MapStage extends GameStage { } }, ScreenUtils.getFrameBufferTexture(), true, false)); } - startPause(0.4f, new Runnable() { + startPause(0.3f, new Runnable() { @Override public void run() { DuelScene S = ((DuelScene) SceneType.DuelScene.instance); @@ -533,7 +576,6 @@ public class MapStage extends GameStage { } public void resetPosition() { - player.setPosition(oldPosition4); stop(); } diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index 6f4273edacf..86ba3c5b102 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -91,7 +91,7 @@ public class WorldStage extends GameStage implements SaveFileContent { Forge.clearTransitionScreen(); } }, ScreenUtils.getFrameBufferTexture(), true, false)); - startPause(0.5f, new Runnable() { + startPause(0.3f, new Runnable() { @Override public void run() { ((DuelScene) SceneType.DuelScene.instance).setEnemy(currentMob); diff --git a/forge-gui-mobile/src/forge/adventure/util/JSONStringLoader.java b/forge-gui-mobile/src/forge/adventure/util/JSONStringLoader.java new file mode 100644 index 00000000000..c7faac4c2e0 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/util/JSONStringLoader.java @@ -0,0 +1,27 @@ +package forge.adventure.util; + +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.Null; +import com.badlogic.gdx.utils.SerializationException; +/** + * JSONStringLoader + * Wrapper around Json functions for easier loading of arbitrary JSON strings without + * having to try/catch every time. + */ +public class JSONStringLoader { + private static final Json JSON = new Json(); + public static @Null T parse(Class type, String json, String fallback){ + return parse(type, null, json, fallback); + } + + public static @Null T parse(Class type, Class elementType, String json, String fallback){ + if(json != null && !json.isEmpty()){ + try { return JSON.fromJson(type, elementType, json); } + catch(SerializationException E) { + //JSON parsing could fail. Since this an user written part, assume failure is possible (it happens). + System.err.printf("Error loading JSON string:\n%s\nUsing fallback.", E.getMessage()); + } + } + return JSON.fromJson(type, elementType, fallback); + } +} diff --git a/forge-gui-mobile/src/forge/adventure/util/MapDialog.java b/forge-gui-mobile/src/forge/adventure/util/MapDialog.java index f023bfeff5f..c6eb16c6ece 100644 --- a/forge-gui-mobile/src/forge/adventure/util/MapDialog.java +++ b/forge-gui-mobile/src/forge/adventure/util/MapDialog.java @@ -2,10 +2,10 @@ package forge.adventure.util; import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.Json; -import com.badlogic.gdx.utils.SerializationException; import forge.Forge; +import forge.adventure.character.EnemySprite; import forge.adventure.data.DialogData; +import forge.adventure.player.AdventurePlayer; import forge.adventure.stage.MapStage; import forge.util.Localizer; @@ -32,21 +32,15 @@ public class MapDialog { "]"; - public MapDialog(String S, MapStage ST, int parentID) { - this.stage = ST; + public MapDialog(String S, MapStage stage, int parentID) { + this.stage = stage; this.parentID = parentID; - Json json = new Json(); - if (S.isEmpty()){ + if (S.isEmpty()) { System.err.print("Dialog error. Dialog property is empty.\n"); - this.data = json.fromJson(Array.class, DialogData.class, defaultJSON); + this.data = JSONStringLoader.parse(Array.class, DialogData.class, defaultJSON, defaultJSON); return; } - try { data = json.fromJson(Array.class, DialogData.class, S); } - catch(SerializationException E){ - //JSON parsing could fail. Since this an user written part, assume failure is possible (it happens). - System.err.printf("[%s] while loading JSON file for dialog actor. JSON:\n%s\nUsing a default dialog.", E.getMessage(), S); - this.data = json.fromJson(Array.class, DialogData.class, defaultJSON); - } + this.data = JSONStringLoader.parse(Array.class, DialogData.class, S, defaultJSON); } private void loadDialog(DialogData dialog) { //Displays a dialog with dialogue and possible choices. @@ -69,6 +63,7 @@ public class MapDialog { TextButton B = Controls.newTextButton(name,() -> loadDialog(option)); B.getLabel().setWrap(true); //We want this to wrap in case it's a wordy choice. D.getButtonTable().add(B).width(WIDTH - 10); //The button table also returns a Cell when adding. + //TODO: Reducing the space a tiny bit could help. But should be fine as long as there aren't more than 4-5 options. D.getButtonTable().row(); //Add a row. Tried to allow a few per row but it was a bit erratic. } } @@ -79,7 +74,7 @@ public class MapDialog { } } - public void activate() { + public void activate() { //Method for actors to show their dialogues. for(DialogData dialog:data) { if(isConditionOk(dialog.condition)) { loadDialog(dialog); @@ -87,42 +82,122 @@ public class MapDialog { } } - void setEffects(DialogData.EffectData[] data) { + void setEffects(DialogData.ActionData[] data) { if(data==null) return; - for(DialogData.EffectData E:data) { - if (E.removeItem != null){ //Removes an item from the player's inventory. + for(DialogData.ActionData E:data) { + if(E.removeItem != null){ //Removes an item from the player's inventory. Current.player().removeItem(E.removeItem); } - if (E.addItem != null){ //Gives an item to the player. + if(E.addItem != null){ //Gives an item to the player. Current.player().addItem(E.addItem); } - if (E.deleteMapObject != 0){ //Removes a dummy object from the map. + if(E.addLife != 0){ //Gives (positive or negative) life to the player. Cannot go over max health. + Current.player().heal(E.addLife); + } + if(E.addGold != 0){ //Gives (positive or negative) gold to the player. + if(E.addGold > 0) Current.player().giveGold(E.addGold); + else Current.player().takeGold(-E.addGold); + } + if(E.deleteMapObject != 0){ //Removes a dummy object from the map. if(E.deleteMapObject < 0) stage.deleteObject(parentID); else stage.deleteObject(E.deleteMapObject); } - if (E.battleWithActorID != 0){ //Starts a battle with the given enemy ID. + if(E.battleWithActorID != 0){ //Starts a battle with the given enemy ID. if(E.battleWithActorID < 0) stage.beginDuel(stage.getEnemyByID(parentID)); else stage.beginDuel(stage.getEnemyByID(E.battleWithActorID)); } + if(E.giveBlessing != null) { //Gives a blessing for your next battle. + Current.player().addBlessing(E.giveBlessing); + } + if(E.setColorIdentity != null && !E.setColorIdentity.isEmpty()){ //Sets color identity (use sparingly) + Current.player().setColorIdentity(E.setColorIdentity); + } //Create map object. - //Check for quest flags, local. - //Check for quest flags, global. + //Toggle dummy object's hitbox. (Like to make a door passable) + if(E.setQuestFlag != null && !E.setQuestFlag.key.isEmpty()){ //Set a quest to given value. + Current.player().setQuestFlag(E.setQuestFlag.key, E.setQuestFlag.val); + } + if(E.advanceQuestFlag != null && !E.advanceQuestFlag.isEmpty()){ //Increase a given quest flag by 1. + Current.player().advanceQuestFlag(E.advanceQuestFlag); + } + //Set dungeon flag. + if(E.setEffect != null){ //Replace current effects. + EnemySprite EN = stage.getEnemyByID(parentID); + EN.effect = E.setEffect; + } } } + public boolean canShow(){ + if( data == null) return false; + for(DialogData dialog:data) { + if(isConditionOk(dialog.condition)) { + return true; + } + } + return false; + } + boolean isConditionOk(DialogData.ConditionData[] data) { - if(data==null) return true; + if( data==null ) return true; + AdventurePlayer player = Current.player(); for(DialogData.ConditionData condition:data) { - if(condition.item != null && !condition.item.isEmpty()) { //Check for item. - if(!Current.player().hasItem(condition.item)) { + if(condition.item != null && !condition.item.isEmpty()) { //Check for an item in player's inventory. + if(!player.hasItem(condition.item)) { if(!condition.not) return false; //Only return on a false. } else if(condition.not) return false; } + if(condition.colorIdentity != null && !condition.colorIdentity.isEmpty()) { //Check for player's color ID. + if(!player.getColorIdentity().equals(condition.colorIdentity.toUpperCase())){ + if(!condition.not) return false; + } else if(condition.not) return false; + } + if(condition.hasGold != 0){ //Check for at least X gold. + if(player.getGold() < condition.hasGold){ + if(!condition.not) return false; + } else if(condition.not) return false; + } + if(condition.hasLife != 0){ //Check for at least X life.. + if(player.getLife() < condition.hasLife + 1){ + if(!condition.not) return false; + } else if(condition.not) return false; + } + if(condition.hasBlessing != null && !condition.hasBlessing.isEmpty()){ //Check for a named blessing. + if(!player.hasBlessing(condition.hasBlessing)){ + if(!condition.not) return false; + } else if(condition.not) return false; + } if(condition.actorID != 0) { //Check for actor ID. if(!stage.lookForID(condition.actorID)){ if(!condition.not) return false; //Same as above. } else if(condition.not) return false; } + if(condition.getQuestFlag != null){ + String key = condition.getQuestFlag.key; + String cond = condition.getQuestFlag.op; + + int val = condition.getQuestFlag.val; + int QF = player.getQuestFlag(key); + boolean result = false; + if(!player.checkQuestFlag(key)) return false; //If the quest is not ongoing, stop. + + + switch(cond){ + default: case "EQUALS": case"EQUAL": case "=": + if(QF == val) result = true; break; + case "LESSTHAN": case "<": if(QF < val) result = true; break; + case "MORETHAN": case ">": if(QF > val) result = true; break; + case "LE_THAN": case "<=": if(QF <= val) result = true; break; + case "ME_THAN": case ">=": if(QF >= val) result = true; break; + } + if(!result) { if(!condition.not) return false; } + else { if(condition.not) return false; } + } + if(condition.checkQuestFlag != null && !condition.checkQuestFlag.isEmpty()){ + if(!player.checkQuestFlag(condition.checkQuestFlag)){ + if(!condition.not) return false; + } else if(condition.not) return false; + } } return true; } diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index ab240aa1a51..0c7117c0d86 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -3,6 +3,7 @@ package forge.adventure.world; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; @@ -47,6 +48,7 @@ public class World implements Disposable, SaveFileContent { private long seed; private final Random random = MyRandom.getRandom(); private boolean worldDataLoaded=false; + private Texture globalTexture = null; public Random getRandom() { @@ -570,5 +572,11 @@ public class World implements Disposable, SaveFileContent { random.setSeed(seedOffset+seed); } - + public Texture getGlobalTexture() { + if(globalTexture == null){ + globalTexture = new Texture(Config.instance().getFile("ui/sprite_markers.png")); + System.out.print("Loading auxiliary sprites.\n"); + } + return globalTexture; + } } diff --git a/forge-gui-mobile/src/forge/adventure/world/WorldSave.java b/forge-gui-mobile/src/forge/adventure/world/WorldSave.java index adcd6c0af5b..f0a5ab683f0 100644 --- a/forge-gui-mobile/src/forge/adventure/world/WorldSave.java +++ b/forge-gui-mobile/src/forge/adventure/world/WorldSave.java @@ -118,12 +118,11 @@ public class WorldSave { return currentSave; } - public static WorldSave generateNewWorld(String name, boolean male, int race, int avatarIndex, int startingDeckIndex, DifficultyData diff, long seed) { - + public static WorldSave generateNewWorld(String name, boolean male, int race, int avatarIndex, int startingColorIdentity, DifficultyData diff, long seed) { currentSave.world.generateNew(seed); currentSave.pointOfInterestChanges.clear(); - Deck starterDeck = Config.instance().starterDecks()[startingDeckIndex]; - currentSave.player.create(name, starterDeck, male, race, avatarIndex,diff); + Deck starterDeck = Config.instance().starterDecks()[startingColorIdentity]; + currentSave.player.create(name, startingColorIdentity, starterDeck, male, race, avatarIndex,diff); 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.onLoadList.emit(); diff --git a/forge-gui/res/adventure/Shandalar/maps/main.tiled-session b/forge-gui/res/adventure/Shandalar/maps/main.tiled-session index 05bdc7e82df..28b54e498f6 100644 --- a/forge-gui/res/adventure/Shandalar/maps/main.tiled-session +++ b/forge-gui/res/adventure/Shandalar/maps/main.tiled-session @@ -3,12 +3,12 @@ "height": 4300, "width": 2 }, - "activeFile": "map/waste_town.tmx", + "activeFile": "map/debug_map.tmx", "automapping.whileDrawing": false, "expandedProjectPaths": [ + "obj", "tileset", "map/main_story", - "obj", "map" ], "file.lastUsedOpenFilter": "All Files (*)", @@ -1422,11 +1422,11 @@ } }, "map/debug_map.tmx": { - "scale": 8, + "scale": 2, "selectedLayer": 3, "viewCenter": { - "x": 240, - "y": 239.875 + "x": 175.75, + "y": 316 } }, "map/djinnpalace_1.tmx": { @@ -2663,7 +2663,7 @@ "scale": 3, "selectedLayer": 4, "viewCenter": { - "x": 235.33333333333331, + "x": 235.5, "y": 135.66666666666663 } }, @@ -2714,7 +2714,7 @@ "tileset/main.tsx": { "dynamicWrapping": false, "scaleInDock": 1.5, - "scaleInEditor": 0.75 + "scaleInEditor": 1 } }, "map.height": 60, @@ -2726,16 +2726,14 @@ "openFiles": [ "map/debug_map.tmx", "tileset/buildings.tsx", - "tileset/main.tsx", - "map/waste_town.tmx" + "tileset/main.tsx" ], "project": "main.tiled-project", "property.type": "string", "recentFiles": [ - "map/debug_map.tmx", - "tileset/buildings.tsx", "tileset/main.tsx", - "map/waste_town.tmx", + "tileset/buildings.tsx", + "map/debug_map.tmx", "map/main_story/white_castle.tmx", "map/main_story/final_castle.tmx", "map/main_story/black_castle.tmx", @@ -2743,7 +2741,8 @@ "map/main_story/green_castle.tmx", "map/main_story/blue_castle.tmx", "map/main_story/colorless_castle.tmx", - "map/barbariancamp_2.tmx" + "map/barbariancamp_2.tmx", + "map/portal_1G2.tmx" ], "resizeMap.removeObjects": true, "textEdit.monospace": true diff --git a/forge-gui/res/adventure/Shandalar/maps/map/debug_map.tmx b/forge-gui/res/adventure/Shandalar/maps/map/debug_map.tmx index bdf8c9d7f65..3609c25b5cf 100644 --- a/forge-gui/res/adventure/Shandalar/maps/map/debug_map.tmx +++ b/forge-gui/res/adventure/Shandalar/maps/map/debug_map.tmx @@ -1,5 +1,5 @@ - + @@ -32,11 +32,17 @@ - - + + { + "lifeModifier": -25, + "opponent":{ + "startBattleWithCard": [ "c_0_1_eldrazi_spawn_sac", "c_0_1_eldrazi_spawn_sac", "c_0_1_eldrazi_spawn_sac", "c_0_1_eldrazi_spawn_sac" ] + } +} + @@ -70,13 +76,12 @@ - - + + - + - - + [ { @@ -90,7 +95,7 @@ ] - + [ { @@ -106,10 +111,16 @@ + [ + { + "text":"Impressive...", + "loctext":"", + "options":[ { "name":"Hey why are you still standing...?" } ] + } +] [ { "effect":[], - "name":"ABC", "text":"I am an elf. I do elf things like hugging trees and being pretty.", "loctext":"", "condition":[], @@ -118,7 +129,13 @@ { "name":"Fight me, elf!", "text": "Gladly.", - "options": [ { "name": "I FEAR NOTHING!!?", "effect": [ { "battleWithActorID": -1 } ]} ] + "options": [ { "name": "Hey aren't you a bit swole for an elf...?", "effect": [ { "battleWithActorID": -1 } ]} ] + }, + { + "name": "I want to be eco-friendly too.", + "condition": [ { "colorIdentity": "G", "not": true } ], + "text": "Listen to the forest, friend.\nYour color identity is now green!", + "options": [ { "name": "Awesome.", "effect": [ { "setColorIdentity": "G" } ]} ] }, { "name":"I wanna fight Emrakul over there!", @@ -133,35 +150,193 @@ "options": [ { "name": "Sorry..." } ] }, { - "name":"That's cool dude.", - "condition": [ { "item": "Treasure", "not": true } ], + "name":"That's cool my green dude.", + "condition": [ { "item": "Treasure", "not": true }, { "colorIdentity": "G" } ], "effect": [ { "addItem": "Treasure" } ], - "text": "You get it. Take this.", + "text": "You get it! Take this.", "options": [ { "name": "Thanks bro." } ] }, + { + "name":"Thanks for the blessing.", + "condition": [ { "hasBlessing": "Debug Elf" } ], + "text": "You are welcome.", + "options": [ { "name": "Thumbs up emoji" } ] + }, + { + "name":"Got any fancy elven blessing?", + "condition": [ { "item": "Treasure" }, { "hasBlessing": "Debug Elf", "not": true } ], + "text": "If you give me a Treasure, I will give you the blessing of the Debug Elf.\nWhich is a Llanowar Elves and 2 extra life in your next battle. Sounds good?", + "options": [ + { "name": "But I love my Treasure! I humbly refuse."}, + { + "name": "I'll take it", + "effect": [ + { "removeItem": "Treasure", "giveBlessing": { "name": "Debug Elf" ,"lifeModifier": 2, "startBattleWithCard": [ "Llanowar Elves" ] } } + ] + } + ] + }, { "name":"Can you open that hidden wall?", "condition": [ { "actorID": 83 } ], "text": "Since you asked nicely, I shall.", "options": [ { "name": "Thanks bro.", "effect": [ { "deleteMapObject": 83 } ]} ] + }, + { + "name": "Got a quest?", + "condition": [ { "checkQuestFlag": "128", "not": true} ], + "text": "Ah, perhaps you can help me. Can you ask the Debug Demon about his favorite color?", + "options": [ + { "name": "That's weird, but sure.", "effect": [ { "setQuestFlag": {"key":"128", "val": 1} } ] }, + { "name": "That guy scares me, I'd rather not." } + ] + }, + { + "name": "About that quest...", + "condition": [ { "getQuestFlag": { "key": "128", "op":"<", "val": 3 } } ], + "text": "Please let me know what the Debug Demon's answer is.", + "options": [ + { "name": "Sure" } + ] + }, + { + "name": "Got it, bro.", + "condition": [ { "getQuestFlag": { "key": "128", "op":"=", "val": 3 } } ], + "text": "Ah. I see. Thank you friend, have this gold for your inconvenience.", + "options": [ + { "name": "Thanks", "effect": [ { "setQuestFlag": {"key":"128", "val": 4}, "addGold": 250 } ] } + ] + } + ] } - ] - } -] - - + ] + { + "lifeModifier": 190, + "startBattleWithCard": [ "Llanowar Elves", "Llanowar Elves", "Forest", "Forest" ] +} + + + [ + { + "text": "You...you hurt Grog!\nYou...you filthy swine! I will stop at nothing until I see you defeated!\nGods...anyone! Grant me strength! Grant me REVENGE!!!!", + "condition": [ + { + "actorID": 82, + "not": true + } + ], + "options": [ + { + "name": "Uh oh.", + "effect": [ + { + "setEffect": { + "lifeModifier": 99, + "startBattleWithCard": [ + "Avacyn, Angel of Hope", + "Urabrask the Hidden", + "Elesh Norn, Grand Cenobite", + "Emrakul, the Aeons Torn" + ] + }, "battleWithActorID": -1 + } + ] + } + ] + } +] + [ + { + "text":"...", + "condition":[ { "getQuestFlag": { "key": "128", "op":"<", "val": 3 } } ], + "options":[ + { "name":"???" } + ] + } +] + + + [ + { + "effect":[], + "text":"I have some things to offer for that life you have...", + "condition":[], + "options":[ + { "name":"You are suspicious and have two shadows, I'm out." }, + { + "name":"I'll vanquish you, demon!", + "text": "Oh look we got a tough guy over here!", + "options": [ { "name": "I FEAR NOTHING!!", "effect": [ { "battleWithActorID": -1 } ]} ] + }, + { + "name": "I dig your edge.", + "condition": [ { "colorIdentity": "B", "not": true }, { "hasLife": 2 } ], + "text": "You can be dark and edgy like me. Maybe for some of your life force...", + "options": [ { "name": "I'm doing nothing better with it.", "effect": [ { "setColorIdentity": "B", "addLife": -2 } ]} ] + }, + { + "name": "I dig your edge.", + "condition": [ { "colorIdentity": "B", "not": true }, { "hasLife": 2, "not": true } ], + "text": "You don't have enough life force...come back with more to offer.", + "options": [ { "name": "Aw man..." } ] + }, + { + "name": "Any cool demon deals?", + "condition": [ { "colorIdentity": "B" }, { "hasGold": 200 } ], + "text": "I can offer you this Treasure for the fair price of 200 gold.", + "options": [ + { "name": "This gem has a lot of edge, just like me. Deal!" , "effect": [ { "addGold": -20000, "addItem": "Treasure" } ] }, + { "name": "I'll think about it." } + ] + }, + { + "name":"Got any fancy demon blessing?", + "condition": [ {"colorIdentity": "B"}, { "item": "Treasure" }, { "hasBlessing": "Debug Demon", "not": true } ], + "text": "Give me that Treasure of yours...\n(+1 health, Manasight, move speed 120%, Lord of the Pit starts in play)", + "options": [ + { "name": "That's shady."}, + { + "name": "What can possibly go wrong?", + "effect": [ + { "removeItem": "Treasure", "giveBlessing": { "name": "Debug Demon" , "lifeModifier": 1, "colorView": true, "moveSpeed": 2, "startBattleWithCard": [ "Lord of the Pit" ] } } + ] + } + ] + }, + { + "name": "Hey what's your favorite color?", + "condition": [ {"getQuestFlag": { "key":"128", "op":"=", "val":1 } } ], + "text": "Why, purple. It is a powerful color.", + "options": [ + { "name": "Thank you Satan.", "effect": [ { "setQuestFlag": { "key":"128", "val":3 } } ] } + ] + } + ] + } +] + + + + + + + [ + { "cardName": "Black Lotus", "type":"card", "count":1 } +] + + diff --git a/forge-gui/res/adventure/Shandalar/maps/obj/scroll.tx b/forge-gui/res/adventure/Shandalar/maps/obj/scroll.tx new file mode 100644 index 00000000000..8b317692960 --- /dev/null +++ b/forge-gui/res/adventure/Shandalar/maps/obj/scroll.tx @@ -0,0 +1,10 @@ + + diff --git a/forge-gui/res/adventure/Shandalar/maps/tileset/buildings.png b/forge-gui/res/adventure/Shandalar/maps/tileset/buildings.png index d069b144752..c590e2df4e9 100644 Binary files a/forge-gui/res/adventure/Shandalar/maps/tileset/buildings.png and b/forge-gui/res/adventure/Shandalar/maps/tileset/buildings.png differ diff --git a/forge-gui/res/adventure/Shandalar/maps/tileset/buildings.xcf b/forge-gui/res/adventure/Shandalar/maps/tileset/buildings.xcf index 1cb8d253696..a2f068736f6 100644 Binary files a/forge-gui/res/adventure/Shandalar/maps/tileset/buildings.xcf and b/forge-gui/res/adventure/Shandalar/maps/tileset/buildings.xcf differ diff --git a/forge-gui/res/adventure/Shandalar/skin/ui_skin.atlas b/forge-gui/res/adventure/Shandalar/skin/ui_skin.atlas index 1eca92c5dcb..c0e7b918780 100644 --- a/forge-gui/res/adventure/Shandalar/skin/ui_skin.atlas +++ b/forge-gui/res/adventure/Shandalar/skin/ui_skin.atlas @@ -321,3 +321,12 @@ touchKnob orig: 72, 72 offset: 0, 0 index: -1 +dummy + rotate: false + xy: 0, 360 + size: 5,5 + orig: 1,1 + split: 1, 1, 1, 1 + pad: 0, 0, 0, 0 + offset: 0,0 + index:-1 diff --git a/forge-gui/res/adventure/Shandalar/skin/ui_skin.json b/forge-gui/res/adventure/Shandalar/skin/ui_skin.json index d909ab8bef0..3b681e94305 100644 --- a/forge-gui/res/adventure/Shandalar/skin/ui_skin.json +++ b/forge-gui/res/adventure/Shandalar/skin/ui_skin.json @@ -249,6 +249,25 @@ "frameDuration": 0.03, "regions": [], "playMode": 2 + }, + "dummy": { + "region": "dummy", + "horizontalStretchAreas": [ 1, 1 ], + "verticalStretchAreas": [ 1, 1 ], + "tiling": true, + "minWidth": 5, + "minHeight": 5, + "rightWidth": 0, + "leftWidth": 0, + "bottomHeight": 0, + "topHeight": 0, + "offsetX": 0, + "offsetY": 0, + "offsetXspeed": 0, + "offsetYspeed": 0, + "frameDuration": 0.03, + "regions": [], + "playMode": 2 } }, "com.badlogic.gdx.scenes.scene2d.ui.Button$ButtonStyle": { @@ -316,6 +335,9 @@ "whiteBig": { "font": "default" } + "nobg": { + "font": "black" + } }, "com.badlogic.gdx.scenes.scene2d.ui.List$ListStyle": { "default": { @@ -345,6 +367,9 @@ }, "gold": { "background": "9patch4" + }, + "nobg": { + "background": "dummy", } }, "com.badlogic.gdx.scenes.scene2d.ui.SelectBox$SelectBoxStyle": { diff --git a/forge-gui/res/adventure/Shandalar/sprites/1life.atlas b/forge-gui/res/adventure/Shandalar/sprites/1life.atlas index 4718bc62b7f..1dfa6cf6e68 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/1life.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/1life.atlas @@ -1,5 +1,5 @@ treasure.png -size: 64,112 +size: 64,128 format: RGBA8888 filter: Nearest,Nearest repeat: none diff --git a/forge-gui/res/adventure/Shandalar/sprites/2life.atlas b/forge-gui/res/adventure/Shandalar/sprites/2life.atlas index 20651148734..30ed39daf9c 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/2life.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/2life.atlas @@ -1,5 +1,5 @@ treasure.png -size: 64,112 +size: 64,128 format: RGBA8888 filter: Nearest,Nearest repeat: none diff --git a/forge-gui/res/adventure/Shandalar/sprites/3life.atlas b/forge-gui/res/adventure/Shandalar/sprites/3life.atlas index abc2ae050f5..9a3b13fe131 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/3life.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/3life.atlas @@ -1,5 +1,5 @@ treasure.png -size: 64,112 +size: 64,128 format: RGBA8888 filter: Nearest,Nearest repeat: none diff --git a/forge-gui/res/adventure/Shandalar/sprites/booster.atlas b/forge-gui/res/adventure/Shandalar/sprites/booster.atlas index f852f7067d0..db4bc8eb158 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/booster.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/booster.atlas @@ -1,5 +1,5 @@ treasure.png -size: 64,112 +size: 64,128 format: RGBA8888 filter: Nearest,Nearest repeat: none diff --git a/forge-gui/res/adventure/Shandalar/sprites/gold.atlas b/forge-gui/res/adventure/Shandalar/sprites/gold.atlas index 6d45a763d5f..77f40aabc45 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/gold.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/gold.atlas @@ -1,5 +1,5 @@ treasure.png -size: 64,112 +size: 64,128 format: RGBA8888 filter: Nearest,Nearest repeat: none diff --git a/forge-gui/res/adventure/Shandalar/sprites/scroll.atlas b/forge-gui/res/adventure/Shandalar/sprites/scroll.atlas new file mode 100644 index 00000000000..fed15bd9fa6 --- /dev/null +++ b/forge-gui/res/adventure/Shandalar/sprites/scroll.atlas @@ -0,0 +1,17 @@ +treasure.png +size: 64,128 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +Idle + xy: 0, 112 + size: 16, 16 +Idle + xy: 16, 112 + size: 16, 16 +Idle + xy: 32, 112 + size: 16, 16 +Idle + xy: 48, 112 + size: 16, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/treasure.png b/forge-gui/res/adventure/Shandalar/sprites/treasure.png index 3f58ea7ef2f..a25b381e9bf 100644 Binary files a/forge-gui/res/adventure/Shandalar/sprites/treasure.png and b/forge-gui/res/adventure/Shandalar/sprites/treasure.png differ diff --git a/forge-gui/res/adventure/Shandalar/ui/avatarhud.png b/forge-gui/res/adventure/Shandalar/ui/avatarhud.png index ac39721de69..37cf557fc9a 100644 Binary files a/forge-gui/res/adventure/Shandalar/ui/avatarhud.png and b/forge-gui/res/adventure/Shandalar/ui/avatarhud.png differ diff --git a/forge-gui/res/adventure/Shandalar/ui/colorC.png b/forge-gui/res/adventure/Shandalar/ui/colorC.png new file mode 100644 index 00000000000..3122325b2f0 Binary files /dev/null and b/forge-gui/res/adventure/Shandalar/ui/colorC.png differ diff --git a/forge-gui/res/adventure/Shandalar/ui/color_frames.png b/forge-gui/res/adventure/Shandalar/ui/color_frames.png new file mode 100644 index 00000000000..636a66ed7c1 Binary files /dev/null and b/forge-gui/res/adventure/Shandalar/ui/color_frames.png differ diff --git a/forge-gui/res/adventure/Shandalar/ui/inventory.json b/forge-gui/res/adventure/Shandalar/ui/inventory.json index 49f633773b0..27790c85833 100644 --- a/forge-gui/res/adventure/Shandalar/ui/inventory.json +++ b/forge-gui/res/adventure/Shandalar/ui/inventory.json @@ -3,64 +3,65 @@ "height": 270, "yDown": true, "elements": [ - { + { "type": "Image", "image": "ui/title_bg.png", "width": 480, "height": 270 - }, { + }, + { "type": "Image", - "image": "ui/equipment.png", - "x": 8, + "image": "ui/equipment.png", + "x": 8, "y": 8, "width": 129, "height": 243 - }, + }, { "type": "ImageButton", - "name": "Equipment_Neck", - "style": "item_frame", + "name": "Equipment_Neck", + "style": "item_frame", "width": 20, "height": 20, "x": 62, "y": 40 - } , + }, { "type": "ImageButton", - "name": "Equipment_Body", - "style": "item_frame", + "name": "Equipment_Body", + "style": "item_frame", "width": 20, "height": 20, "x": 62, "y": 85 - } , + }, { "type": "ImageButton", - "name": "Equipment_Boots", - "style": "item_frame", + "name": "Equipment_Boots", + "style": "item_frame", "width": 20, "height": 20, "x": 62, "y": 220 - } , + }, { "type": "ImageButton", - "name": "Equipment_Left", - "style": "item_frame", + "name": "Equipment_Left", + "style": "item_frame", "width": 20, "height": 20, "x": 17, "y": 130 - } , + }, { "type": "ImageButton", - "name": "Equipment_Right", - "style": "item_frame", + "name": "Equipment_Right", + "style": "item_frame", "width": 20, "height": 20, "x": 107, "y": 130 - } , + }, { "type": "Scroll", "name": "inventory", @@ -68,22 +69,22 @@ "y": 110, "width": 330, "height": 100 - }, + }, { - "type": "Window", + "type": "Window", "x": 145, "y": 8, "width": 330, "height": 98 - } , + }, { "type": "Label", "name": "item_description", "x": 155, - "y": 8, + "y": 12, "width": 310, - "height": 98 - } , + "height": 94 + }, { "type": "TextButton", "name": "return", @@ -99,17 +100,17 @@ "text": "Equip", "width": 60, "height": 30, - "x": 330, + "x": 320, "y": 222 - } , + }, { "type": "TextButton", "name": "delete", - "text": "Delete", + "text": "Discard", "width": 60, "height": 30, "x": 240, "y": 222 - } + } ] } \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/ui/inventory_portrait.json b/forge-gui/res/adventure/Shandalar/ui/inventory_portrait.json index 6aeab969c15..56109660bde 100644 --- a/forge-gui/res/adventure/Shandalar/ui/inventory_portrait.json +++ b/forge-gui/res/adventure/Shandalar/ui/inventory_portrait.json @@ -87,7 +87,7 @@ { "type": "TextButton", "name": "delete", - "text": "Delete", + "text": "Discard", "width": 80, "height": 30, "x": 8, diff --git a/forge-gui/res/adventure/Shandalar/ui/sprite_markers.png b/forge-gui/res/adventure/Shandalar/ui/sprite_markers.png new file mode 100644 index 00000000000..88d3b758aa4 Binary files /dev/null and b/forge-gui/res/adventure/Shandalar/ui/sprite_markers.png differ diff --git a/forge-gui/res/adventure/Shandalar/ui/statistic.json b/forge-gui/res/adventure/Shandalar/ui/statistic.json index f1894e38e41..ae71365194c 100644 --- a/forge-gui/res/adventure/Shandalar/ui/statistic.json +++ b/forge-gui/res/adventure/Shandalar/ui/statistic.json @@ -16,7 +16,7 @@ "x": 300, "y": 18, "width": 160, - "height": 180 + "height": 200 }, { "type": "Scroll", @@ -29,34 +29,25 @@ { "type": "Image", "name": "avatar", - "x": 320, + "x": 321, "y": 28, "width": 64, "height": 64 }, { "type": "Image", - "name": "avatarBorder", - "image": "ui/avatarhud.png", - "x": 320, - "y": 28, + "name": "colorFrame", + "image": "ui/colorC.png", + "x": 305, + "y": 45, "width": 64, "height": 64 }, - { - "type": "Label", - "name": "playerName", - "x": 330, - "y": 90, - "width": 80, - "height": 24, - "font": "black" - }, { "type": "Label", "name": "totalWins", "x": 410, - "y": 114, + "y": 102, "width": 80, "height": 24, "font": "black" @@ -66,7 +57,7 @@ "name": "wins", "text": "Win:", "x": 330, - "y": 114, + "y": 102, "width": 80, "height": 24, "font": "black" @@ -75,7 +66,7 @@ "type": "Label", "name": "totalLoss", "x": 410, - "y": 134, + "y": 113, "width": 80, "height": 24, "font": "black" @@ -85,7 +76,7 @@ "name": "loss", "text": "Loss:", "x": 330, - "y": 134, + "y": 113, "width": 80, "height": 24, "font": "black" @@ -94,7 +85,7 @@ "type": "Label", "name": "lossWinRatio", "x": 410, - "y": 154, + "y": 125, "width": 80, "height": 24, "font": "black" @@ -104,11 +95,20 @@ "name": "winloss", "text": "Win Loss Ratio:", "x": 330, - "y": 154, + "y": 125, "width": 80, "height": 24, "font": "black" }, + { + "type": "Scroll", + "name": "blessingInfo", + "style": "nobg", + "x": 308, + "y": 143, + "width": 144, + "height": 72 + }, { "type": "TextButton", "name": "return", @@ -116,13 +116,13 @@ "width": 100, "height": 30, "x": 335, - "y": 212 + "y": 224 }, { "type": "Image", "name": "lifeIcon", "image": "ui/life.png", - "x": 400, + "x": 392, "y": 40, "width": 16, "height": 16 @@ -131,18 +131,27 @@ "type": "Image", "name": "goldIcon", "image": "ui/money.png", - "x": 400, + "x": 392, "y": 60, "width": 16, "height": 16 }, + { + "type": "Label", + "name": "playerName", + "x": 394, + "y": 20, + "width": 80, + "height": 24, + "font": "black" + }, { "type": "Label", "name": "lifePoints", "font": "black", "width": 64, "height": 16, - "x": 420, + "x": 410, "y": 40 }, { @@ -151,7 +160,7 @@ "font": "black", "width": 64, "height": 16, - "x": 420, + "x": 410, "y": 60 }, { diff --git a/forge-gui/res/adventure/Shandalar/ui/statistic_portrait.json b/forge-gui/res/adventure/Shandalar/ui/statistic_portrait.json index 09a737bebe0..5ca37dab220 100644 --- a/forge-gui/res/adventure/Shandalar/ui/statistic_portrait.json +++ b/forge-gui/res/adventure/Shandalar/ui/statistic_portrait.json @@ -16,15 +16,15 @@ "x": 4, "y": 4, "width": 262, - "height": 90 + "height": 98 }, { "type": "Scroll", "name": "enemies", "x": 4, - "y": 98, + "y": 106, "width": 262, - "height": 335 + "height": 327 }, { "type": "Image", @@ -36,28 +36,19 @@ }, { "type": "Image", - "name": "avatarBorder", - "image": "ui/avatarhud.png", - "x": 24, - "y": 8, + "name": "colorFrame", + "image": "ui/colorC.png", + "x": 8, + "y": 25, "width": 64, "height": 64 }, - { - "type": "Label", - "name": "playerName", - "x": 34, - "y": 70, - "width": 80, - "height": 24, - "font": "black" - }, { "type": "Label", "name": "totalWins", - "x": 234, - "y": 14, - "width": 40, + "x": 144, + "y": 56, + "width": 26, "height": 24, "font": "black" }, @@ -65,8 +56,8 @@ "type": "Label", "name": "wins", "text": "Win:", - "x": 170, - "y": 14, + "x": 98, + "y": 56, "width": 60, "height": 24, "font": "black" @@ -74,9 +65,9 @@ { "type": "Label", "name": "totalLoss", - "x": 234, - "y": 34, - "width": 40, + "x": 144, + "y": 68, + "width": 26, "height": 24, "font": "black" }, @@ -84,8 +75,8 @@ "type": "Label", "name": "loss", "text": "Loss:", - "x": 170, - "y": 34, + "x": 98, + "y": 68, "width": 60, "height": 24, "font": "black" @@ -93,9 +84,9 @@ { "type": "Label", "name": "lossWinRatio", - "x": 234, - "y": 54, - "width": 40, + "x": 144, + "y": 80, + "width": 26, "height": 24, "font": "black" }, @@ -103,8 +94,8 @@ "type": "Label", "name": "winloss", "text": "Win Loss Ratio:", - "x": 170, - "y": 54, + "x": 98, + "y": 80, "width": 60, "height": 24, "font": "black" @@ -118,12 +109,21 @@ "x": 5, "y": 440 }, + { + "type": "Label", + "name": "playerName", + "x": 98, + "y": 4, + "width": 80, + "height": 24, + "font": "black" + }, { "type": "Image", "name": "lifeIcon", "image": "ui/life.png", - "x": 104, - "y": 40, + "x": 98, + "y": 22, "width": 16, "height": 16 }, @@ -131,8 +131,8 @@ "type": "Image", "name": "goldIcon", "image": "ui/money.png", - "x": 104, - "y": 60, + "x": 98, + "y": 42, "width": 16, "height": 16 }, @@ -142,8 +142,8 @@ "font": "black", "width": 64, "height": 16, - "x": 124, - "y": 40 + "x": 118, + "y": 22 }, { "type": "Label", @@ -151,8 +151,17 @@ "font": "black", "width": 64, "height": 16, - "x": 124, - "y": 60 + "x": 118, + "y": 42 + }, + { + "type": "Scroll", + "name": "blessingInfo", + "style": "nobg", + "x": 170, + "y": 14, + "width": 86, + "height": 80 }, { "type": "Table", diff --git a/forge-gui/res/adventure/Shandalar/world/enemies.json b/forge-gui/res/adventure/Shandalar/world/enemies.json index 0ad7e9eba39..d89d087227d 100644 --- a/forge-gui/res/adventure/Shandalar/world/enemies.json +++ b/forge-gui/res/adventure/Shandalar/world/enemies.json @@ -2,7 +2,7 @@ { "name": "Adventurer", "sprite": "sprites/swordsman_3.atlas", - "deck": "decks/adventurer.dck", + "deck": "decks/adventurer.dck", "colors": "UW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -25,7 +25,7 @@ { "name": "Amonkhet Minotaur", "sprite": "sprites/warden.atlas", - "deck": "decks/amonkhet_minotaur.dck", + "deck": "decks/amonkhet_minotaur.dck", "colors": "BR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -47,7 +47,7 @@ }, { "name": "Ape", - "sprite": "sprites/behemoth.atlas", + "sprite": "sprites/behemoth.atlas", "colors": "GR", "deck": "decks/ape.json", "spawnRate": 0.2, "difficulty": 0.1, @@ -71,7 +71,7 @@ { "name": "Archer", "sprite": "sprites/archer_2.atlas", - "deck": "decks/human_archer.dck", + "deck": "decks/human_archer.dck", "colors": "GW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -94,7 +94,7 @@ { "name": "Ashmouth Devil", "sprite": "sprites/devil.atlas", - "deck": "decks/ashmouth_devil.dck", + "deck": "decks/ashmouth_devil.dck", "colors": "BR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -117,7 +117,7 @@ { "name": "Axgard Dwarf", "sprite": "sprites/dwarf_8.atlas", - "deck": "decks/axgard_dwarf.dck", + "deck": "decks/axgard_dwarf.dck", "colors": "RW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 22, @@ -139,7 +139,7 @@ }, { "name": "Bandit", - "sprite": "sprites/dwarf_7.atlas", + "sprite": "sprites/dwarf_7.atlas", "colors": "BR", "deck": "decks/bandit.dck", "spawnRate": 0.2, "difficulty": 0.1, @@ -162,7 +162,7 @@ }, { "name": "Bear", - "sprite": "sprites/bear.atlas", + "sprite": "sprites/bear.atlas", "colors": "G", "deck": "decks/bear.json", "spawnRate": 0.2, "difficulty": 0.1, @@ -186,7 +186,7 @@ { "name": "Beholder", "sprite": "sprites/beholder.atlas", - "deck": "decks/beholder.dck", + "deck": "decks/beholder.dck", "colors": "BRU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -209,7 +209,7 @@ { "name": "Berserker", "sprite": "sprites/dwarf_5.atlas", - "deck": "decks/berserker.json", + "deck": "decks/berserker.json", "colors": "BGR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 22, @@ -232,7 +232,7 @@ { "name": "Big Zombie", "sprite": "sprites/zombie_2.atlas", - "deck": "decks/zombie_bad.json", + "deck": "decks/zombie_bad.json", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 15, @@ -266,7 +266,7 @@ { "name": "Bird", "sprite": "sprites/griffin_2.atlas", - "deck": "decks/bird_blue.json", + "deck": "decks/bird_blue.json", "colors": "U", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -289,7 +289,7 @@ { "name": "Black Wiz1", "sprite": "sprites/black_wizard.atlas", - "deck": "decks/black_bad.json", + "deck": "decks/black_bad.json", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -312,7 +312,7 @@ { "name": "Black Wiz2", "sprite": "sprites/black_wiz2.atlas", - "deck": "decks/fear.dck", + "deck": "decks/fear.dck", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -335,7 +335,7 @@ { "name": "Black Wiz3", "sprite": "sprites/black_wiz3.atlas", - "deck": "decks/black_wiz3.dck", + "deck": "decks/black_wiz3.dck", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -358,7 +358,7 @@ { "name": "Blue Wiz1", "sprite": "sprites/mage.atlas", - "deck": "decks/blue_bad.json", + "deck": "decks/blue_bad.json", "colors": "U", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -381,7 +381,7 @@ { "name": "Blue Wiz2", "sprite": "sprites/blue_wiz2.atlas", - "deck": "decks/mill.dck", + "deck": "decks/mill.dck", "colors": "U", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -404,7 +404,7 @@ { "name": "Blue Wiz3", "sprite": "sprites/mage_2.atlas", - "deck": "decks/counter.dck", + "deck": "decks/counter.dck", "colors": "U", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -427,7 +427,7 @@ { "name": "Boggart", "sprite": "sprites/goblin_2.atlas", - "deck": "decks/eyeblight.dck", + "deck": "decks/eyeblight.dck", "colors": "GR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 27, @@ -461,7 +461,7 @@ { "name": "Cat", "sprite": "sprites/lion.atlas", - "deck": "decks/cat.json", + "deck": "decks/cat.json", "colors": "GW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 27, @@ -484,7 +484,7 @@ { "name": "Cathar", "sprite": "sprites/cathar.atlas", - "deck": "decks/cathar.dck", + "deck": "decks/cathar.dck", "colors": "GW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -507,7 +507,7 @@ { "name": "Centaur", "sprite": "sprites/centaur.atlas", - "deck": "decks/centaur.json", + "deck": "decks/centaur.json", "colors": "GW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 30, @@ -530,7 +530,7 @@ { "name": "Centaur Warrior", "sprite": "sprites/centaur_2.atlas", - "deck": "decks/centaur_warrior.dck", + "deck": "decks/centaur_warrior.dck", "colors": "GW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 30, @@ -553,7 +553,7 @@ { "name": "ClayGolem", "sprite": "sprites/golem_2.atlas", - "deck": "decks/golem_good.json", + "deck": "decks/golem_good.json", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 19, @@ -585,7 +585,7 @@ { "name": "Cleric", "sprite": "sprites/cleric.atlas", - "deck": "decks/cleric.json", + "deck": "decks/cleric.json", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -608,7 +608,7 @@ { "name": "Construct", "sprite": "sprites/golem_3.atlas", - "deck": "decks/artificer.dck", + "deck": "decks/artificer.dck", "colors": "RU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 21, @@ -631,7 +631,7 @@ { "name": "Cyclops", "sprite": "sprites/cyclops.atlas", - "deck": "decks/cyclops.dck", + "deck": "decks/cyclops.dck", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 16, @@ -654,7 +654,7 @@ { "name": "Dark Knight", "sprite": "sprites/death_knight.atlas", - "deck": "decks/death_knight.json", + "deck": "decks/death_knight.json", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 30, @@ -677,7 +677,7 @@ { "name": "Dawnhart Witch", "sprite": "sprites/dawnhart_witch.atlas", - "deck": "decks/dawnhart_witch.dck", + "deck": "decks/dawnhart_witch.dck", "colors": "GW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -700,7 +700,7 @@ { "name": "Death Knight", "sprite": "sprites/death_knight_2.atlas", - "deck": "decks/death_knight.dck", + "deck": "decks/death_knight.dck", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 30, @@ -723,7 +723,7 @@ { "name": "Demon", "sprite": "sprites/demon_3.atlas", - "deck": "decks/demon.json", + "deck": "decks/demon.json", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -746,7 +746,7 @@ { "name": "Devil", "sprite": "sprites/imp.atlas", - "deck": "decks/devil.json", + "deck": "decks/devil.json", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -769,7 +769,7 @@ { "name": "Dino", "sprite": "sprites/ancient.atlas", - "deck": "decks/dinosaurs.json", + "deck": "decks/dinosaurs.json", "colors": "GRW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 15, @@ -805,7 +805,7 @@ { "name": "Dinosaur", "sprite": "sprites/ancient_2.atlas", - "deck": "decks/dinosaur_w_r.dck", + "deck": "decks/dinosaur_w_r.dck", "colors": "RW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 15, @@ -841,7 +841,7 @@ { "name": "Djinn", "sprite": "sprites/djinn.atlas", - "deck": "decks/djinn.json", + "deck": "decks/djinn.json", "colors": "RU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 32, @@ -864,7 +864,7 @@ { "name": "Dragon", "sprite": "sprites/dragon.atlas", - "deck": "decks/dragon.dck", + "deck": "decks/dragon.dck", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -887,7 +887,7 @@ { "name": "Dwarf", "sprite": "sprites/dwarf_2.atlas", - "deck": "decks/dwarf.json", + "deck": "decks/dwarf.json", "colors": "RW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 22, @@ -909,7 +909,7 @@ }, { "name": "Efreet", - "sprite": "sprites/efreet_2.atlas", + "sprite": "sprites/efreet_2.atlas", "colors": "RU", "deck": "decks/efreet.dck", "spawnRate": 0.2, "difficulty": 0.1, @@ -933,7 +933,7 @@ { "name": "Eldraine Faerie", "sprite": "sprites/pixie.atlas", - "deck": "decks/eldraine_faerie.dck", + "deck": "decks/eldraine_faerie.dck", "colors": "GU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -956,7 +956,7 @@ { "name": "Eldraine Knight", "sprite": "sprites/paladin_2.atlas", - "deck": "decks/eldraine_knight.dck", + "deck": "decks/eldraine_knight.dck", "colors": "RW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 30, @@ -979,7 +979,7 @@ { "name": "Eldrazi", "sprite": "sprites/mindelemental.atlas", - "deck": "decks/eldrazi.json", + "deck": "decks/eldrazi.json", "colors": "BGU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 15, @@ -1002,7 +1002,7 @@ { "name": "Elemental", "sprite": "sprites/crystalelemental.atlas", - "deck": "decks/elemental_blue.json", + "deck": "decks/elemental_blue.json", "colors": "U", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -1025,7 +1025,7 @@ { "name": "Elf", "sprite": "sprites/druid.atlas", - "deck": "decks/elf_bad.json", + "deck": "decks/elf_bad.json", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -1059,7 +1059,7 @@ { "name": "Elf warrior", "sprite": "sprites/hunter.atlas", - "deck": "decks/elf_mid.json", + "deck": "decks/elf_mid.json", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -1093,7 +1093,7 @@ { "name": "Elk", "sprite": "sprites/deer_2.atlas", - "deck": "decks/elk.dck", + "deck": "decks/elk.dck", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 29, @@ -1116,7 +1116,7 @@ { "name": "Faerie", "sprite": "sprites/pixie_2.atlas", - "deck": "decks/faerie.json", + "deck": "decks/faerie.json", "colors": "BGU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -1139,7 +1139,7 @@ { "name": "Fire Elemental", "sprite": "sprites/fireelemental.atlas", - "deck": "decks/fire_elemental.dck", + "deck": "decks/fire_elemental.dck", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -1162,7 +1162,7 @@ { "name": "Flame Elemental", "sprite": "sprites/magmaelemental.atlas", - "deck": "decks/flame_elemental.dck", + "deck": "decks/flame_elemental.dck", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 23, @@ -1185,7 +1185,7 @@ { "name": "Gargoyle", "sprite": "sprites/gargoyle.atlas", - "deck": "decks/gargoyle.json", + "deck": "decks/gargoyle.json", "colors": "RUW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -1208,7 +1208,7 @@ { "name": "Gargoyle 2", "sprite": "sprites/gargoyle_2.atlas", - "deck": "decks/gargoyle.dck", + "deck": "decks/gargoyle.dck", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -1231,7 +1231,7 @@ { "name": "Geist", "sprite": "sprites/ghost.atlas", - "deck": "decks/ghost_blue.dck", + "deck": "decks/ghost_blue.dck", "colors": "U", "spawnRate": 0.2, "difficulty": 0.1, "speed": 32, @@ -1254,7 +1254,7 @@ { "name": "Ghoul", "sprite": "sprites/ghoul.atlas", - "deck": "decks/ghoul.dck", + "deck": "decks/ghoul.dck", "colors": "BU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 15, @@ -1277,7 +1277,7 @@ { "name": "Ghost", "sprite": "sprites/ghost_2.atlas", - "deck": "decks/ghost.json", + "deck": "decks/ghost.json", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -1300,7 +1300,7 @@ { "name": "Giant Spider", "sprite": "sprites/spider_2.atlas", - "deck": "decks/spider_token.dck", + "deck": "decks/spider_token.dck", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 23, @@ -1323,7 +1323,7 @@ { "name": "Goblin", "sprite": "sprites/goblin.atlas", - "deck": "decks/goblin_bad.json", + "deck": "decks/goblin_bad.json", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 27, @@ -1365,7 +1365,7 @@ { "name": "Goblin Chief", "sprite": "sprites/wolf_rider_2.atlas", - "deck": "decks/goblin_good.json", + "deck": "decks/goblin_good.json", "colors": "BR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 29, @@ -1399,7 +1399,7 @@ { "name": "Goblin Warrior", "sprite": "sprites/wolf_rider.atlas", - "deck": "decks/goblin_mid.json", + "deck": "decks/goblin_mid.json", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 28, @@ -1433,7 +1433,7 @@ { "name": "Golem", "sprite": "sprites/golem.atlas", - "deck": "decks/golem.json", + "deck": "decks/golem.json", "colors": "GW", "spawnRate": 0.1, "difficulty": 0.1, "speed": 20, @@ -1471,7 +1471,7 @@ { "name": "Golem that is Generous", "sprite": "sprites/golem.atlas", - "deck": "decks/golem.json", + "deck": "decks/golem.json", "colors": "GW", "spawnRate": 0.1, "difficulty": 0.1, "speed": 20, @@ -1521,7 +1521,7 @@ { "name": "Gorgon", "sprite": "sprites/gorgone.atlas", - "deck": "decks/gorgon.dck", + "deck": "decks/gorgon.dck", "colors": "BG", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -1544,7 +1544,7 @@ { "name": "Gorgon 2", "sprite": "sprites/gorgonen.atlas", - "deck": "decks/gorgon_2.dck", + "deck": "decks/gorgon_2.dck", "colors": "BG", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -1567,7 +1567,7 @@ { "name": "Green Beast", "sprite": "sprites/basilisk.atlas", - "deck": "decks/beast_green.json", + "deck": "decks/beast_green.json", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 22, @@ -1590,7 +1590,7 @@ { "name": "Green Wiz1", "sprite": "sprites/green_wiz1.atlas", - "deck": "decks/green_bad.json", + "deck": "decks/green_bad.json", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -1613,7 +1613,7 @@ { "name": "Green Wiz2", "sprite": "sprites/green_wiz2.atlas", - "deck": "decks/trample.dck", + "deck": "decks/trample.dck", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -1636,7 +1636,7 @@ { "name": "Green Wiz3", "sprite": "sprites/green_wiz3.atlas", - "deck": "decks/ramp.dck", + "deck": "decks/ramp.dck", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -1659,7 +1659,7 @@ { "name": "Griffin", "sprite": "sprites/griffin.atlas", - "deck": "decks/griffin.json", + "deck": "decks/griffin.json", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 32, @@ -1682,7 +1682,7 @@ { "name": "Harpy", "sprite": "sprites/harpy.atlas", - "deck": "decks/harpy.dck", + "deck": "decks/harpy.dck", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -1705,7 +1705,7 @@ { "name": "Harpy 2", "sprite": "sprites/harpy_2.atlas", - "deck": "decks/harpy_2.dck", + "deck": "decks/harpy_2.dck", "colors": "BU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -1728,7 +1728,7 @@ { "name": "Hellhound", "sprite": "sprites/hellhound_2.atlas", - "deck": "decks/hellhound.dck", + "deck": "decks/hellhound.dck", "colors": "BR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -1751,7 +1751,7 @@ { "name": "High Elf", "sprite": "sprites/druid_2.atlas", - "deck": "decks/elf_good.json", + "deck": "decks/elf_good.json", "colors": "BG", "spawnRate": 0.2, "difficulty": 0.1, "speed": 26, @@ -1785,7 +1785,7 @@ { "name": "High Vampire", "sprite": "sprites/vampire_2.atlas", - "deck": "decks/vampire.json", + "deck": "decks/vampire.json", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 32, @@ -1808,7 +1808,7 @@ { "name": "Horseman", "sprite": "sprites/cavalier_2.atlas", - "deck": "decks/horsemanship.dck", + "deck": "decks/horsemanship.dck", "colors": "UW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 30, @@ -1842,7 +1842,7 @@ { "name": "Human", "sprite": "sprites/pikeman.atlas", - "deck": "decks/human_bad.json", + "deck": "decks/human_bad.json", "colors": "BRW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 23, @@ -1876,7 +1876,7 @@ { "name": "Human elite", "sprite": "sprites/legionite.atlas", - "deck": "decks/human_good.json", + "deck": "decks/human_good.json", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -1910,7 +1910,7 @@ { "name": "Human guard", "sprite": "sprites/swordsman.atlas", - "deck": "decks/human_mid.json", + "deck": "decks/human_mid.json", "colors": "BW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -1944,7 +1944,7 @@ { "name": "Hydra", "sprite": "sprites/hydra.atlas", - "deck": "decks/hydra.json", + "deck": "decks/hydra.json", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 15, @@ -1978,7 +1978,7 @@ { "name": "Immersturm Demon", "sprite": "sprites/devil_2.atlas", - "deck": "decks/immersturm_demon.dck", + "deck": "decks/immersturm_demon.dck", "colors": "BR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -2001,7 +2001,7 @@ { "name": "Khan", "sprite": "sprites/cavalier.atlas", - "deck": "decks/mardu.dck", + "deck": "decks/mardu.dck", "colors": "BRW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 30, @@ -2024,7 +2024,7 @@ { "name": "Knight", "sprite": "sprites/paladin.atlas", - "deck": "decks/knight.json", + "deck": "decks/knight.json", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 30, @@ -2058,7 +2058,7 @@ { "name": "Lich", "sprite": "sprites/lich_2.atlas", - "deck": "decks/lich.dck", + "deck": "decks/lich.dck", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 20, @@ -2081,7 +2081,7 @@ { "name": "Merfolk", "sprite": "sprites/waterelemental.atlas", - "deck": "decks/merfolk_bad.json", + "deck": "decks/merfolk_bad.json", "colors": "U", "spawnRate": 0.2, "difficulty": 0.1, "speed": 23, @@ -2115,7 +2115,7 @@ { "name": "Merfolk Avatar", "sprite": "sprites/iceelemental.atlas", - "deck": "decks/merfolk_good.json", + "deck": "decks/merfolk_good.json", "colors": "GU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -2149,7 +2149,7 @@ { "name": "Merfolk Fighter", "sprite": "sprites/merfolk.atlas", - "deck": "decks/merfolk_lords.dck", + "deck": "decks/merfolk_lords.dck", "colors": "GU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 22, @@ -2183,7 +2183,7 @@ { "name": "Merfolk Lord", "sprite": "sprites/merfolk_lord.atlas", - "deck": "decks/merfolk_lord2.dck", + "deck": "decks/merfolk_lord2.dck", "colors": "GU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -2206,7 +2206,7 @@ { "name": "Merfolk Soldier", "sprite": "sprites/mermaid.atlas", - "deck": "decks/merfolk_v_goblins.dck", + "deck": "decks/merfolk_v_goblins.dck", "colors": "U", "spawnRate": 0.2, "difficulty": 0.1, "speed": 22, @@ -2240,7 +2240,7 @@ { "name": "Merfolk warrior", "sprite": "sprites/airelemental.atlas", - "deck": "decks/merfolk_mid.json", + "deck": "decks/merfolk_mid.json", "colors": "U", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2274,7 +2274,7 @@ { "name": "Mimic", "sprite": "sprites/mimic.atlas", - "deck": "decks/mimic.dck", + "deck": "decks/mimic.dck", "colors": "BU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 15, @@ -2297,7 +2297,7 @@ { "name": "Minotaur", "sprite": "sprites/minotaur.atlas", - "deck": "decks/minotaur.json", + "deck": "decks/minotaur.json", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -2320,7 +2320,7 @@ { "name": "Minotaur Flayer", "sprite": "sprites/warden_2.atlas", - "deck": "decks/minotaur.dck", + "deck": "decks/minotaur.dck", "colors": "BR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -2343,7 +2343,7 @@ { "name": "Monk", "sprite": "sprites/monk.atlas", - "deck": "decks/angel.json", + "deck": "decks/angel.json", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2366,7 +2366,7 @@ { "name": "Rakdos Devil", "sprite": "sprites/juggler.atlas", - "deck": "decks/rakdos_devil.dck", + "deck": "decks/rakdos_devil.dck", "colors": "BR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2389,7 +2389,7 @@ { "name": "Red Beast", "sprite": "sprites/basilisk_2.atlas", - "deck": "decks/beast_red.json", + "deck": "decks/beast_red.json", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 23, @@ -2412,7 +2412,7 @@ { "name": "Red Wiz1", "sprite": "sprites/enchanter.atlas", - "deck": "decks/red_bad.json", + "deck": "decks/red_bad.json", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2435,7 +2435,7 @@ { "name": "Red Wiz2", "sprite": "sprites/red_wiz2.atlas", - "deck": "decks/haste_burn.dck", + "deck": "decks/haste_burn.dck", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2458,7 +2458,7 @@ { "name": "Red Wiz3", "sprite": "sprites/red_wiz3.atlas", - "deck": "decks/lava_axe.dck", + "deck": "decks/lava_axe.dck", "colors": "R", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2481,7 +2481,7 @@ { "name": "Rogue", "sprite": "sprites/rogue.atlas", - "deck": "decks/rogue.json", + "deck": "decks/rogue.json", "colors": "BU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -2504,7 +2504,7 @@ { "name": "Satyr", "sprite": "sprites/satyr.atlas", - "deck": "decks/satyr.dck", + "deck": "decks/satyr.dck", "colors": "GR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -2527,7 +2527,7 @@ { "name": "Sea Monster", "sprite": "sprites/leech_2.atlas", - "deck": "decks/sea_monster.dck", + "deck": "decks/sea_monster.dck", "colors": "U", "spawnRate": 0.2, "difficulty": 0.1, "speed": 15, @@ -2550,7 +2550,7 @@ { "name": "Shaman", "sprite": "sprites/shaman_2.atlas", - "deck": "decks/shaman.json", + "deck": "decks/shaman.json", "colors": "GR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2573,7 +2573,7 @@ { "name": "Skeleton", "sprite": "sprites/skeleton.atlas", - "deck": "decks/skeleton.dck", + "deck": "decks/skeleton.dck", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 20, @@ -2595,7 +2595,7 @@ { "name": "Skeleton Soldier", "sprite": "sprites/skeleton_2.atlas", - "deck": "decks/skeleton_2.dck", + "deck": "decks/skeleton_2.dck", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 20, @@ -2617,7 +2617,7 @@ { "name": "Sliver", "sprite": "sprites/sliver.atlas", - "deck": "decks/sliver.json", + "deck": "decks/sliver.json", "colors": "GRW", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2639,7 +2639,7 @@ { "name": "Snake", "sprite": "sprites/big_snake.atlas", - "deck": "decks/snake.json", + "deck": "decks/snake.json", "colors": "GU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -2662,7 +2662,7 @@ { "name": "Spider", "sprite": "sprites/spider.atlas", - "deck": "decks/spider.json", + "deck": "decks/spider.json", "colors": "BG", "spawnRate": 0.2, "difficulty": 0.1, "speed": 22, @@ -2685,7 +2685,7 @@ { "name": "Tarkir Djinn", "sprite": "sprites/djinn_2.atlas", - "deck": "decks/djinn_tarkir.dck", + "deck": "decks/djinn_tarkir.dck", "colors": "RU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -2708,7 +2708,7 @@ { "name": "Treefolk", "sprite": "sprites/treant.atlas", - "deck": "decks/treefolk.json", + "deck": "decks/treefolk.json", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 16, @@ -2731,7 +2731,7 @@ { "name": "Treefolk Guardian", "sprite": "sprites/treant_2.atlas", - "deck": "decks/treefolk.dck", + "deck": "decks/treefolk.dck", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "speed": 16, @@ -2754,7 +2754,7 @@ { "name": "Troll", "sprite": "sprites/troll.atlas", - "deck": "decks/troll.json", + "deck": "decks/troll.json", "colors": "GR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -2777,7 +2777,7 @@ { "name": "Vampire", "sprite": "sprites/vampire.atlas", - "deck": "decks/vampire.dck", + "deck": "decks/vampire.dck", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -2793,7 +2793,7 @@ { "name": "Vampire Lord", "sprite": "sprites/vampire_3.atlas", - "deck": "decks/vampire_blood_token_fly.dck", + "deck": "decks/vampire_blood_token_fly.dck", "colors": "BR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 31, @@ -2809,7 +2809,7 @@ { "name": "Viashino", "sprite": "sprites/battler.atlas", - "deck": "decks/viashino.dck", + "deck": "decks/viashino.dck", "colors": "BGR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -2832,7 +2832,7 @@ { "name": "Viper", "sprite": "sprites/big_snake_2.atlas", - "deck": "decks/snake.dck", + "deck": "decks/snake.dck", "colors": "BG", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -2855,7 +2855,7 @@ { "name": "Werewolf", "sprite": "sprites/hellhound.atlas", - "deck": "decks/werewolf.dck", + "deck": "decks/werewolf.dck", "colors": "GR", "spawnRate": 0.2, "difficulty": 0.1, "speed": 26, @@ -2877,7 +2877,7 @@ { "name": "White Dwarf", "sprite": "sprites/dwarf_6.atlas", - "deck": "decks/white_dwarf.dck", + "deck": "decks/white_dwarf.dck", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 22, @@ -2900,7 +2900,7 @@ { "name": "White Wiz1", "sprite": "sprites/priest.atlas", - "deck": "decks/white_bad.json", + "deck": "decks/white_bad.json", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2923,7 +2923,7 @@ { "name": "White Wiz2", "sprite": "sprites/white_wiz2.atlas", - "deck": "decks/basri.dck", + "deck": "decks/basri.dck", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2946,7 +2946,7 @@ { "name": "White Wiz3", "sprite": "sprites/white_wiz3.atlas", - "deck": "decks/human_soldier_token.dck", + "deck": "decks/human_soldier_token.dck", "colors": "W", "spawnRate": 0.2, "difficulty": 0.1, "speed": 24, @@ -2969,7 +2969,7 @@ { "name": "Wurm", "sprite": "sprites/leech.atlas", - "deck": "decks/wurm.json", + "deck": "decks/wurm.json", "colors": "G", "spawnRate": 0.2, "difficulty": 0.1, "ai": "reckless", @@ -3004,7 +3004,7 @@ { "name": "Yeti", "sprite": "sprites/yeti_2.atlas", - "deck": "decks/yeti.dck", + "deck": "decks/yeti.dck", "colors": "GRU", "spawnRate": 0.2, "difficulty": 0.1, "speed": 25, @@ -3027,7 +3027,7 @@ { "name": "Zombie", "sprite": "sprites/zombie.atlas", - "deck": "decks/zombie_bad.json", + "deck": "decks/zombie_bad.json", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 15, @@ -3061,7 +3061,7 @@ { "name": "Zombie Lord", "sprite": "sprites/lich.atlas", - "deck": "decks/zombie_good.json", + "deck": "decks/zombie_good.json", "colors": "B", "spawnRate": 0.2, "difficulty": 0.1, "speed": 21, @@ -3095,7 +3095,7 @@ { "name": "Sliver Queen", "sprite": "sprites/boss/sliver_queen.atlas", - "deck": "decks/boss/sliver_queen.dck", + "deck": "decks/boss/sliver_queen.dck", "colors": "BGRUW", "speed": 1, "life": 50, "rewards": [ @@ -3119,7 +3119,7 @@ { "name": "Griselbrand", "sprite": "sprites/boss/griselbrand.atlas", - "deck": "decks/boss/griselbrand.dck", + "deck": "decks/boss/griselbrand.dck", "colors": "B", "speed": 1, "life": 40, "rewards": [ @@ -3143,7 +3143,7 @@ { "name": "Akroma", "sprite": "sprites/boss/akroma.atlas", - "deck": "decks/boss/akroma.dck", + "deck": "decks/boss/akroma.dck", "colors": "W", "speed": 1, "life": 80, "rewards": [ @@ -3167,7 +3167,7 @@ { "name": "Emrakul", "sprite": "sprites/boss/emrakul.atlas", - "deck": "decks/boss/emrakul.dck", + "deck": "decks/boss/emrakul.dck", "colors": "C", "speed": 1, "life": 40, "rewards": [ @@ -3185,7 +3185,7 @@ { "name": "Ghalta", "sprite": "sprites/boss/ghalta.atlas", - "deck": "decks/boss/ghalta.dck", + "deck": "decks/boss/ghalta.dck", "colors": "G", "speed": 1, "life": 80, "rewards": [ @@ -3209,7 +3209,7 @@ { "name": "Lorthos", "sprite": "sprites/boss/lorthos.atlas", - "deck": "decks/boss/lorthos.dck", + "deck": "decks/boss/lorthos.dck", "colors": "U", "speed": 1, "life": 80, "rewards": [ @@ -3233,7 +3233,7 @@ { "name": "Lathliss", "sprite": "sprites/boss/lathiss.atlas", - "deck": "decks/boss/lathliss.dck", + "deck": "decks/boss/lathliss.dck", "colors": "R", "speed": 1, "life": 80, "rewards": [ diff --git a/forge-gui/res/adventure/Shandalar/world/items.json b/forge-gui/res/adventure/Shandalar/world/items.json index 9e2c5c04708..10e260dd25c 100644 --- a/forge-gui/res/adventure/Shandalar/world/items.json +++ b/forge-gui/res/adventure/Shandalar/world/items.json @@ -587,6 +587,14 @@ ] } }, + { + "name": "Manasight Amulet", + "equipmentSlot": "Neck", + "iconName": "RelicAmulet", + "effect": { + "colorView": true + } + }, { "name": "Amulet of Kroog", "equipmentSlot": "Neck",