Merge pull request #2678 from kevlahnota/newmaster2

fix dialog voiceFile not playing on Android
This commit is contained in:
Anthony Calosa
2023-03-14 18:20:35 +08:00
committed by GitHub
4 changed files with 216 additions and 133 deletions

View File

@@ -281,41 +281,23 @@ public class MapStage extends GameStage {
FImageComplex cardArt = CardRenderer.getCardArt(dp.getHighestCMCCard()); FImageComplex cardArt = CardRenderer.getCardArt(dp.getHighestCMCCard());
if (cardArt != null) { if (cardArt != null) {
Image art = new Image(cardArt.getTextureRegion()); Image art = new Image(cardArt.getTextureRegion());
art.setWidth(57); art.setWidth(58);
art.setHeight(41); art.setHeight(46);
art.setPosition(23, 30); art.setPosition(25, 43);
Image image = new Image(FSkinImage.ADV_DECKBOX.getTextureRegion()); Image image = new Image(FSkinImage.ADV_DECKBOX.getTextureRegion());
image.setWidth(60); image.setWidth(60);
image.setHeight(50); image.setHeight(80);
image.setPosition(22, 22); image.setPosition(24, 10);
ColorSet colorSet = DeckProxy.getColorIdentity(deck); ColorSet colorSet = DeckProxy.getColorIdentity(deck);
TypingLabel deckColors = Controls.newTypingLabel(Controls.colorIdToTypingString(colorSet, false).toUpperCase()); TypingLabel deckColors = Controls.newTypingLabel(Controls.colorIdToTypingString(colorSet, true).toUpperCase());
deckColors.skipToTheEnd(); deckColors.skipToTheEnd();
deckColors.setAlignment(Align.left); deckColors.setAlignment(Align.center);
float padding; deckColors.setPosition(14, 44);
switch (colorSet.countColors()) {
case 1:
padding = 24f;
break;
case 2:
padding = 18f;
break;
case 3:
padding = 12f;
break;
case 4:
padding = 6f;
break;
default:
padding = 0f;
break;
}
deckColors.setPosition(22 + padding, 15);
TextraLabel deckname = Controls.newTextraLabel(deck.getName()); TextraLabel deckname = Controls.newTextraLabel(deck.getName());
deckname.setAlignment(Align.bottom); deckname.setAlignment(Align.center);
deckname.setWrap(true); deckname.setWrap(true);
deckname.setWidth(100); deckname.setWidth(80);
deckname.setPosition(0, 75); deckname.setPosition(14, 28);
Group group = new Group(); Group group = new Group();
group.addActor(art); group.addActor(art);
group.addActor(image); group.addActor(image);

View File

@@ -1,5 +1,8 @@
package forge.adventure.util; package forge.adventure.util;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.Dialog; import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
@@ -16,8 +19,9 @@ import forge.adventure.stage.MapStage;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences;
import forge.model.FModel; import forge.model.FModel;
import forge.sound.AudioClip; import forge.sound.SoundSystem;
import forge.util.Localizer; import forge.util.Localizer;
import org.apache.commons.lang3.tuple.Pair;
/** /**
* MapDialog * MapDialog
@@ -26,7 +30,7 @@ import forge.util.Localizer;
public class MapDialog { public class MapDialog {
private final MapStage stage; private final MapStage stage;
private Array<DialogData> data; private Array<DialogData> data;
private final int parentID; private final int parentID;
private final static float WIDTH = 250f; private final static float WIDTH = 250f;
static private final String defaultJSON = "[\n" + static private final String defaultJSON = "[\n" +
@@ -45,8 +49,7 @@ public class MapDialog {
public MapDialog(String S, MapStage stage, int parentID) { public MapDialog(String S, MapStage stage, int parentID) {
this.stage = stage; this.stage = stage;
this.parentID = parentID; this.parentID = parentID;
try try {
{
if (S.isEmpty()) { if (S.isEmpty()) {
System.err.print("Dialog error. Dialog property is empty.\n"); System.err.print("Dialog error. Dialog property is empty.\n");
@@ -54,31 +57,80 @@ public class MapDialog {
return; return;
} }
this.data = JSONStringLoader.parse(Array.class, DialogData.class, S, defaultJSON); this.data = JSONStringLoader.parse(Array.class, DialogData.class, S, defaultJSON);
} } catch (Exception exception) {
catch (Exception exception)
{
exception.printStackTrace(); exception.printStackTrace();
} }
} }
static AudioClip audio=null;
Pair<FileHandle, Music> audio = null;
float fade = 1f;
void unload() {
if (audio != null) {
audio.getRight().setOnCompletionListener(null);
audio.getRight().stop();
Forge.getAssets().manager().unload(audio.getLeft().path());
audio = null;
}
}
void disposeAudio() {
disposeAudio(false);
}
void disposeAudio(boolean fadeout) {
if (fadeout) {
final float[] v = {1f};
for (int i = 10; i > 1; i--) {
float delay = i * 0.1f;
float j = i;
Timer.schedule(new Timer.Task() {
@Override
public void run() {
v[0] -= 0.1f;
if (v[0] < 0.1f)
v[0] = 0.1f;
if (audio != null && j == 2) {
unload();
} else if (audio != null && j == 10) {
audio.getRight().setVolume(v[0]);
}
}
}, delay);
}
} else {
unload();
}
}
private void loadDialog(DialogData dialog) { //Displays a dialog with dialogue and possible choices. private void loadDialog(DialogData dialog) { //Displays a dialog with dialogue and possible choices.
setEffects(dialog.action); setEffects(dialog.action);
Dialog D = stage.getDialog(); Dialog D = stage.getDialog();
Localizer L = Forge.getLocalizer(); Localizer L = Forge.getLocalizer();
D.getContentTable().clear(); D.getButtonTable().clear(); //Clear tables to start fresh. D.getContentTable().clear();
D.getButtonTable().clear(); //Clear tables to start fresh.
D.clearListeners(); D.clearListeners();
String text; //Check for localized string (locname), otherwise print text. String text; //Check for localized string (locname), otherwise print text.
if(dialog.loctext != null && !dialog.loctext.isEmpty()) text = L.getMessage(dialog.loctext); if (dialog.loctext != null && !dialog.loctext.isEmpty()) text = L.getMessage(dialog.loctext);
else text = dialog.text; else text = dialog.text;
if(audio!=null) disposeAudio();
audio.stop(); if (dialog.voiceFile != null) {
if(dialog.voiceFile!=null) FileHandle file = Gdx.files.absolute(Config.instance().getFilePath(dialog.voiceFile));
{ if (file.exists()) {
audio = AudioClip.createClip(Config.instance().getFilePath(dialog.voiceFile)); audio = Pair.of(file, Forge.getAssets().getMusic(file));
if(audio!=null) }
audio.play(FModel.getPreferences().getPrefInt(ForgePreferences.FPref.UI_VOL_SOUNDS)/100f); if (audio != null) {
int vol = FModel.getPreferences().getPrefInt(ForgePreferences.FPref.UI_VOL_MUSIC);
if (vol > 0) {
fadeOut();
audio.getRight().play();
}
} else {
fadeIn();
}
} else {
fadeIn();
} }
TypingLabel A = Controls.newTypingLabel(text); TypingLabel A = Controls.newTypingLabel(text);
A.setWrap(true); A.setWrap(true);
@@ -99,14 +151,14 @@ public class MapDialog {
} }
}); });
D.getContentTable().add(A).width(WIDTH); //Add() returns a Cell, which is what the width is being applied to. D.getContentTable().add(A).width(WIDTH); //Add() returns a Cell, which is what the width is being applied to.
if(dialog.options != null) { if (dialog.options != null) {
int i=0; int i = 0;
for(DialogData option:dialog.options) { for (DialogData option : dialog.options) {
if( isConditionOk(option.condition) ) { if (isConditionOk(option.condition)) {
String name; //Get localized label if present. String name; //Get localized label if present.
if(option.locname != null && !option.locname.isEmpty()) name = L.getMessage(option.locname); if (option.locname != null && !option.locname.isEmpty()) name = L.getMessage(option.locname);
else name = option.name; else name = option.name;
TextraButton B = Controls.newTextButton(name,() -> loadDialog(option)); TextraButton B = Controls.newTextButton(name, () -> loadDialog(option));
B.getTextraLabel().setWrap(true); //We want this to wrap in case it's a wordy choice. B.getTextraLabel().setWrap(true); //We want this to wrap in case it's a wordy choice.
buttons.add(B); buttons.add(B);
B.setVisible(false); B.setVisible(false);
@@ -116,84 +168,116 @@ public class MapDialog {
i++; i++;
} }
} }
D.addListener(new ClickListener(){ D.addListener(new ClickListener() {
@Override @Override
public void clicked(InputEvent event, float x, float y) { public void clicked(InputEvent event, float x, float y) {
A.skipToTheEnd(); A.skipToTheEnd();
super.clicked(event, x, y); super.clicked(event, x, y);
} }
}); });
if(i==0) if (i == 0)
stage.hideDialog(); stage.hideDialog();
else else
stage.showDialog(); stage.showDialog();
} } else {
else {
stage.hideDialog(); stage.hideDialog();
} }
} }
void fadeIn() {
disposeAudio(true);
if (fade >= 1f)
return;
for (int i = 10; i > 1; i--) {
float delay = i * 0.1f;
Timer.schedule(new Timer.Task() {
@Override
public void run() {
fade += 0.1f;
if (fade > 1f)
fade = 1f;
SoundSystem.instance.fadeModifier(fade);
}
}, delay);
}
}
void fadeOut() {
for (int i = 10; i > 1; i--) {
float delay = i * 0.1f;
Timer.schedule(new Timer.Task() {
@Override
public void run() {
fade -= 0.1f;
if (fade < 0.1f)
fade = 0.1f;
SoundSystem.instance.fadeModifier(fade);
}
}, delay);
}
}
public void activate() { //Method for actors to show their dialogues. public void activate() { //Method for actors to show their dialogues.
for(DialogData dialog:data) { for (DialogData dialog : data) {
if(isConditionOk(dialog.condition)) { if (isConditionOk(dialog.condition)) {
loadDialog(dialog); loadDialog(dialog);
} }
} }
} }
void setEffects(DialogData.ActionData[] data) { void setEffects(DialogData.ActionData[] data) {
if(data==null) return; if (data == null) return;
for(DialogData.ActionData E:data) { for (DialogData.ActionData E : data) {
if(E.removeItem != null){ //Removes an item from the player's inventory. if (E.removeItem != null) { //Removes an item from the player's inventory.
Current.player().removeItem(E.removeItem); 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); Current.player().addItem(E.addItem);
} }
if(E.addLife != 0){ //Gives (positive or negative) life to the player. Cannot go over max health. if (E.addLife != 0) { //Gives (positive or negative) life to the player. Cannot go over max health.
Current.player().heal(E.addLife); Current.player().heal(E.addLife);
} }
if(E.addGold != 0){ //Gives (positive or negative) gold to the player. if (E.addGold != 0) { //Gives (positive or negative) gold to the player.
if(E.addGold > 0) Current.player().giveGold(E.addGold); if (E.addGold > 0) Current.player().giveGold(E.addGold);
else Current.player().takeGold(-E.addGold); else Current.player().takeGold(-E.addGold);
} }
if(E.deleteMapObject != 0){ //Removes a dummy object from the map. if (E.deleteMapObject != 0) { //Removes a dummy object from the map.
if(E.deleteMapObject < 0) stage.deleteObject(parentID); if (E.deleteMapObject < 0) stage.deleteObject(parentID);
else stage.deleteObject(E.deleteMapObject); 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)); if (E.battleWithActorID < 0) stage.beginDuel(stage.getEnemyByID(parentID));
else stage.beginDuel(stage.getEnemyByID(E.battleWithActorID)); else stage.beginDuel(stage.getEnemyByID(E.battleWithActorID));
} }
if(E.giveBlessing != null) { //Gives a blessing for your next battle. if (E.giveBlessing != null) { //Gives a blessing for your next battle.
Current.player().addBlessing(E.giveBlessing); Current.player().addBlessing(E.giveBlessing);
} }
if(E.setColorIdentity != null && !E.setColorIdentity.isEmpty()){ //Sets color identity (use sparingly) if (E.setColorIdentity != null && !E.setColorIdentity.isEmpty()) { //Sets color identity (use sparingly)
Current.player().setColorIdentity(E.setColorIdentity); Current.player().setColorIdentity(E.setColorIdentity);
} }
if(E.setQuestFlag != null && !E.setQuestFlag.key.isEmpty()){ //Set a quest to given value. if (E.setQuestFlag != null && !E.setQuestFlag.key.isEmpty()) { //Set a quest to given value.
Current.player().setQuestFlag(E.setQuestFlag.key, E.setQuestFlag.val); Current.player().setQuestFlag(E.setQuestFlag.key, E.setQuestFlag.val);
} }
if(E.advanceQuestFlag != null && !E.advanceQuestFlag.isEmpty()){ //Increase a given quest flag by 1. if (E.advanceQuestFlag != null && !E.advanceQuestFlag.isEmpty()) { //Increase a given quest flag by 1.
Current.player().advanceQuestFlag(E.advanceQuestFlag); Current.player().advanceQuestFlag(E.advanceQuestFlag);
} }
if(E.setMapFlag != null && !E.setMapFlag.key.isEmpty()){ //Set a local quest to given value. if (E.setMapFlag != null && !E.setMapFlag.key.isEmpty()) { //Set a local quest to given value.
stage.setQuestFlag(E.setMapFlag.key, E.setMapFlag.val); stage.setQuestFlag(E.setMapFlag.key, E.setMapFlag.val);
} }
if(E.advanceMapFlag != null && !E.advanceMapFlag.isEmpty()){ //Increase a given local quest flag by 1. if (E.advanceMapFlag != null && !E.advanceMapFlag.isEmpty()) { //Increase a given local quest flag by 1.
stage.advanceQuestFlag(E.advanceMapFlag); stage.advanceQuestFlag(E.advanceMapFlag);
} }
if(E.setEffect != null){ //Replace current effects. if (E.setEffect != null) { //Replace current effects.
EnemySprite EN = stage.getEnemyByID(parentID); EnemySprite EN = stage.getEnemyByID(parentID);
EN.effect = E.setEffect; EN.effect = E.setEffect;
} }
} }
} }
public boolean canShow(){ public boolean canShow() {
if( data == null) return false; if (data == null) return false;
for(DialogData dialog:data) { for (DialogData dialog : data) {
if(isConditionOk(dialog.condition)) { if (isConditionOk(dialog.condition)) {
return true; return true;
} }
} }
@@ -201,80 +285,97 @@ public class MapDialog {
} }
public boolean isConditionOk(DialogData.ConditionData[] data) { public boolean isConditionOk(DialogData.ConditionData[] data) {
if( data==null ) return true; if (data == null) return true;
AdventurePlayer player = Current.player(); AdventurePlayer player = Current.player();
for(DialogData.ConditionData condition:data) { for (DialogData.ConditionData condition : data) {
//TODO:Check for card in inventory. //TODO:Check for card in inventory.
if(condition.item != null && !condition.item.isEmpty()) { //Check for an item in player's inventory. if (condition.item != null && !condition.item.isEmpty()) { //Check for an item in player's inventory.
if(!player.hasItem(condition.item)) { if (!player.hasItem(condition.item)) {
if(!condition.not) return false; //Only return on a false. if (!condition.not) return false; //Only return on a false.
} else if(condition.not) return false; } else if (condition.not) return false;
} }
if(condition.colorIdentity != null && !condition.colorIdentity.isEmpty()) { //Check for player's color ID. if (condition.colorIdentity != null && !condition.colorIdentity.isEmpty()) { //Check for player's color ID.
if(player.getColorIdentity().hasAllColors(ColorSet.fromNames(condition.colorIdentity.toCharArray()).getColor())) if (player.getColorIdentity().hasAllColors(ColorSet.fromNames(condition.colorIdentity.toCharArray()).getColor())) {
{ if (!condition.not) return false;
if(!condition.not) return false; } else if (condition.not) return false;
} else if(condition.not) return false;
} }
if(condition.hasGold != 0){ //Check for at least X gold. if (condition.hasGold != 0) { //Check for at least X gold.
if(player.getGold() < condition.hasGold){ if (player.getGold() < condition.hasGold) {
if(!condition.not) return false; if (!condition.not) return false;
} else if(condition.not) return false; } else if (condition.not) return false;
} }
if(condition.hasLife != 0){ //Check for at least X life.. if (condition.hasLife != 0) { //Check for at least X life..
if(player.getLife() < condition.hasLife + 1){ if (player.getLife() < condition.hasLife + 1) {
if(!condition.not) return false; if (!condition.not) return false;
} else if(condition.not) return false; } else if (condition.not) return false;
} }
if(condition.hasBlessing != null && !condition.hasBlessing.isEmpty()){ //Check for a named blessing. if (condition.hasBlessing != null && !condition.hasBlessing.isEmpty()) { //Check for a named blessing.
if(!player.hasBlessing(condition.hasBlessing)){ if (!player.hasBlessing(condition.hasBlessing)) {
if(!condition.not) return false; if (!condition.not) return false;
} else if(condition.not) return false; } else if (condition.not) return false;
} }
if(condition.actorID != 0) { //Check for actor ID. if (condition.actorID != 0) { //Check for actor ID.
if(!stage.lookForID(condition.actorID)){ if (!stage.lookForID(condition.actorID)) {
if(!condition.not) return false; //Same as above. if (!condition.not) return false; //Same as above.
} else if(condition.not) return false; } else if (condition.not) return false;
} }
if(condition.getQuestFlag != null){ if (condition.getQuestFlag != null) {
String key = condition.getQuestFlag.key; String key = condition.getQuestFlag.key;
String cond = condition.getQuestFlag.op; String cond = condition.getQuestFlag.op;
int val = condition.getQuestFlag.val; int val = condition.getQuestFlag.val;
int QF = player.getQuestFlag(key); int QF = player.getQuestFlag(key);
if(!player.checkQuestFlag(key)) return false; //If the quest is not ongoing, stop. if (!player.checkQuestFlag(key)) return false; //If the quest is not ongoing, stop.
if(!checkFlagCondition(QF, cond, val)) { if(!condition.not) return false; } if (!checkFlagCondition(QF, cond, val)) {
else { if(condition.not) return false; } if (!condition.not) return false;
} else {
if (condition.not) return false;
}
} }
if(condition.checkQuestFlag != null && !condition.checkQuestFlag.isEmpty()){ if (condition.checkQuestFlag != null && !condition.checkQuestFlag.isEmpty()) {
if(!player.checkQuestFlag(condition.checkQuestFlag)){ if (!player.checkQuestFlag(condition.checkQuestFlag)) {
if(!condition.not) return false; if (!condition.not) return false;
} else if(condition.not) return false; } else if (condition.not) return false;
} }
if(condition.getMapFlag != null){ if (condition.getMapFlag != null) {
String key = condition.getMapFlag.key; String key = condition.getMapFlag.key;
String cond = condition.getMapFlag.op; String cond = condition.getMapFlag.op;
int val = condition.getMapFlag.val; int val = condition.getMapFlag.val;
int QF = stage.getQuestFlag(key); int QF = stage.getQuestFlag(key);
if(!stage.checkQuestFlag(key)) return false; //If the quest is not ongoing, stop. if (!stage.checkQuestFlag(key)) return false; //If the quest is not ongoing, stop.
if(!checkFlagCondition(QF, cond, val)) { if(!condition.not) return false; } if (!checkFlagCondition(QF, cond, val)) {
else { if(condition.not) return false; } if (!condition.not) return false;
} else {
if (condition.not) return false;
}
} }
if(condition.checkMapFlag != null && !condition.checkMapFlag.isEmpty()){ if (condition.checkMapFlag != null && !condition.checkMapFlag.isEmpty()) {
if(!stage.checkQuestFlag(condition.checkMapFlag)){ if (!stage.checkQuestFlag(condition.checkMapFlag)) {
if(!condition.not) return false; if (!condition.not) return false;
} else if(condition.not) return false; } else if (condition.not) return false;
} }
} }
return true; return true;
} }
private boolean checkFlagCondition(int flag, String condition, int value){
switch(condition.toUpperCase()){ private boolean checkFlagCondition(int flag, String condition, int value) {
default: case "EQUALS": case"EQUAL": case "=": switch (condition.toUpperCase()) {
if(flag == value) return true; default:
case "LESSTHAN": case "<": if(flag < value) return true; case "EQUALS":
case "MORETHAN": case ">": if(flag > value) return true; case "EQUAL":
case "LE_THAN": case "<=": if(flag <= value) return true; case "=":
case "ME_THAN": case ">=": if(flag >= value) return true; if (flag == value) return true;
case "LESSTHAN":
case "<":
if (flag < value) return true;
case "MORETHAN":
case ">":
if (flag > value) return true;
case "LE_THAN":
case "<=":
if (flag <= value) return true;
case "ME_THAN":
case ">=":
if (flag >= value) return true;
} }
return false; return false;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -270,7 +270,7 @@ public enum FSkinProp {
//adventure icons //adventure icons
ICO_MANASHARD (new int[] {2, 304, 100, 100}, PropType.ADVENTURE), ICO_MANASHARD (new int[] {2, 304, 100, 100}, PropType.ADVENTURE),
ICO_ADVLOGO (new int[] {2, 2, 300, 300}, PropType.ADVENTURE), ICO_ADVLOGO (new int[] {2, 2, 300, 300}, PropType.ADVENTURE),
ICO_ADVDECKBOX (new int[] {107, 427, 195, 175}, PropType.ADVENTURE), ICO_ADVDECKBOX (new int[] {111, 365, 192, 240}, PropType.ADVENTURE),
//menu icon //menu icon
ICO_MENU_GALAXY (new int[] {0, 1520, 80, 80}, PropType.ICON), ICO_MENU_GALAXY (new int[] {0, 1520, 80, 80}, PropType.ICON),