From 3f252af15e82ebf52e340f0c50e1921b92cd8365 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sun, 27 Feb 2022 12:34:35 +0800 Subject: [PATCH 1/4] fix black transition screen when loading save - run transition screen first then switchscene --- .../src/forge/adventure/scene/SaveLoadScene.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java b/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java index 18716fcf5c7..da8f03ad0f8 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java @@ -110,8 +110,12 @@ public class SaveLoadScene extends UIScene { stage.setKeyboardFocus(textInput); } else { if (WorldSave.load(currentSlot)) { - Forge.setTransitionScreen(new TransitionScreen(null, null, false, true)); - Forge.switchScene(SceneType.GameScene.instance); + Forge.setTransitionScreen(new TransitionScreen(new Runnable() { + @Override + public void run() { + Forge.switchScene(SceneType.GameScene.instance); + } + }, null, false, true)); } else { Forge.clearTransitionScreen(); } From ac8365e13a2c021697b81456353763960d1ffe8b Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sun, 27 Feb 2022 13:12:55 +0800 Subject: [PATCH 2/4] Fix World Background --- .../adventure/stage/WorldBackground.java | 26 +++++-------------- .../forge/adventure/world/BiomeTexture.java | 2 +- .../src/forge/adventure/world/World.java | 6 ++--- .../adventure/world/WorldSaveHeader.java | 4 +-- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldBackground.java b/forge-gui-mobile/src/forge/adventure/stage/WorldBackground.java index 98e39d23a24..0cfaf1e186a 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldBackground.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldBackground.java @@ -6,7 +6,6 @@ import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.math.GridPoint2; import com.badlogic.gdx.scenes.scene2d.Actor; import forge.adventure.world.WorldSave; -import forge.gui.GuiBase; import java.util.ArrayList; @@ -69,26 +68,15 @@ public class WorldBackground extends Actor { currentChunkX = pos.x; currentChunkY = pos.y; } - batch.disableBlending(); - - if (GuiBase.isAndroid()) { - //TODO WorldBackground for Android - if (t == null) - t = new Texture(WorldSave.getCurrentSave().getWorld().getBiomeImage2()); - - batch.draw(t, 0, 0, WorldStage.getInstance().getViewport().getWorldWidth(), WorldStage.getInstance().getViewport().getWorldHeight()); - } else { - for (int x = -1; x < 2; x++) { - for (int y = -1; y < 2; y++) { - if (pos.y + y < 0 || pos.x + x < 0 || pos.y >= chunks[0].length || pos.x >= chunks.length) - continue; + for (int x = -1; x < 2; x++) { + for (int y = -1; y < 2; y++) { + if (pos.y + y < 0 || pos.x + x < 0 || pos.y >= chunks[0].length || pos.x >= chunks.length) + continue; - batch.draw(getChunkTexture(pos.x + x, pos.y + y), transChunkToWorld(pos.x + x), transChunkToWorld(pos.y + y)); - } + batch.draw(getChunkTexture(pos.x + x, pos.y + y), transChunkToWorld(pos.x + x), transChunkToWorld(pos.y + y)); } } - batch.enableBlending(); } @@ -124,7 +112,7 @@ public class WorldBackground extends Actor { public Texture getChunkTexture(int x, int y) { Texture tex = chunks[x][y]; if (tex == null) { - Texture newChunk = new Texture(chunkSize * tileSize, chunkSize * tileSize, Pixmap.Format.RGB888); + Texture newChunk = new Texture(chunkSize * tileSize, chunkSize * tileSize, Pixmap.Format.RGBA8888); for (int cx = 0; cx < chunkSize; cx++) { for (int cy = 0; cy < chunkSize; cy++) { newChunk.draw(WorldSave.getCurrentSave().getWorld().getBiomeSprite(cx + chunkSize * x, cy + chunkSize * y), cx * tileSize, (chunkSize * tileSize) - (cy + 1) * tileSize); @@ -155,7 +143,7 @@ public class WorldBackground extends Actor { if(loadingTexture==null) { - Pixmap loadPix = new Pixmap(chunkSize * tileSize, chunkSize * tileSize, Pixmap.Format.RGB565); + Pixmap loadPix = new Pixmap(chunkSize * tileSize, chunkSize * tileSize, Pixmap.Format.RGBA8888); loadPix.setColor(0.5f, 0.5f, 0.5f, 1); loadPix.fill(); loadingTexture = new Texture(loadPix); diff --git a/forge-gui-mobile/src/forge/adventure/world/BiomeTexture.java b/forge-gui-mobile/src/forge/adventure/world/BiomeTexture.java index 1e13e442a3c..c55b8374d60 100644 --- a/forge-gui-mobile/src/forge/adventure/world/BiomeTexture.java +++ b/forge-gui-mobile/src/forge/adventure/world/BiomeTexture.java @@ -19,7 +19,7 @@ import java.util.ArrayList; public class BiomeTexture implements Serializable { private final BiomeData data; private final int tileSize; - public Pixmap emptyPixmap = new Pixmap(1, 1, Pixmap.Format.RGB888); + public Pixmap emptyPixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); ArrayList> images = new ArrayList<>(); ArrayList> smallImages = new ArrayList<>(); ArrayList> edgeImages = new ArrayList<>(); diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index cad5cfc0af2..eb4eb27687d 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -135,7 +135,7 @@ public class World implements Disposable, SaveFileContent { } public Pixmap getBiomeSprite(int x, int y) { if (x < 0 || y <= 0 || x >= width || y > height) - return new Pixmap(data.tileSize, data.tileSize, Pixmap.Format.RGB888); + return new Pixmap(data.tileSize, data.tileSize, Pixmap.Format.RGBA8888); long biomeIndex = getBiome(x, y); int terrain = getTerrainIndex(x, y); @@ -242,8 +242,8 @@ public class World implements Disposable, SaveFileContent { //save at all data biomeMap = new long[width][height]; terrainMap= new int[width][height]; - Pixmap pix = new Pixmap(width, height, Pixmap.Format.RGB888); - Pixmap pix2 = new Pixmap(width, height, Pixmap.Format.RGB888); + Pixmap pix = new Pixmap(width, height, Pixmap.Format.RGBA8888); + Pixmap pix2 = new Pixmap(width, height, Pixmap.Format.RGBA8888); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { diff --git a/forge-gui-mobile/src/forge/adventure/world/WorldSaveHeader.java b/forge-gui-mobile/src/forge/adventure/world/WorldSaveHeader.java index 8b71eb028d9..bc90494633e 100644 --- a/forge-gui-mobile/src/forge/adventure/world/WorldSaveHeader.java +++ b/forge-gui-mobile/src/forge/adventure/world/WorldSaveHeader.java @@ -22,7 +22,7 @@ public class WorldSaveHeader implements java.io.Serializable, Disposable { out.writeUTF(name); if (preview == null) - preview = new Pixmap(1, 1, Pixmap.Format.RGB888); + preview = new Pixmap(1, 1, Pixmap.Format.RGBA8888); Serializer.WritePixmap(out, preview, true); out.writeObject(saveDate); } @@ -42,7 +42,7 @@ public class WorldSaveHeader implements java.io.Serializable, Disposable { public void createPreview() { Pixmap pixmap = Pixmap.createFromFrameBuffer(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); - Pixmap scaled = new Pixmap(WorldSaveHeader.previewImageWidth, (int) (WorldSaveHeader.previewImageWidth / (Scene.GetIntendedWidth() / (float) Scene.GetIntendedHeight())), Pixmap.Format.RGB888); + Pixmap scaled = new Pixmap(WorldSaveHeader.previewImageWidth, (int) (WorldSaveHeader.previewImageWidth / (Scene.GetIntendedWidth() / (float) Scene.GetIntendedHeight())), Pixmap.Format.RGBA8888); scaled.drawPixmap(pixmap, 0, 0, pixmap.getWidth(), pixmap.getHeight(), 0, 0, scaled.getWidth(), scaled.getHeight()); From 360522475c68dad53bf0d19825cfaf2585cdf136 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sun, 27 Feb 2022 13:19:33 +0800 Subject: [PATCH 3/4] remove unnecessary pixmap --- .../src/forge/adventure/world/World.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index eb4eb27687d..8f9a7e2151c 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -34,7 +34,7 @@ public class World implements Disposable, SaveFileContent { private WorldData data; - private Pixmap biomeImage, biomeImage2; + private Pixmap biomeImage; private long[][] biomeMap; private int[][] terrainMap; private int width; @@ -243,7 +243,6 @@ public class World implements Disposable, SaveFileContent { biomeMap = new long[width][height]; terrainMap= new int[width][height]; Pixmap pix = new Pixmap(width, height, Pixmap.Format.RGBA8888); - Pixmap pix2 = new Pixmap(width, height, Pixmap.Format.RGBA8888); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { @@ -291,8 +290,6 @@ public class World implements Disposable, SaveFileContent { color.fromHsv(hsv); pix.setColor(color.r, color.g, color.b, 1); pix.drawPixel(x, y); - pix2.setColor(color.r, color.g, color.b, 1); - pix2.drawPixel(x, y); biomeMap[x][y] |= (1L << biomeIndex); int terrainCounter=1; if(biome.terrain==null) @@ -480,7 +477,6 @@ public class World implements Disposable, SaveFileContent { } } biomeImage = pix; - biomeImage2 = pix2; return this;//new World(); } @@ -517,15 +513,6 @@ public class World implements Disposable, SaveFileContent { return biomeImage; } - public Pixmap getBiomeImage2() { - if (biomeImage2 == null) { - generateNew(0); - return biomeImage2; - } - return biomeImage2; - } - - public List> GetMapObjects(int chunkX, int chunkY) { return mapObjectIds.positions(chunkX, chunkY); } From 9e4ce0756e6519dcf610a42ee008ca0725148d0b Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sun, 27 Feb 2022 19:08:03 +0800 Subject: [PATCH 4/4] [Adventure] fix Map Stage Visibility - add Life, Money on Statistics - use ExtendViewport for MapStage - auto show/hide Map and GameHud controls for MapStage visibility - decrease Reward/Match delay for faster loading of scenes --- .../adventure/scene/PlayerStatisticScene.java | 22 +- .../src/forge/adventure/stage/GameHUD.java | 41 ++- .../src/forge/adventure/stage/GameStage.java | 123 ++++---- .../src/forge/adventure/stage/MapStage.java | 283 ++++++++---------- .../src/forge/adventure/stage/WorldStage.java | 7 +- forge-gui/res/adventure/Shandalar/ui/hud.json | 2 + .../adventure/Shandalar/ui/hud_mobile.json | 2 + forge-gui/res/adventure/Shandalar/ui/life.png | Bin 0 -> 1741 bytes .../res/adventure/Shandalar/ui/money.png | Bin 0 -> 1717 bytes .../res/adventure/Shandalar/ui/statistic.json | 38 ++- 10 files changed, 280 insertions(+), 238 deletions(-) create mode 100644 forge-gui/res/adventure/Shandalar/ui/life.png create mode 100644 forge-gui/res/adventure/Shandalar/ui/money.png diff --git a/forge-gui-mobile/src/forge/adventure/scene/PlayerStatisticScene.java b/forge-gui-mobile/src/forge/adventure/scene/PlayerStatisticScene.java index 9062073a3e3..a4e096dcd1c 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/PlayerStatisticScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/PlayerStatisticScene.java @@ -11,9 +11,11 @@ import forge.Forge; import forge.adventure.character.EnemySprite; import forge.adventure.data.EnemyData; import forge.adventure.data.WorldData; +import forge.adventure.player.AdventurePlayer; import forge.adventure.stage.GameHUD; import forge.adventure.util.Controls; import forge.adventure.util.Current; +import forge.adventure.world.WorldSave; import forge.player.GamePlayerUtil; import org.apache.commons.lang3.tuple.Pair; @@ -23,6 +25,7 @@ public class PlayerStatisticScene extends UIScene { Image avatar; + Label money, life; Label totalWins; Label totalLoss; Label lossWinRatio; @@ -71,6 +74,22 @@ public class PlayerStatisticScene extends UIScene { if (avatar != null) { avatar.setDrawable(new TextureRegionDrawable(Current.player().avatar())); } + if (life != null) { + AdventurePlayer.current().onLifeChange(new Runnable() { + @Override + public void run() { + life.setText(AdventurePlayer.current().getLife() + "/" + AdventurePlayer.current().getMaxLife()); + } + }); + } + if (money != null) { + WorldSave.getCurrentSave().getPlayer().onGoldChange(new Runnable() { + @Override + public void run() { + money.setText(String.valueOf(AdventurePlayer.current().getGold())); + } + }); + } if (totalWins != null) { totalWins.setText(Current.player().getStatistic().totalWins()); } @@ -112,7 +131,8 @@ public class PlayerStatisticScene extends UIScene { }); avatar = ui.findActor("avatar"); playerName = ui.findActor("playerName"); - + life = ui.findActor("lifePoints"); + money = ui.findActor("money"); totalWins = ui.findActor("totalWins"); totalLoss = ui.findActor("totalLoss"); lossWinRatio = ui.findActor("lossWinRatio"); diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java b/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java index 19a4fd5bd9f..0039ae87cf3 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java @@ -39,7 +39,7 @@ public class GameHUD extends Stage { private final Image miniMapPlayer; private final Label lifePoints; private final Label money; - private Image miniMap; + private Image miniMap, gamehud, mapborder, avatarborder; private TextButton deckActor, menuActor, statsActor; private boolean deckPressed = false; private boolean menuPressed = false; @@ -60,9 +60,12 @@ public class GameHUD extends Stage { ui = new UIActor(Config.instance().getFile(GuiBase.isAndroid() ? "ui/hud_mobile.json" : "ui/hud.json")); miniMap = ui.findActor("map"); + mapborder = ui.findActor("mapborder"); + avatarborder = ui.findActor("avatarborder"); deckActor = ui.findActor("deck"); menuActor = ui.findActor("menu"); statsActor = ui.findActor("statistic"); + gamehud = ui.findActor("gamehud"); miniMapPlayer = new Image(new Texture(Config.instance().getFile("ui/minimap_player.png"))); //create touchpad skin @@ -129,7 +132,6 @@ public class GameHUD extends Stage { money.setText(String.valueOf(AdventurePlayer.current().getGold())); } }) ; - miniMap = ui.findActor("map"); addActor(ui); addActor(miniMapPlayer); @@ -241,19 +243,19 @@ public class GameHUD extends Stage { return true; } - float uiX = ui.findActor("gamehud").getX(); - float uiY = ui.findActor("gamehud").getY(); - float uiTop = ui.findActor("gamehud").getTop(); - float uiRight = ui.findActor("gamehud").getRight(); + float uiX = gamehud.getX(); + float uiY = gamehud.getY(); + float uiTop = gamehud.getTop(); + float uiRight = gamehud.getRight(); //gamehud bounds if (c.x>=uiX&&c.x<=uiRight&&c.y>=uiY&&c.y<=uiTop) { return true; } - float mMapX = ui.findActor("map").getX(); - float mMapY = ui.findActor("map").getY(); - float mMapT = ui.findActor("map").getTop(); - float mMapR = ui.findActor("map").getRight(); + float mMapX = miniMap.getX(); + float mMapY = miniMap.getY(); + float mMapT = miniMap.getTop(); + float mMapR = miniMap.getRight(); //map bounds if (c.x>=mMapX&&c.x<=mMapR&&c.y>=mMapY&&c.y<=mMapT) { if (MapStage.getInstance().isInMap()) @@ -333,4 +335,23 @@ public class GameHUD extends Stage { private void menu() { gameStage.openMenu(); } + public void showHideMap(boolean visible) { + miniMap.setVisible(visible); + mapborder.setVisible(visible); + miniMapPlayer.setVisible(visible); + avatarborder.setVisible(visible); + avatar.setVisible(visible); + lifePoints.setVisible(visible); + money.setVisible(visible); + gamehud.setVisible(visible); + if (visible) { + deckActor.getColor().a = 1f; + menuActor.getColor().a = 1f; + statsActor.getColor().a = 1f; + } else { + deckActor.getColor().a = 0.5f; + menuActor.getColor().a = 0.5f; + statsActor.getColor().a = 0.5f; + } + } } diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java index 7a78f2cd73b..0f22a9041a7 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java @@ -7,7 +7,7 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Group; import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.utils.viewport.StretchViewport; +import com.badlogic.gdx.utils.viewport.ExtendViewport; import forge.Forge; import forge.adventure.character.MapActor; import forge.adventure.character.PlayerSprite; @@ -33,20 +33,22 @@ public abstract class GameStage extends Stage { private final float timer = 0; private float animationTimeout = 0; - public void startPause(int i) { - startPause(i,null); + public void startPause(float i) { + startPause(i, null); } - public void startPause(int i,Runnable runnable) { - onEndAction=runnable; - animationTimeout=i; + + public void startPause(float i, Runnable runnable) { + onEndAction = runnable; + animationTimeout = i; player.setMovementDirection(Vector2.Zero); } + public boolean isPaused() { - return animationTimeout>0; + return animationTimeout > 0; } public GameStage() { - super(new StretchViewport(Scene.GetIntendedWidth(), Scene.GetIntendedHeight(), new OrthographicCamera())); + super(new ExtendViewport(Scene.GetIntendedWidth(), Scene.GetIntendedHeight(), new OrthographicCamera())); WorldSave.getCurrentSave().onLoad(new Runnable() { @Override public void run() { @@ -71,6 +73,7 @@ public abstract class GameStage extends Stage { public void setWinner(boolean b) { } + public void setBounds(float width, float height) { getViewport().setWorldSize(width, height); } @@ -93,9 +96,8 @@ public abstract class GameStage extends Stage { } + Runnable onEndAction; - - Runnable onEndAction; @Override public final void act(float delta) { super.act(delta); @@ -104,17 +106,15 @@ public abstract class GameStage extends Stage { animationTimeout -= delta; return; } - if(isPaused()) - { + if (isPaused()) { return; } - if (onEndAction != null) { onEndAction.run(); - onEndAction=null; + onEndAction = null; } if (touchX >= 0) { @@ -139,14 +139,12 @@ public abstract class GameStage extends Stage { camera.position.y = Math.min(Math.max(Scene.GetIntendedHeight() / 2f, player.pos().y), getViewport().getWorldHeight() - Scene.GetIntendedHeight() / 2f); - onActing(delta); } abstract protected void onActing(float delta); - @Override public boolean keyDown(int keycode) { super.keyDown(keycode); @@ -168,8 +166,7 @@ public abstract class GameStage extends Stage { } if (keycode == Input.Keys.F5)//todo config { - if(!((TileMapScene)SceneType.TileMapScene.instance).currentMap().isInMap()) - { + if (!((TileMapScene) SceneType.TileMapScene.instance).currentMap().isInMap()) { GetPlayer().storePos(); WorldSave.getCurrentSave().header.createPreview(); WorldSave.getCurrentSave().quickSave(); @@ -178,38 +175,33 @@ public abstract class GameStage extends Stage { } if (keycode == Input.Keys.F8)//todo config { - if(!((TileMapScene)SceneType.TileMapScene.instance).currentMap().isInMap()) - { + if (!((TileMapScene) SceneType.TileMapScene.instance).currentMap().isInMap()) { WorldSave.getCurrentSave().quickLoad(); enter(); } } - if (keycode == Input.Keys.F12) - { + if (keycode == Input.Keys.F12) { debugCollision(true); for (Actor actor : foregroundSprites.getChildren()) { if (actor instanceof MapActor) { - ((MapActor)actor).setBoundDebug(true); + ((MapActor) actor).setBoundDebug(true); } } player.setBoundDebug(true); } - if (keycode == Input.Keys.F11) - { + if (keycode == Input.Keys.F11) { debugCollision(false); for (Actor actor : foregroundSprites.getChildren()) { if (actor instanceof MapActor) { - ((MapActor)actor).setBoundDebug(false); + ((MapActor) actor).setBoundDebug(false); } } player.setBoundDebug(false); } - if (keycode == Input.Keys.F10) - { + if (keycode == Input.Keys.F10) { setDebugAll(true); } - if (keycode == Input.Keys.F9) - { + if (keycode == Input.Keys.F9) { setDebugAll(false); } return true; @@ -220,7 +212,7 @@ public abstract class GameStage extends Stage { @Override public boolean scrolled(float amountX, float amountY) { - if(isPaused()) + if (isPaused()) return true; camera.zoom += (amountY * 0.03); if (camera.zoom < 0.2f) @@ -232,7 +224,7 @@ public abstract class GameStage extends Stage { @Override public boolean touchDragged(int screenX, int screenY, int pointer) { - if(isPaused()) + if (isPaused()) return true; if (!GuiBase.isAndroid()) { touchX = screenX; @@ -244,7 +236,7 @@ public abstract class GameStage extends Stage { @Override public boolean touchDown(int screenX, int screenY, int pointer, int button) { - if(isPaused()) + if (isPaused()) return true; if (!GuiBase.isAndroid()) { touchX = screenX; @@ -262,6 +254,7 @@ public abstract class GameStage extends Stage { touchY = -1; player.stop(); } + @Override public boolean touchUp(int screenX, int screenY, int pointer, int button) { stop(); @@ -270,18 +263,18 @@ public abstract class GameStage extends Stage { @Override public boolean keyUp(int keycode) { - if(isPaused()) + if (isPaused()) return true; if (keycode == Input.Keys.LEFT || keycode == Input.Keys.A || keycode == Input.Keys.RIGHT || keycode == Input.Keys.D)//todo config { player.getMovementDirection().x = 0; - if(!player.isMoving()) + if (!player.isMoving()) stop(); } if (keycode == Input.Keys.UP || keycode == Input.Keys.W || keycode == Input.Keys.DOWN || keycode == Input.Keys.S)//todo config { player.getMovementDirection().y = 0; - if(!player.isMoving()) + if (!player.isMoving()) stop(); } if (keycode == Input.Keys.ESCAPE) { @@ -304,56 +297,50 @@ public abstract class GameStage extends Stage { stop(); } - public boolean isColliding(Rectangle boundingRect) - { + public boolean isColliding(Rectangle boundingRect) { return false; } - public void prepareCollision(Vector2 pos, Vector2 direction, Rectangle boundingRect) - { + + public void prepareCollision(Vector2 pos, Vector2 direction, Rectangle boundingRect) { } - public Vector2 adjustMovement( Vector2 direction, Rectangle boundingRect) - { - Vector2 adjDirX=direction.cpy(); - Vector2 adjDirY=direction.cpy(); - boolean foundX=false; - boolean foundY=false; - while(true) - { + public Vector2 adjustMovement(Vector2 direction, Rectangle boundingRect) { + Vector2 adjDirX = direction.cpy(); + Vector2 adjDirY = direction.cpy(); + boolean foundX = false; + boolean foundY = false; + while (true) { - if(!isColliding(new Rectangle(boundingRect.x+adjDirX.x,boundingRect.y+adjDirX.y, boundingRect.width, boundingRect.height))) - { - foundX=true; + if (!isColliding(new Rectangle(boundingRect.x + adjDirX.x, boundingRect.y + adjDirX.y, boundingRect.width, boundingRect.height))) { + foundX = true; break; } - if(adjDirX.x==0) + if (adjDirX.x == 0) break; - if(adjDirX.x>=0) - adjDirX.x=Math.round(Math.max(0,adjDirX.x-1)); + if (adjDirX.x >= 0) + adjDirX.x = Math.round(Math.max(0, adjDirX.x - 1)); else - adjDirX.x=Math.round(Math.max(0,adjDirX.x+1)); + adjDirX.x = Math.round(Math.max(0, adjDirX.x + 1)); } - while(true) - { - if(!isColliding(new Rectangle(boundingRect.x+adjDirY.x,boundingRect.y+adjDirY.y, boundingRect.width, boundingRect.height))) - { - foundY=true; + while (true) { + if (!isColliding(new Rectangle(boundingRect.x + adjDirY.x, boundingRect.y + adjDirY.y, boundingRect.width, boundingRect.height))) { + foundY = true; break; } - if(adjDirY.y==0) + if (adjDirY.y == 0) break; - if(adjDirY.y>=0) - adjDirY.y=Math.round(Math.max(0,adjDirY.y-1)); + if (adjDirY.y >= 0) + adjDirY.y = Math.round(Math.max(0, adjDirY.y - 1)); else - adjDirY.y=Math.round(Math.max(0,adjDirY.y+1)); + adjDirY.y = Math.round(Math.max(0, adjDirY.y + 1)); } - if(foundY&&foundX) - return adjDirX.len()>adjDirY.len()?adjDirX:adjDirY; - else if(foundY) + if (foundY && foundX) + return adjDirX.len() > adjDirY.len() ? adjDirX : adjDirY; + else if (foundY) return adjDirY; - else if(foundX) + else if (foundX) return adjDirX; return Vector2.Zero.cpy(); } diff --git a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java index 15938568c16..049bee7fada 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java @@ -2,6 +2,7 @@ package forge.adventure.stage; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.maps.MapLayer; import com.badlogic.gdx.maps.MapObject; import com.badlogic.gdx.maps.MapProperties; @@ -27,6 +28,7 @@ import forge.adventure.data.WorldData; import forge.adventure.pointofintrest.PointOfInterestChanges; import forge.adventure.scene.DuelScene; import forge.adventure.scene.RewardScene; +import forge.adventure.scene.Scene; import forge.adventure.scene.SceneType; import forge.adventure.util.Config; import forge.adventure.util.Current; @@ -54,28 +56,30 @@ public class MapStage extends GameStage { private float tileWidth; private float width; private float height; - private boolean isInMap=false; + private boolean isInMap = false; MapLayer spriteLayer; private PointOfInterestChanges changes; private EnemySprite currentMob; - private final Vector2 oldPosition=new Vector2();//todo - private final Vector2 oldPosition2=new Vector2(); - private final Vector2 oldPosition3=new Vector2(); - private final Vector2 oldPosition4=new Vector2(); + private final Vector2 oldPosition = new Vector2();//todo + private final Vector2 oldPosition2 = new Vector2(); + private final Vector2 oldPosition3 = new Vector2(); + private final Vector2 oldPosition4 = new Vector2(); + private boolean isLoadingMatch = false; public void clearIsInMap() { isInMap = false; + GameHUD.getInstance().showHideMap(true); } - public MapLayer getSpriteLayer() - { + public MapLayer getSpriteLayer() { return spriteLayer; } - public PointOfInterestChanges getChanges() - { + + public PointOfInterestChanges getChanges() { return changes; } + public static MapStage getInstance() { return instance == null ? instance = new MapStage() : instance; } @@ -88,39 +92,36 @@ public class MapStage extends GameStage { actors.add(newActor); foregroundSprites.addActor(newActor); } + public void addMapActor(MapActor newActor) { actors.add(newActor); foregroundSprites.addActor(newActor); } + @Override - public boolean isColliding( Rectangle adjustedBoundingRect) - { - for(Rectangle collision:currentCollidingRectangles) - { - if(collision.overlaps(adjustedBoundingRect)) - { + public boolean isColliding(Rectangle adjustedBoundingRect) { + for (Rectangle collision : currentCollidingRectangles) { + if (collision.overlaps(adjustedBoundingRect)) { return true; } } return false; } - final ArrayList currentCollidingRectangles=new ArrayList<>(); - @Override - public void prepareCollision(Vector2 pos, Vector2 direction, Rectangle boundingRect) - { - currentCollidingRectangles.clear(); - int x1= (int) (Math.min(boundingRect.x,boundingRect.x+direction.x)/tileWidth); - int y1= (int) (Math.min(boundingRect.y,boundingRect.y+direction.y)/tileHeight); - int x2= (int) (Math.min(boundingRect.x+boundingRect.width,boundingRect.x+boundingRect.width+direction.x)/tileWidth); - int y2= (int) (Math.min(boundingRect.y+boundingRect.height,boundingRect.y+boundingRect.height+direction.y)/tileHeight); - for(int x=x1;x<=x2;x++) - { - for(int y=y1;y<=y2;y++) - { - if(x<0||x>=width||y<0||y>=height) - { + final ArrayList currentCollidingRectangles = new ArrayList<>(); + + @Override + public void prepareCollision(Vector2 pos, Vector2 direction, Rectangle boundingRect) { + currentCollidingRectangles.clear(); + int x1 = (int) (Math.min(boundingRect.x, boundingRect.x + direction.x) / tileWidth); + int y1 = (int) (Math.min(boundingRect.y, boundingRect.y + direction.y) / tileHeight); + int x2 = (int) (Math.min(boundingRect.x + boundingRect.width, boundingRect.x + boundingRect.width + direction.x) / tileWidth); + int y2 = (int) (Math.min(boundingRect.y + boundingRect.height, boundingRect.y + boundingRect.height + direction.y) / tileHeight); + + for (int x = x1; x <= x2; x++) { + for (int y = y1; y <= y2; y++) { + if (x < 0 || x >= width || y < 0 || y >= height) { continue; } currentCollidingRectangles.addAll(collision[x][y]); @@ -130,20 +131,17 @@ public class MapStage extends GameStage { Group collisionGroup; + @Override protected void debugCollision(boolean b) { - if(collisionGroup==null) - { - collisionGroup=new Group(); + if (collisionGroup == null) { + collisionGroup = new Group(); - for (int x = 0; x < collision.length; x++) - { - for (int y = 0; y < collision[x].length; y++) - { - for(Rectangle rectangle:collision[x][y]) - { - MapActor collisionActor=new MapActor(); + for (int x = 0; x < collision.length; x++) { + for (int y = 0; y < collision[x].length; y++) { + for (Rectangle rectangle : collision[x][y]) { + MapActor collisionActor = new MapActor(); collisionActor.setBoundDebug(true); collisionActor.setWidth(rectangle.width); collisionActor.setHeight(rectangle.height); @@ -155,98 +153,88 @@ public class MapStage extends GameStage { } } - if(b) - { + if (b) { addActor(collisionGroup); - } - else - { + } else { collisionGroup.remove(); } } - public void loadMap(TiledMap map,String sourceMap) { - isInMap=true; - this.map=map; + public void loadMap(TiledMap map, String sourceMap) { + isLoadingMatch = false; + isInMap = true; + GameHUD.getInstance().showHideMap(false); + this.map = map; 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()); - tileHeight = Float.parseFloat(map.getProperties().get("tileheight").toString()); - tileWidth = Float.parseFloat(map.getProperties().get("tilewidth").toString()); + actors = new Array<>(); + width = Float.parseFloat(map.getProperties().get("width").toString()); + height = Float.parseFloat(map.getProperties().get("height").toString()); + tileHeight = Float.parseFloat(map.getProperties().get("tileheight").toString()); + tileWidth = Float.parseFloat(map.getProperties().get("tilewidth").toString()); setBounds(width * tileWidth, height * tileHeight); - collision= new ArrayList[(int) width][(int) height]; + collision = new ArrayList[(int) width][(int) height]; GetPlayer().stop(); - for(MapLayer layer: map.getLayers()) - { - if(layer.getProperties().containsKey("spriteLayer")&&layer.getProperties().get("spriteLayer",boolean.class)) - { - spriteLayer=layer; + for (MapLayer layer : map.getLayers()) { + if (layer.getProperties().containsKey("spriteLayer") && layer.getProperties().get("spriteLayer", boolean.class)) { + spriteLayer = layer; } - if(layer instanceof TiledMapTileLayer) - { - loadCollision((TiledMapTileLayer)layer); - } - else - { - loadObjects(layer,sourceMap); + if (layer instanceof TiledMapTileLayer) { + loadCollision((TiledMapTileLayer) layer); + } else { + loadObjects(layer, sourceMap); } } } private void loadCollision(TiledMapTileLayer layer) { - for(int x=0;x(); - ArrayList map=collision[x][y]; - TiledMapTileLayer.Cell cell=layer.getCell(x,y); - if(cell==null) + for (int x = 0; x < layer.getWidth(); x++) { + for (int y = 0; y < layer.getHeight(); y++) { + if (collision[x][y] == null) + collision[x][y] = new ArrayList<>(); + ArrayList map = collision[x][y]; + TiledMapTileLayer.Cell cell = layer.getCell(x, y); + if (cell == null) continue; - for(MapObject collision:cell.getTile().getObjects()) - { - if(collision instanceof RectangleMapObject) - { - Rectangle r=((RectangleMapObject)collision).getRectangle(); - map.add(new Rectangle((Math.round(layer.getTileWidth()*x)+r.x),(Math.round(layer.getTileHeight()*y)+r.y),Math.round(r.width),Math.round(r.height))); + for (MapObject collision : cell.getTile().getObjects()) { + if (collision instanceof RectangleMapObject) { + Rectangle r = ((RectangleMapObject) collision).getRectangle(); + map.add(new Rectangle((Math.round(layer.getTileWidth() * x) + r.x), (Math.round(layer.getTileHeight() * y) + r.y), Math.round(r.width), Math.round(r.height))); } } } } } - private void loadObjects(MapLayer layer,String sourceMap) { + private void loadObjects(MapLayer layer, String sourceMap) { player.setMoveModifier(2); for (MapObject obj : layer.getObjects()) { - MapProperties prop=obj.getProperties(); + MapProperties prop = obj.getProperties(); Object typeObject = prop.get("type"); if (typeObject != null) { - String type = prop.get("type",String.class); - int id = prop.get("id",int.class); - if(changes.isObjectDeleted(id)) + String type = prop.get("type", String.class); + int id = prop.get("id", int.class); + if (changes.isObjectDeleted(id)) continue; switch (type) { case "entry": - float x=Float.parseFloat(prop.get("x").toString()); - float y=Float.parseFloat(prop.get("y").toString()); - float w=Float.parseFloat(prop.get("width").toString()); - float h=Float.parseFloat(prop.get("height").toString()); - EntryActor entry=new EntryActor(this,sourceMap,id,prop.get("teleport").toString(),x,y,w,h,prop.get("direction").toString()); + float x = Float.parseFloat(prop.get("x").toString()); + float y = Float.parseFloat(prop.get("y").toString()); + float w = Float.parseFloat(prop.get("width").toString()); + float h = Float.parseFloat(prop.get("height").toString()); + EntryActor entry = new EntryActor(this, sourceMap, id, prop.get("teleport").toString(), x, y, w, h, prop.get("direction").toString()); addMapActor(obj, entry); break; case "enemy": - EnemySprite mob=new EnemySprite(id, WorldData.getEnemy(prop.get("enemy").toString())); + EnemySprite mob = new EnemySprite(id, WorldData.getEnemy(prop.get("enemy").toString())); addMapActor(obj, mob); break; case "inn": @@ -266,44 +254,37 @@ public class MapStage extends GameStage { })); break; case "shop": - String shopList=prop.get("shopList").toString(); - List possibleShops=Arrays.asList(shopList.split(",")); + String shopList = prop.get("shopList").toString(); + List possibleShops = Arrays.asList(shopList.split(",")); Array shops; - if(possibleShops.size()==0||shopList.equals("")) - shops= WorldData.getShopList(); - else - { - shops=new Array<>(); - for(ShopData data:new Array.ArrayIterator<>(WorldData.getShopList())) - { - if(possibleShops.contains(data.name)) - { + if (possibleShops.size() == 0 || shopList.equals("")) + shops = WorldData.getShopList(); + else { + shops = new Array<>(); + for (ShopData data : new Array.ArrayIterator<>(WorldData.getShopList())) { + if (possibleShops.contains(data.name)) { shops.add(data); } } } - if(shops.size==0) + if (shops.size == 0) continue; - ShopData data=shops.get(WorldSave.getCurrentSave().getWorld().getRandom().nextInt(shops.size)); - Array ret=new Array(); - for(RewardData rdata:new Array.ArrayIterator<>(data.rewards)) - { + ShopData data = shops.get(WorldSave.getCurrentSave().getWorld().getRandom().nextInt(shops.size)); + Array ret = new Array(); + for (RewardData rdata : new Array.ArrayIterator<>(data.rewards)) { ret.addAll(rdata.generate(false)); } - ShopActor actor=new ShopActor(this,id,ret); - addMapActor(obj,actor); - if(prop.containsKey("signYOffset")&&prop.containsKey("signXOffset")) - { + ShopActor actor = new ShopActor(this, id, ret); + addMapActor(obj, actor); + if (prop.containsKey("signYOffset") && prop.containsKey("signXOffset")) { try { - TextureSprite sprite=new TextureSprite(Config.instance().getAtlas(data.spriteAtlas).createSprite(data.sprite)); - sprite.setX(actor.getX()+Float.parseFloat(prop.get("signXOffset").toString())); - sprite.setY(actor.getY()+Float.parseFloat(prop.get("signYOffset").toString())); + TextureSprite sprite = new TextureSprite(Config.instance().getAtlas(data.spriteAtlas).createSprite(data.sprite)); + sprite.setX(actor.getX() + Float.parseFloat(prop.get("signXOffset").toString())); + sprite.setY(actor.getY() + Float.parseFloat(prop.get("signYOffset").toString())); addMapActor(sprite); - } - catch (Exception e) - { - System.err.print("Can not create Texture for "+data.sprite+" Obj:"+data); + } catch (Exception e) { + System.err.print("Can not create Texture for " + data.sprite + " Obj:" + data); } } break; @@ -313,21 +294,20 @@ public class MapStage extends GameStage { } public boolean exit() { - - isInMap=false; + isLoadingMatch = false; + clearIsInMap(); Forge.switchScene(SceneType.GameScene.instance); return true; } - @Override public void setWinner(boolean playerWins) { - + isLoadingMatch = false; if (playerWins) { player.setAnimation(CharacterSprite.AnimationTypes.Attack); currentMob.setAnimation(CharacterSprite.AnimationTypes.Death); - startPause(1, new Runnable() { + startPause(0.3f, new Runnable() { @Override public void run() { MapStage.this.getReward(); @@ -336,10 +316,9 @@ public class MapStage extends GameStage { } else { player.setAnimation(CharacterSprite.AnimationTypes.Hit); currentMob.setAnimation(CharacterSprite.AnimationTypes.Attack); - startPause(1, new Runnable() { + startPause(0.5f, new Runnable() { @Override public void run() { - player.setAnimation(CharacterSprite.AnimationTypes.Idle); currentMob.setAnimation(CharacterSprite.AnimationTypes.Idle); player.setPosition(oldPosition4); @@ -353,53 +332,53 @@ public class MapStage extends GameStage { } - protected void getReward() - { - ((RewardScene)SceneType.RewardScene.instance).loadRewards(currentMob.getRewards(), RewardScene.Type.Loot, null); + protected void getReward() { + isLoadingMatch = false; + ((RewardScene) SceneType.RewardScene.instance).loadRewards(currentMob.getRewards(), RewardScene.Type.Loot, null); currentMob.remove(); - actors.removeValue(currentMob,true); + actors.removeValue(currentMob, true); changes.deleteObject(currentMob.getId()); currentMob = null; - Gdx.input.vibrate(50); Forge.switchScene(SceneType.RewardScene.instance); } + @Override protected void onActing(float delta) { - oldPosition4.set(oldPosition3); oldPosition3.set(oldPosition2); oldPosition2.set(oldPosition); oldPosition.set(player.pos()); for (MapActor actor : new Array.ArrayIterator<>(actors)) { if (actor.collideWithPlayer(player)) { - if(actor instanceof EnemySprite) - { - EnemySprite mob=(EnemySprite) actor; - currentMob=mob; - if(mob.getData().deck==null||mob.getData().deck.isEmpty()) - { + if (actor instanceof EnemySprite) { + EnemySprite mob = (EnemySprite) actor; + currentMob = mob; + if (mob.getData().deck == null || mob.getData().deck.isEmpty()) { currentMob.setAnimation(CharacterSprite.AnimationTypes.Death); - startPause(1, new Runnable() { + Gdx.input.vibrate(50); + startPause(0.3f, new Runnable() { @Override public void run() { MapStage.this.getReward(); } }); - } - else - { + break; + } else { player.setAnimation(CharacterSprite.AnimationTypes.Attack); mob.setAnimation(CharacterSprite.AnimationTypes.Attack); Gdx.input.vibrate(50); Forge.setCursor(null, Forge.magnifyToggle ? "1" : "2"); SoundSystem.instance.play(SoundEffectType.ManaBurn, false); - Forge.setTransitionScreen(new TransitionScreen(new Runnable() { - @Override - public void run() { - Forge.clearTransitionScreen(); - } - }, ScreenUtils.getFrameBufferTexture(), true, false)); - startPause(1, new Runnable() { + if (!isLoadingMatch) { + isLoadingMatch = true; + Forge.setTransitionScreen(new TransitionScreen(new Runnable() { + @Override + public void run() { + Forge.clearTransitionScreen(); + } + }, ScreenUtils.getFrameBufferTexture(), true, false)); + } + startPause(0.5f, new Runnable() { @Override public void run() { ((DuelScene) SceneType.DuelScene.instance).setEnemy(mob); @@ -407,18 +386,16 @@ public class MapStage extends GameStage { Forge.switchScene(SceneType.DuelScene.instance); } }); + break; } - } - } } } public void setPointOfInterest(PointOfInterestChanges change) { - - changes =change; + changes = change; } public boolean isInMap() { diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index 0e91384fcdc..b99cbfdc226 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -90,7 +90,7 @@ public class WorldStage extends GameStage implements SaveFileContent { Forge.clearTransitionScreen(); } }, ScreenUtils.getFrameBufferTexture(), true, false)); - startPause(1, new Runnable() { + startPause(0.5f, new Runnable() { @Override public void run() { ((DuelScene) SceneType.DuelScene.instance).setEnemy(currentMob); @@ -129,20 +129,19 @@ public class WorldStage extends GameStage implements SaveFileContent { if (playerIsWinner) { player.setAnimation(CharacterSprite.AnimationTypes.Attack); currentMob.setAnimation(CharacterSprite.AnimationTypes.Death); - startPause(1, new Runnable() { + startPause(0.5f, new Runnable() { @Override public void run() { ((RewardScene) SceneType.RewardScene.instance).loadRewards(currentMob.getRewards(), RewardScene.Type.Loot, null); WorldStage.this.removeEnemy(currentMob); currentMob = null; - Gdx.input.vibrate(50); Forge.switchScene(SceneType.RewardScene.instance); } }); } else { player.setAnimation(CharacterSprite.AnimationTypes.Hit); currentMob.setAnimation(CharacterSprite.AnimationTypes.Attack); - startPause(1, new Runnable() { + startPause(0.5f, new Runnable() { @Override public void run() { Current.player().defeated(); diff --git a/forge-gui/res/adventure/Shandalar/ui/hud.json b/forge-gui/res/adventure/Shandalar/ui/hud.json index 7c857877c3c..1e50ae4e76c 100644 --- a/forge-gui/res/adventure/Shandalar/ui/hud.json +++ b/forge-gui/res/adventure/Shandalar/ui/hud.json @@ -22,6 +22,7 @@ }, { "type": "Image", + "name": "mapborder", "image": "ui/minimap.png", "width": 64, "height": 64, @@ -38,6 +39,7 @@ }, { "type": "Image", + "name": "avatarborder", "image": "ui/avatarhud.png", "width": 32, "height": 32, diff --git a/forge-gui/res/adventure/Shandalar/ui/hud_mobile.json b/forge-gui/res/adventure/Shandalar/ui/hud_mobile.json index 241a554b0ae..232faff6fbe 100644 --- a/forge-gui/res/adventure/Shandalar/ui/hud_mobile.json +++ b/forge-gui/res/adventure/Shandalar/ui/hud_mobile.json @@ -22,6 +22,7 @@ }, { "type": "Image", + "name": "mapborder", "image": "ui/minimap.png", "width": 80, "height": 80, @@ -38,6 +39,7 @@ }, { "type": "Image", + "name": "avatarborder", "image": "ui/avatarhud.png", "width": 46, "height": 46, diff --git a/forge-gui/res/adventure/Shandalar/ui/life.png b/forge-gui/res/adventure/Shandalar/ui/life.png new file mode 100644 index 0000000000000000000000000000000000000000..a3d32df77afa6dcd8f9eb401d6abdd5f932d5077 GIT binary patch literal 1741 zcmcIlO^Do79M3ZDGHqvJih|SjV9cVpXeKYoWb$Ft?RIB%N6dEJj&^$~ee>R%nXr?* zm}GWl*NfC1R#;JrhbnXOuoe^%J$mSZ2p-f+K@mJCdJ#kqiilLkm-(_tyY9unOWw=- zz2E=$|HwZtuPi?~efaocj^n1wOQluz%qAl}#qJOM+Jo$IC|J4>aomx6lQF@)+0Aj> zQN(5<|Y@HT}ry*g~JzV)Nv+B=CJmylxBgi9vqNS>YFG zNcdtNhzJ0M*Uh|KET~2B7_R^YNI;QfRRppHbW2hA;UzF@A+A}gr6-2A*vb|faU58Z z)NZ%)Z8cBBx+I&XnQ$nI$Pi+*>Bq1m`q9jYp+q7SxYjnPrOxWTLp_1=*CS|t%}g@`O}5I>$78N+CN zHfV*-zNZ*Tq)9vmiC{ZgT7G7cG{3GXG zAJcX;nZC@?Gl22h990fsR=7?@(Wws{b!<5*=s zilL84xnv7WRNi&5rPpxLAetuXx~Yh&R!~F(m_)<{6BRY20v#HCUF>{`qE-^V!_HC{~R^RfHHJ(U3JAL7-s_m@15{8VxcsV6ok)RS7x;hFEYKzm9g11Z)ufsk zJM&`6jace7hu_CJ^89etboqYKSr8?)ZVM<$GQq;|wR?x?9Zctdw%s6%bf4r8U=gjw zZ5WdII*asw7MFB4@e$nEU;4ok|369}h7~oSUni__N%+2&$Ft>Y*=JuMY*)LX}y>epv-8ZhEzVh|2O)`n2y%=foHKasn*M;?D>>f7+)2UFawQ?nlg_htS{emLdD L<J``UXQ>B%5Hj_y%*@Romc{#lmb1v7#JMpEnGqbzlHkn+K zyWPE~qM-O7iftd%gDQ#-MaANSqQ!dH2YnE%Ac6;izK9@NP&l8|$$nX+J@3W9Br}=c z{QkfHNB()XH2=`}$Xz3nB#js6+y(KR$i{*F;(qwIzp!`=M{|!Sk~DfS8$;5|8;2xm z-)DY#DP8g&aR?7`nDPqCwSq{XC28tpE5c-%rE-PU{IH<>`q33d_Gv*`ob;d<&9J&Z zw;r=o>+@x@zD#VYoV;J2YB_=+U@4YcK_g6@Rzd0TI%1x^Ru#DeNtX-CbY@Uq@=Edy zkC|-dARrJT*|Kw*Y3L?AAtQ*O3X!Vm0BR1j9E9ZFr3h;=tvUW5gA{nidqHwCh3;4QRup z7bX!fwS^;9%fZa0KG5@ah6cd^ouspC!b(r?O^K6oJ7VerOZaL`*z6h$(<6Ojlnl;B zt8t^_DJ3dvut2~PAxs;Xit0S&NuA%qkHPl9o5-1o8BTdz=Dg8QRH@G*BS9`7Tl7Q9 zo5_8dqTT`K;*=E>ku?M$0>~r_w#V|>6 zNLbM=C_+@u_o)LlM08v+0Mn5P^15LFY*oe0gr6G$J{60kN2+Z`Eg=#W%Rb_;9|7z z%AKP}e|qWl;BNWe_VzvFulm2Y5Cgi7q-q_Jn+3c_Sn$ntL)Hw zeE1AH`b%=*{OG%%Z!8(5Z#PbipIbXSwEyRcx2B#N+p~A;4HIu3zN(jAdExnyiDRhr r_8;5FKREp=0v|sdUjO8aXEyHu+so#kUv6H`ek{e=dH0