Merge pull request #122 from magpie514/master

Big map update
This commit is contained in:
Anthony Calosa
2022-04-23 12:54:47 +08:00
committed by GitHub
45 changed files with 1256 additions and 548 deletions

View File

@@ -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;
}
}

View File

@@ -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<Reward> getRewards() {
Array<Reward> ret=new Array<Reward>();
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);
}
}
}

View File

@@ -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() {

View File

@@ -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);
}
}

View File

@@ -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 { <flagID>, <comparison>, <value> }
public boolean not = false; //Reverse the result of a condition ("actorID":"XX" + "not":true => true if XX is not in the map.)
}
}

View File

@@ -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;
}
}

View File

@@ -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<rewards.length;i++)
} else {
rewards = new RewardData[enemyData.rewards.length];
for(int i=0; i<rewards.length; i++)
rewards[i]=new RewardData(enemyData.rewards[i]);
}
}

View File

@@ -51,9 +51,7 @@ public class WorldData implements Serializable {
if (allEnemies == null) {
Json json = new Json();
FileHandle handle = Config.instance().getFile(Paths.ENEMIES);
if (handle.exists())
{
if (handle.exists()) {
Array readList = json.fromJson(Array.class, EnemyData.class, handle);
allEnemies = readList;
}
@@ -62,8 +60,7 @@ public class WorldData implements Serializable {
}
public static EnemyData getEnemy(String enemy) {
for(EnemyData data: new Array.ArrayIterator<>(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;
}
}

View File

@@ -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<String, Byte> 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<String> inventoryItems=new Array<>();
private final HashMap<String,String> equippedItems=new HashMap<>();
public AdventurePlayer()
{
for(int i=0;i<NUMBER_OF_DECKS;i++)
{
public AdventurePlayer() {
for(int i=0;i<NUMBER_OF_DECKS;i++) {
decks[i]=new Deck("Empty Deck");
}
}
@@ -63,7 +61,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
private final CardPool cards=new CardPool();
private final ItemPool<InventoryItem> 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.length;i++)
{
for(int i=0;i<slots.length;i++) {
equippedItems.put(slots[i],items[i]);
}
}
@@ -186,10 +215,18 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
if(data.containsKey("sideBoardCards"))
deck.getOrCreate(DeckSection.Sideboard).addAll(CardPool.fromCardList(Lists.newArrayList((String[])data.readObject("sideBoardCards"))));
for(int i=0;i<NUMBER_OF_DECKS;i++)
{
if(!data.containsKey("deck_name_"+i))
{
questFlags.clear();
if(data.containsKey("questFlagsKey") && data.containsKey("questFlagsValue")){
String[] keys = (String[]) data.readObject("questFlagsKey");
Byte[] values = (Byte[]) data.readObject("questFlagsValue");
assert( keys.length == values.length );
for( int i = 0; i < keys.length; i++){
questFlags.put(keys[i], values[i]);
}
}
for(int i=0;i<NUMBER_OF_DECKS;i++) {
if(!data.containsKey("deck_name_"+i)) {
if(i==0)
decks[i]=deck;
else
@@ -231,13 +268,14 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
data.store("avatarIndex",avatarIndex);
data.store("heroRace",heroRace);
data.store("isFemale",isFemale);
data.store("colorIdentity", getColorIdentity());
data.store("gold",gold);
data.store("life",life);
data.store("maxLife",maxLife);
data.store("deckName",deck.getName());
data.storeObject("inventory",inventoryItems.toArray(String.class));
data.storeObject("blessing", blessing);
ArrayList<String> slots=new ArrayList<>();
ArrayList<String> 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<String> questFlagsKey = new ArrayList<>();
ArrayList<Byte> questFlagsValue = new ArrayList<>();
for(Map.Entry<String, Byte> 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();
}
}

View File

@@ -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<GameType> appliedVariants = new HashSet<>();
appliedVariants.add(GameType.Constructed);
AdventurePlayer advPlayer = Current.player();
List<RegisteredPlayer> 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<EffectData> playerEffects = new Array<>();
Array<EffectData> 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);
}

View File

@@ -24,7 +24,7 @@ public class InnScene extends UIScene {
}
public void heal() {
Current.player().heal();
Current.player().fullHeal();
}
@Override

View File

@@ -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<Actor> children = ui.getChildren();
for (int i = 0, n = children.size; i < n; i++)
Array<Actor> 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<Current.player().getItems().size;i++)
{
for(int i=0;i<Current.player().getItems().size;i++) {
if(i%columns==0)
inventory.row();
Button newActor=createInventorySlot();
inventory.add(newActor).align(Align.left|Align.top).space(1);
inventory.add(newActor).top().left().space(1);
inventoryButtons.add(newActor);
ItemData item=ItemData.getItem(Current.player().getItems().get(i));
if(item==null)

View File

@@ -1,6 +1,9 @@
package forge.adventure.scene;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
@@ -14,6 +17,7 @@ import forge.adventure.data.EnemyData;
import forge.adventure.data.WorldData;
import forge.adventure.player.AdventurePlayer;
import forge.adventure.stage.GameHUD;
import forge.adventure.util.Config;
import forge.adventure.util.Controls;
import forge.adventure.util.Current;
import forge.adventure.world.WorldSave;
@@ -24,13 +28,16 @@ import java.util.Map;
public class PlayerStatisticScene extends UIScene {
Image avatar, avatarBorder, lifeIcon, goldIcon;
Image colorFrame;
Label money, life;
Label wins, totalWins;
Label loss, totalLoss;
Label winloss, lossWinRatio;
Label playerName;
TextButton back;
Texture colorFrames;
private Table enemiesGroup;
Label blessingScroll;
public PlayerStatisticScene() {
super(Forge.isLandscapeMode() ? "ui/statistic.json" : "ui/statistic_portrait.json");
@@ -39,6 +46,7 @@ public class PlayerStatisticScene extends UIScene {
@Override
public void dispose() {
colorFrames.dispose(); //Get rid of the cached color ID texture.
}
@@ -55,6 +63,20 @@ public class PlayerStatisticScene extends UIScene {
Forge.switchToLast();
return true;
}
private TextureRegion getColorFrame(String C){
int x, y;
switch(C){
case "B": { x = 0 ; y = 0 ; break; }
case "G": { x = 64; y = 0 ; break; }
case "R": { x = 0 ; y = 32; break; }
case "U": { x = 32; y = 32; break; }
case "W": { x = 64; y = 32; break; }
default:
case "C": { x = 32; y = 0 ; break; }
}
TextureRegion result = new TextureRegion(colorFrames, x, y, 32, 32);
return result;
}
@Override
public void enter() {
@@ -99,6 +121,16 @@ public class PlayerStatisticScene extends UIScene {
if (lossWinRatio != null) {
lossWinRatio.setText(Float.toString(Current.player().getStatistic().winLossRatio()));
}
if(colorFrame != null){
colorFrame.setDrawable(new TextureRegionDrawable(getColorFrame(Current.player().getColorIdentity())));
}
if(blessingScroll != null){
if(Current.player().getBlessing() != null) {
blessingScroll.setText(Current.player().getBlessing().getDescription());
} else {
blessingScroll.setText("No blessing.");
}
}
for (Map.Entry<String, Pair<Integer, Integer>> 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() {
}
}

View File

@@ -66,7 +66,7 @@ public class RewardScene extends UIScene {
}
}
if (wait) {
flipCountDown = 3.0f;
flipCountDown = 1.5f;
doneClicked = true;
} else {
Forge.switchToLast();

View File

@@ -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";

View File

@@ -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<Rectangle> 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();
}

View File

@@ -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);

View File

@@ -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> T parse(Class<T> type, String json, String fallback){
return parse(type, null, json, fallback);
}
public static @Null <T> T parse(Class<T> 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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.8" tiledversion="1.8.4" orientation="orthogonal" renderorder="right-down" width="30" height="30" tilewidth="16" tileheight="16" infinite="0" nextlayerid="6" nextobjectid="84">
<map version="1.8" tiledversion="1.8.4" orientation="orthogonal" renderorder="right-down" width="30" height="30" tilewidth="16" tileheight="16" infinite="0" nextlayerid="6" nextobjectid="86">
<editorsettings>
<export format="tmx"/>
</editorsettings>
@@ -32,11 +32,17 @@
</data>
</layer>
<objectgroup id="4" name="Objects">
<object id="47" template="../obj/gold.tx" x="96" y="224"/>
<object id="49" template="../obj/gold.tx" x="176" y="224"/>
<object id="47" template="../obj/gold.tx" x="32" y="352"/>
<object id="50" template="../obj/enemy.tx" x="112" y="192" width="64" height="64">
<properties>
<property name="effect">{
&quot;lifeModifier&quot;: -25,
&quot;opponent&quot;:{
&quot;startBattleWithCard&quot;: [ &quot;c_0_1_eldrazi_spawn_sac&quot;, &quot;c_0_1_eldrazi_spawn_sac&quot;, &quot;c_0_1_eldrazi_spawn_sac&quot;, &quot;c_0_1_eldrazi_spawn_sac&quot; ]
}
}</property>
<property name="enemy" value="Emrakul"/>
<property name="name" value="Emrakul, the promised rest"/>
</properties>
</object>
<object id="51" template="../obj/entry_up.tx" x="209" y="480">
@@ -70,13 +76,12 @@
<property name="sprite" value="sprites/3life.atlas"/>
</properties>
</object>
<object id="69" template="../obj/treasure.tx" x="192" y="352"/>
<object id="74" template="../obj/treasure.tx" x="224" y="352"/>
<object id="69" template="../obj/treasure.tx" x="48" y="336"/>
<object id="74" template="../obj/treasure.tx" x="224" y="64"/>
<object id="70" template="../obj/booster.tx" x="32" y="336"/>
<object id="72" template="../obj/booster.tx" x="224" y="320"/>
<object id="72" template="../obj/booster.tx" x="192" y="64"/>
<object id="71" template="../obj/gold.tx" x="48" y="352"/>
<object id="73" template="../obj/gold.tx" x="224" y="288"/>
<object id="78" template="../obj/gate.tx" x="144" y="208" visible="0">
<object id="78" template="../obj/gate.tx" x="64" y="208" visible="1">
<properties>
<property name="dialog">[
{
@@ -90,7 +95,7 @@
]</property>
</properties>
</object>
<object id="79" template="../obj/gate.tx" x="128" y="208" visible="0">
<object id="79" template="../obj/gate.tx" x="128" y="208" width="32" height="16" visible="1">
<properties>
<property name="dialog">[
{
@@ -106,10 +111,16 @@
</object>
<object id="80" template="../obj/enemy.tx" x="96" y="304">
<properties>
<property name="defeatDialog">[
{
&quot;text&quot;:&quot;Impressive...&quot;,
&quot;loctext&quot;:&quot;&quot;,
&quot;options&quot;:[ { &quot;name&quot;:&quot;Hey why are you still standing...?&quot; } ]
}
]</property>
<property name="dialog">[
{
&quot;effect&quot;:[],
&quot;name&quot;:&quot;ABC&quot;,
&quot;text&quot;:&quot;I am an elf. I do elf things like hugging trees and being pretty.&quot;,
&quot;loctext&quot;:&quot;&quot;,
&quot;condition&quot;:[],
@@ -118,7 +129,13 @@
{
&quot;name&quot;:&quot;Fight me, elf!&quot;,
&quot;text&quot;: &quot;Gladly.&quot;,
&quot;options&quot;: [ { &quot;name&quot;: &quot;I FEAR NOTHING!!?&quot;, &quot;effect&quot;: [ { &quot;battleWithActorID&quot;: -1 } ]} ]
&quot;options&quot;: [ { &quot;name&quot;: &quot;Hey aren't you a bit swole for an elf...?&quot;, &quot;effect&quot;: [ { &quot;battleWithActorID&quot;: -1 } ]} ]
},
{
&quot;name&quot;: &quot;I want to be eco-friendly too.&quot;,
&quot;condition&quot;: [ { &quot;colorIdentity&quot;: &quot;G&quot;, &quot;not&quot;: true } ],
&quot;text&quot;: &quot;Listen to the forest, friend.\nYour color identity is now green!&quot;,
&quot;options&quot;: [ { &quot;name&quot;: &quot;Awesome.&quot;, &quot;effect&quot;: [ { &quot;setColorIdentity&quot;: &quot;G&quot; } ]} ]
},
{
&quot;name&quot;:&quot;I wanna fight Emrakul over there!&quot;,
@@ -133,35 +150,193 @@
&quot;options&quot;: [ { &quot;name&quot;: &quot;Sorry...&quot; } ]
},
{
&quot;name&quot;:&quot;That's cool dude.&quot;,
&quot;condition&quot;: [ { &quot;item&quot;: &quot;Treasure&quot;, &quot;not&quot;: true } ],
&quot;name&quot;:&quot;That's cool my green dude.&quot;,
&quot;condition&quot;: [ { &quot;item&quot;: &quot;Treasure&quot;, &quot;not&quot;: true }, { &quot;colorIdentity&quot;: &quot;G&quot; } ],
&quot;effect&quot;: [ { &quot;addItem&quot;: &quot;Treasure&quot; } ],
&quot;text&quot;: &quot;You get it. Take this.&quot;,
&quot;text&quot;: &quot;You get it! Take this.&quot;,
&quot;options&quot;: [ { &quot;name&quot;: &quot;Thanks bro.&quot; } ]
},
{
&quot;name&quot;:&quot;Thanks for the blessing.&quot;,
&quot;condition&quot;: [ { &quot;hasBlessing&quot;: &quot;Debug Elf&quot; } ],
&quot;text&quot;: &quot;You are welcome.&quot;,
&quot;options&quot;: [ { &quot;name&quot;: &quot;Thumbs up emoji&quot; } ]
},
{
&quot;name&quot;:&quot;Got any fancy elven blessing?&quot;,
&quot;condition&quot;: [ { &quot;item&quot;: &quot;Treasure&quot; }, { &quot;hasBlessing&quot;: &quot;Debug Elf&quot;, &quot;not&quot;: true } ],
&quot;text&quot;: &quot;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?&quot;,
&quot;options&quot;: [
{ &quot;name&quot;: &quot;But I love my Treasure! I humbly refuse.&quot;},
{
&quot;name&quot;: &quot;I'll take it&quot;,
&quot;effect&quot;: [
{ &quot;removeItem&quot;: &quot;Treasure&quot;, &quot;giveBlessing&quot;: { &quot;name&quot;: &quot;Debug Elf&quot; ,&quot;lifeModifier&quot;: 2, &quot;startBattleWithCard&quot;: [ &quot;Llanowar Elves&quot; ] } }
]
}
]
},
{
&quot;name&quot;:&quot;Can you open that hidden wall?&quot;,
&quot;condition&quot;: [ { &quot;actorID&quot;: 83 } ],
&quot;text&quot;: &quot;Since you asked nicely, I shall.&quot;,
&quot;options&quot;: [ { &quot;name&quot;: &quot;Thanks bro.&quot;, &quot;effect&quot;: [ { &quot;deleteMapObject&quot;: 83 } ]} ]
},
{
&quot;name&quot;: &quot;Got a quest?&quot;,
&quot;condition&quot;: [ { &quot;checkQuestFlag&quot;: &quot;128&quot;, &quot;not&quot;: true} ],
&quot;text&quot;: &quot;Ah, perhaps you can help me. Can you ask the Debug Demon about his favorite color?&quot;,
&quot;options&quot;: [
{ &quot;name&quot;: &quot;That's weird, but sure.&quot;, &quot;effect&quot;: [ { &quot;setQuestFlag&quot;: {&quot;key&quot;:&quot;128&quot;, &quot;val&quot;: 1} } ] },
{ &quot;name&quot;: &quot;That guy scares me, I'd rather not.&quot; }
]
},
{
&quot;name&quot;: &quot;About that quest...&quot;,
&quot;condition&quot;: [ { &quot;getQuestFlag&quot;: { &quot;key&quot;: &quot;128&quot;, &quot;op&quot;:&quot;&lt;&quot;, &quot;val&quot;: 3 } } ],
&quot;text&quot;: &quot;Please let me know what the Debug Demon's answer is.&quot;,
&quot;options&quot;: [
{ &quot;name&quot;: &quot;Sure&quot; }
]
},
{
&quot;name&quot;: &quot;Got it, bro.&quot;,
&quot;condition&quot;: [ { &quot;getQuestFlag&quot;: { &quot;key&quot;: &quot;128&quot;, &quot;op&quot;:&quot;=&quot;, &quot;val&quot;: 3 } } ],
&quot;text&quot;: &quot;Ah. I see. Thank you friend, have this gold for your inconvenience.&quot;,
&quot;options&quot;: [
{ &quot;name&quot;: &quot;Thanks&quot;, &quot;effect&quot;: [ { &quot;setQuestFlag&quot;: {&quot;key&quot;:&quot;128&quot;, &quot;val&quot;: 4}, &quot;addGold&quot;: 250 } ] }
]
}
]
}
]
}
]</property>
<property name="enemy" value="Elf"/>
<property name="permanent" type="bool" value="true"/>
]</property>
<property name="effect">{
&quot;lifeModifier&quot;: 190,
&quot;startBattleWithCard&quot;: [ &quot;Llanowar Elves&quot;, &quot;Llanowar Elves&quot;, &quot;Forest&quot;, &quot;Forest&quot; ]
}</property>
<property name="enemy" value="Elf warrior"/>
<property name="name" value="Debug Elf"/>
</properties>
</object>
<object id="81" template="../obj/enemy.tx" x="288" y="224">
<properties>
<property name="dialog">[
{
&quot;text&quot;: &quot;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!!!!&quot;,
&quot;condition&quot;: [
{
&quot;actorID&quot;: 82,
&quot;not&quot;: true
}
],
&quot;options&quot;: [
{
&quot;name&quot;: &quot;Uh oh.&quot;,
&quot;effect&quot;: [
{
&quot;setEffect&quot;: {
&quot;lifeModifier&quot;: 99,
&quot;startBattleWithCard&quot;: [
&quot;Avacyn, Angel of Hope&quot;,
&quot;Urabrask the Hidden&quot;,
&quot;Elesh Norn, Grand Cenobite&quot;,
&quot;Emrakul, the Aeons Torn&quot;
]
}, &quot;battleWithActorID&quot;: -1
}
]
}
]
}
]</property>
<property name="enemy" value="Goblin"/>
</properties>
</object>
<object id="82" template="../obj/enemy.tx" gid="2147491275" x="272" y="224">
<properties>
<property name="dialog">[
{
&quot;text&quot;:&quot;...&quot;,
&quot;condition&quot;:[ { &quot;getQuestFlag&quot;: { &quot;key&quot;: &quot;128&quot;, &quot;op&quot;:&quot;&lt;&quot;, &quot;val&quot;: 3 } } ],
&quot;options&quot;:[
{ &quot;name&quot;:&quot;???&quot; }
]
}
]</property>
<property name="enemy" value="Goblin"/>
</properties>
</object>
<object id="83" template="../obj/gate.tx" type="dummy" gid="3651" x="64" y="336" width="16" height="16"/>
<object id="84" template="../obj/enemy.tx" x="320" y="304">
<properties>
<property name="dialog">[
{
&quot;effect&quot;:[],
&quot;text&quot;:&quot;I have some things to offer for that life you have...&quot;,
&quot;condition&quot;:[],
&quot;options&quot;:[
{ &quot;name&quot;:&quot;You are suspicious and have two shadows, I'm out.&quot; },
{
&quot;name&quot;:&quot;I'll vanquish you, demon!&quot;,
&quot;text&quot;: &quot;Oh look we got a tough guy over here!&quot;,
&quot;options&quot;: [ { &quot;name&quot;: &quot;I FEAR NOTHING!!&quot;, &quot;effect&quot;: [ { &quot;battleWithActorID&quot;: -1 } ]} ]
},
{
&quot;name&quot;: &quot;I dig your edge.&quot;,
&quot;condition&quot;: [ { &quot;colorIdentity&quot;: &quot;B&quot;, &quot;not&quot;: true }, { &quot;hasLife&quot;: 2 } ],
&quot;text&quot;: &quot;You can be dark and edgy like me. Maybe for some of your life force...&quot;,
&quot;options&quot;: [ { &quot;name&quot;: &quot;I'm doing nothing better with it.&quot;, &quot;effect&quot;: [ { &quot;setColorIdentity&quot;: &quot;B&quot;, &quot;addLife&quot;: -2 } ]} ]
},
{
&quot;name&quot;: &quot;I dig your edge.&quot;,
&quot;condition&quot;: [ { &quot;colorIdentity&quot;: &quot;B&quot;, &quot;not&quot;: true }, { &quot;hasLife&quot;: 2, &quot;not&quot;: true } ],
&quot;text&quot;: &quot;You don't have enough life force...come back with more to offer.&quot;,
&quot;options&quot;: [ { &quot;name&quot;: &quot;Aw man...&quot; } ]
},
{
&quot;name&quot;: &quot;Any cool demon deals?&quot;,
&quot;condition&quot;: [ { &quot;colorIdentity&quot;: &quot;B&quot; }, { &quot;hasGold&quot;: 200 } ],
&quot;text&quot;: &quot;I can offer you this Treasure for the fair price of 200 gold.&quot;,
&quot;options&quot;: [
{ &quot;name&quot;: &quot;This gem has a lot of edge, just like me. Deal!&quot; , &quot;effect&quot;: [ { &quot;addGold&quot;: -20000, &quot;addItem&quot;: &quot;Treasure&quot; } ] },
{ &quot;name&quot;: &quot;I'll think about it.&quot; }
]
},
{
&quot;name&quot;:&quot;Got any fancy demon blessing?&quot;,
&quot;condition&quot;: [ {&quot;colorIdentity&quot;: &quot;B&quot;}, { &quot;item&quot;: &quot;Treasure&quot; }, { &quot;hasBlessing&quot;: &quot;Debug Demon&quot;, &quot;not&quot;: true } ],
&quot;text&quot;: &quot;Give me that Treasure of yours...\n(+1 health, Manasight, move speed 120%, Lord of the Pit starts in play)&quot;,
&quot;options&quot;: [
{ &quot;name&quot;: &quot;That's shady.&quot;},
{
&quot;name&quot;: &quot;What can possibly go wrong?&quot;,
&quot;effect&quot;: [
{ &quot;removeItem&quot;: &quot;Treasure&quot;, &quot;giveBlessing&quot;: { &quot;name&quot;: &quot;Debug Demon&quot; , &quot;lifeModifier&quot;: 1, &quot;colorView&quot;: true, &quot;moveSpeed&quot;: 2, &quot;startBattleWithCard&quot;: [ &quot;Lord of the Pit&quot; ] } }
]
}
]
},
{
&quot;name&quot;: &quot;Hey what's your favorite color?&quot;,
&quot;condition&quot;: [ {&quot;getQuestFlag&quot;: { &quot;key&quot;:&quot;128&quot;, &quot;op&quot;:&quot;=&quot;, &quot;val&quot;:1 } } ],
&quot;text&quot;: &quot;Why, purple. It is a powerful color.&quot;,
&quot;options&quot;: [
{ &quot;name&quot;: &quot;Thank you Satan.&quot;, &quot;effect&quot;: [ { &quot;setQuestFlag&quot;: { &quot;key&quot;:&quot;128&quot;, &quot;val&quot;:3 } } ] }
]
}
]
}
]</property>
<property name="enemy" value="Demon"/>
<property name="name" value="Debug Demon"/>
</properties>
</object>
<object id="85" template="../obj/scroll.tx" x="208" y="96">
<properties>
<property name="reward">[
{ &quot;cardName&quot;: &quot;Black Lotus&quot;, &quot;type&quot;:&quot;card&quot;, &quot;count&quot;:1 }
]</property>
</properties>
</object>
</objectgroup>
</map>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<template>
<tileset firstgid="1" source="../tileset/buildings.tsx"/>
<object name="Scroll" type="reward" gid="1363" width="16" height="16">
<properties>
<property name="reward" value="[ { &quot;type&quot;: &quot;card&quot;, &quot;cardName&quot;: &quot;Black Lotus&quot;, &quot;amount&quot;: 1 } ]"/>
<property name="sprite" value="sprites/scroll.atlas"/>
</properties>
</object>
</template>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

After

Width:  |  Height:  |  Size: 227 KiB

View File

@@ -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

View File

@@ -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": {

View File

@@ -1,5 +1,5 @@
treasure.png
size: 64,112
size: 64,128
format: RGBA8888
filter: Nearest,Nearest
repeat: none

View File

@@ -1,5 +1,5 @@
treasure.png
size: 64,112
size: 64,128
format: RGBA8888
filter: Nearest,Nearest
repeat: none

View File

@@ -1,5 +1,5 @@
treasure.png
size: 64,112
size: 64,128
format: RGBA8888
filter: Nearest,Nearest
repeat: none

View File

@@ -1,5 +1,5 @@
treasure.png
size: 64,112
size: 64,128
format: RGBA8888
filter: Nearest,Nearest
repeat: none

View File

@@ -1,5 +1,5 @@
treasure.png
size: 64,112
size: 64,128
format: RGBA8888
filter: Nearest,Nearest
repeat: none

View File

@@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -3,12 +3,13 @@
"height": 270,
"yDown": true,
"elements": [
{
{
"type": "Image",
"image": "ui/title_bg.png",
"width": 480,
"height": 270
}, {
},
{
"type": "Image",
"image": "ui/equipment.png",
"x": 8,
@@ -24,7 +25,7 @@
"height": 20,
"x": 62,
"y": 40
} ,
},
{
"type": "ImageButton",
"name": "Equipment_Body",
@@ -33,7 +34,7 @@
"height": 20,
"x": 62,
"y": 85
} ,
},
{
"type": "ImageButton",
"name": "Equipment_Boots",
@@ -42,7 +43,7 @@
"height": 20,
"x": 62,
"y": 220
} ,
},
{
"type": "ImageButton",
"name": "Equipment_Left",
@@ -51,7 +52,7 @@
"height": 20,
"x": 17,
"y": 130
} ,
},
{
"type": "ImageButton",
"name": "Equipment_Right",
@@ -60,7 +61,7 @@
"height": 20,
"x": 107,
"y": 130
} ,
},
{
"type": "Scroll",
"name": "inventory",
@@ -75,15 +76,15 @@
"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,13 +100,13 @@
"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,

View File

@@ -87,7 +87,7 @@
{
"type": "TextButton",
"name": "delete",
"text": "Delete",
"text": "Discard",
"width": 80,
"height": 30,
"x": 8,

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

View File

@@ -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
},
{

View File

@@ -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",

File diff suppressed because it is too large Load Diff

View File

@@ -587,6 +587,14 @@
]
}
},
{
"name": "Manasight Amulet",
"equipmentSlot": "Neck",
"iconName": "RelicAmulet",
"effect": {
"colorView": true
}
},
{
"name": "Amulet of Kroog",
"equipmentSlot": "Neck",