From f5e062d06deeb1711f53ca0806209a5a0a88da80 Mon Sep 17 00:00:00 2001 From: jjayers99 <56438137+jjayers99@users.noreply.github.com> Date: Wed, 10 May 2023 23:55:55 -0400 Subject: [PATCH] Adventure mode content Preview release of Liliana dungeon Autosave when entering POI Improved POI enemy pathing (slightly) Addition of Portal mechanics Rework of Death Ring Increased land quantity in basic land shops Removed problematic objective from quest "(Almost) Open for Business" --- forge-gui-mobile/src/forge/Forge.java | 7 + .../adventure/character/CharacterSprite.java | 20 +- .../adventure/character/DialogActor.java | 6 +- .../adventure/character/EnemySprite.java | 20 +- .../forge/adventure/character/EntryActor.java | 29 +- .../adventure/character/PortalActor.java | 183 + .../src/forge/adventure/data/DialogData.java | 2 + .../forge/adventure/scene/TileMapScene.java | 13 +- .../src/forge/adventure/stage/MapStage.java | 192 +- .../stage/PointOfInterestMapRenderer.java | 4 +- .../src/forge/adventure/stage/WorldStage.java | 1 + .../src/forge/adventure/util/MapDialog.java | 8 +- .../Death Ring.fullborder.jpg | Bin 0 -> 575472 bytes .../Shandalar/custom_card_pics/Death Ring.png | Bin 0 -> 2803848 bytes .../Demonic Contract.fullborder.jpg | Bin 0 -> 617456 bytes .../Pack Alpha.fullborder.jpg | Bin 98399 -> 737511 bytes .../Waker of the Dead.fullborder.jpg | Bin 0 -> 677129 bytes .../Shandalar/custom_cards/death_ring.txt | 8 + .../custom_cards/demonic_contract.txt | 10 + .../Shandalar/custom_cards/pack_alpha.txt | 3 +- .../custom_cards/waker_of_the_dead.txt | 58 + .../Shandalar/decks/cleric_orzhov.dck | 21 + .../adventure/Shandalar/decks/dark_spirit.dck | 27 + .../Shandalar/decks/dimir_faerie.dck | 29 + .../adventure/Shandalar/decks/dimir_ninja.dck | 26 + .../Shandalar/decks/dimir_poison.dck | 30 + .../adventure/Shandalar/decks/elf_golgari.dck | 31 + .../Shandalar/decks/fungus_golgari.dck | 26 + .../adventure/Shandalar/decks/golgari_elf.dck | 31 + .../Shandalar/decks/golgari_treefolk.dck | 24 + .../Shandalar/decks/lilianas_herbalist.dck | 27 + .../miniboss/angel_rainbow_encounter.dck | 52 + .../Shandalar/decks/miniboss/liliana.dck | 23 + .../decks/miniboss/liliana_zombies.dck | 38 + .../Shandalar/decks/rakdos_vamps.dck | 37 + .../Shandalar/decks/skeleton_champion.dck | 25 + .../Shandalar/decks/sliver_black.dck | 35 + .../Shandalar/decks/treefolk_golgari.dck | 24 + .../Shandalar/decks/zombie_greater.dck | 25 + .../Shandalar/maps/main.tiled-project | 3 +- .../Shandalar/maps/map/debug_map.tmx | 14 +- .../adventure/Shandalar/maps/map/dig_site.tmx | 45 + .../Shandalar/maps/map/dig_site_2.tmx | 112 + .../Shandalar/maps/map/dig_site_3.tmx | 52 + .../map/main_story/temple_of_liliana/bog.tmx | 611 +++ .../main_story/temple_of_liliana/forest.tmx | 483 +++ .../temple_of_liliana/graveyard.tmx | 560 +++ .../map/main_story/temple_of_liliana/keep.tmx | 198 + .../map/main_story/temple_of_liliana/town.tmx | 2142 +++++++++++ .../maps/map/main_story/templeofchandra.tmx | 16 +- .../maps/map/main_story/templeofliliana.tmx | 328 -- .../maps/map/plains_town_generic.tmx | 21 +- .../maps/map/plains_town_identity.tmx | 21 +- .../Shandalar/maps/map/plains_town_tribal.tmx | 21 +- .../adventure/Shandalar/maps/obj/dialog.tx | 10 + .../res/adventure/Shandalar/maps/obj/enemy.tx | 4 + .../Shandalar/maps/obj/entry_right.tx | 4 +- .../adventure/Shandalar/maps/obj/portal.tx | 13 + .../Shandalar/maps/tileset/FarmFood.tsx | 65 + .../Shandalar/maps/tileset/buildings.atlas | 3 + .../Shandalar/maps/tileset/buildings.tsx | 24 +- .../Shandalar/maps/tileset/main-nocollide.tsx | 4 + .../adventure/Shandalar/maps/tileset/main.tsx | 3342 +++++++++++++++-- .../Shandalar/sprites/cleric_orzhov.atlas | 68 + .../Shandalar/sprites/cleric_orzhov.png | Bin 0 -> 17874 bytes .../Shandalar/sprites/dimir_wiz.atlas | 68 + .../adventure/Shandalar/sprites/dimir_wiz.png | Bin 0 -> 16588 bytes .../Shandalar/sprites/elf_golgari.atlas | 68 + .../Shandalar/sprites/elf_golgari.png | Bin 0 -> 20787 bytes .../Shandalar/sprites/fungus_golgari.atlas | 77 + .../Shandalar/sprites/fungus_golgari.png | Bin 0 -> 39196 bytes .../Shandalar/sprites/golgari_treant.atlas | 68 + .../Shandalar/sprites/golgari_treant.png | Bin 0 -> 16103 bytes .../adventure/Shandalar/sprites/items.atlas | 6 +- .../Shandalar/sprites/pixie_dimir.atlas | 68 + .../Shandalar/sprites/pixie_dimir.png | Bin 0 -> 13996 bytes .../adventure/Shandalar/sprites/portal.atlas | 23 + .../adventure/Shandalar/sprites/portal2.atlas | 23 + .../adventure/Shandalar/sprites/portal3.atlas | 23 + .../adventure/Shandalar/sprites/portal4.atlas | 23 + .../adventure/Shandalar/sprites/portals.png | Bin 0 -> 27498 bytes .../Shandalar/sprites/rakdos_wiz.atlas | 68 + .../Shandalar/sprites/rakdos_wiz.png | Bin 0 -> 17877 bytes .../Shandalar/sprites/skeleton_2.atlas | 29 +- .../Shandalar/sprites/sliver_black.atlas | 68 + .../Shandalar/sprites/sliver_black.png | Bin 0 -> 17061 bytes .../Shandalar/sprites/sliver_blue.png | Bin 0 -> 21158 bytes .../Shandalar/sprites/sliver_white.png | Bin 0 -> 23658 bytes .../Shandalar/sprites/treant_golgari.atlas | 68 + .../Shandalar/sprites/treant_golgari.png | Bin 0 -> 16103 bytes .../res/adventure/Shandalar/world/black.json | 5 +- .../adventure/Shandalar/world/enemies.json | 1086 +++++- .../res/adventure/Shandalar/world/items.json | 24 +- .../Shandalar/world/points_of_interest.json | 17 + .../res/adventure/Shandalar/world/quests.json | 155 +- .../res/adventure/Shandalar/world/shops.json | 50 +- 96 files changed, 10403 insertions(+), 873 deletions(-) create mode 100644 forge-gui-mobile/src/forge/adventure/character/PortalActor.java create mode 100644 forge-gui/res/adventure/Shandalar/custom_card_pics/Death Ring.fullborder.jpg create mode 100644 forge-gui/res/adventure/Shandalar/custom_card_pics/Death Ring.png create mode 100644 forge-gui/res/adventure/Shandalar/custom_card_pics/Demonic Contract.fullborder.jpg create mode 100644 forge-gui/res/adventure/Shandalar/custom_card_pics/Waker of the Dead.fullborder.jpg create mode 100644 forge-gui/res/adventure/Shandalar/custom_cards/death_ring.txt create mode 100644 forge-gui/res/adventure/Shandalar/custom_cards/demonic_contract.txt create mode 100644 forge-gui/res/adventure/Shandalar/custom_cards/waker_of_the_dead.txt create mode 100644 forge-gui/res/adventure/Shandalar/decks/cleric_orzhov.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/dark_spirit.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/dimir_faerie.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/dimir_ninja.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/dimir_poison.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/elf_golgari.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/fungus_golgari.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/golgari_elf.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/golgari_treefolk.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/lilianas_herbalist.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/miniboss/angel_rainbow_encounter.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/miniboss/liliana.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/miniboss/liliana_zombies.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/rakdos_vamps.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/skeleton_champion.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/sliver_black.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/treefolk_golgari.dck create mode 100644 forge-gui/res/adventure/Shandalar/decks/zombie_greater.dck create mode 100644 forge-gui/res/adventure/Shandalar/maps/map/dig_site.tmx create mode 100644 forge-gui/res/adventure/Shandalar/maps/map/dig_site_2.tmx create mode 100644 forge-gui/res/adventure/Shandalar/maps/map/dig_site_3.tmx create mode 100644 forge-gui/res/adventure/Shandalar/maps/map/main_story/temple_of_liliana/bog.tmx create mode 100644 forge-gui/res/adventure/Shandalar/maps/map/main_story/temple_of_liliana/forest.tmx create mode 100644 forge-gui/res/adventure/Shandalar/maps/map/main_story/temple_of_liliana/graveyard.tmx create mode 100644 forge-gui/res/adventure/Shandalar/maps/map/main_story/temple_of_liliana/keep.tmx create mode 100644 forge-gui/res/adventure/Shandalar/maps/map/main_story/temple_of_liliana/town.tmx delete mode 100644 forge-gui/res/adventure/Shandalar/maps/map/main_story/templeofliliana.tmx create mode 100644 forge-gui/res/adventure/Shandalar/maps/obj/dialog.tx create mode 100644 forge-gui/res/adventure/Shandalar/maps/obj/portal.tx create mode 100644 forge-gui/res/adventure/Shandalar/maps/tileset/main-nocollide.tsx create mode 100644 forge-gui/res/adventure/Shandalar/sprites/cleric_orzhov.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/cleric_orzhov.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/dimir_wiz.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/dimir_wiz.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/elf_golgari.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/elf_golgari.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/fungus_golgari.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/fungus_golgari.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/golgari_treant.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/golgari_treant.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/pixie_dimir.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/pixie_dimir.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/portal.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/portal2.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/portal3.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/portal4.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/portals.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/rakdos_wiz.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/rakdos_wiz.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/sliver_black.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/sliver_black.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/sliver_blue.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/sliver_white.png create mode 100644 forge-gui/res/adventure/Shandalar/sprites/treant_golgari.atlas create mode 100644 forge-gui/res/adventure/Shandalar/sprites/treant_golgari.png diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 5f0787f8aee..001979a773d 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -1034,6 +1034,13 @@ public class Forge implements ApplicationListener { if (currentScene != null) { if (!currentScene.leave()) return false; + if (lastScene.contains(currentScene, false)) + { + int i = lastScene.indexOf(currentScene, false); + if (i > -1){ + lastScene.setSize(i); + } + } lastScene.add(currentScene); } storeScreen(); diff --git a/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java b/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java index a03088fd066..13b1d12248f 100644 --- a/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java @@ -20,6 +20,7 @@ public class CharacterSprite extends MapActor { private AnimationDirections currentAnimationDir = AnimationDirections.None; private final Array avatar=new Array<>(); public boolean hidden = false; + public boolean inactive = false; private String atlasPath; private float wakeTimer = 0.0f; @@ -175,10 +176,18 @@ public class CharacterSprite extends MapActor { public void moveBy(float x, float y, float delta) { + if (inactive){ + return; + } + if (hidden) { - setAnimation(AnimationTypes.Wake); - wakeTimer = 0.0f; - hidden = false; + if (animations.containsKey(AnimationTypes.Wake)) { + //Todo: Need another check here if we want objects revealed by activateMapObject to play wake animation + setAnimation(AnimationTypes.Wake); + wakeTimer = 0.0f; + hidden = false; + } + else return; } if (currentAnimationType == AnimationTypes.Wake && wakeTimer <= currentAnimation.getAnimationDuration()){ @@ -192,7 +201,7 @@ public class CharacterSprite extends MapActor { Vector2 vec = new Vector2(x, y); float degree = vec.angleDeg(); - setAnimation(AnimationTypes.Walk); + if (!hidden) setAnimation(AnimationTypes.Walk); if (degree < 22.5) setDirection(AnimationDirections.Right); else if (degree < 22.5 + 45) @@ -229,9 +238,8 @@ public class CharacterSprite extends MapActor { @Override public void draw(Batch batch, float parentAlpha) { - if (currentAnimation == null || hidden) + if (currentAnimation == null || hidden || inactive) { - return; } super.draw(batch,parentAlpha); diff --git a/forge-gui-mobile/src/forge/adventure/character/DialogActor.java b/forge-gui-mobile/src/forge/adventure/character/DialogActor.java index aeee3c78a16..29a9e3feb0f 100644 --- a/forge-gui-mobile/src/forge/adventure/character/DialogActor.java +++ b/forge-gui-mobile/src/forge/adventure/character/DialogActor.java @@ -64,8 +64,10 @@ public class DialogActor extends CharacterSprite { public void onPlayerCollide() { if (dialog != null) { stage.resetPosition(); - stage.showDialog(); - dialog.activate(); + + if (dialog.activate()){ + stage.showDialog(); + } } } diff --git a/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java b/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java index 85d23c3e6bd..2ea2e0b9438 100644 --- a/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java @@ -4,7 +4,6 @@ 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; @@ -51,8 +50,10 @@ public class EnemySprite extends CharacterSprite { private final Float _movementTimeout = 150.0f; private boolean _freeze = false; //freeze movement after defeating player public float unfreezeRange = 30.0f; - public float threatRange = 0.0f; - public float fleeRange = 0.0f; + public float threatRange = 0.0f; //If range < threatRange, begin pursuit + public float pursueRange = 0.0f; //If range > pursueRange, abandon pursuit + public float fleeRange = 0.0f; //If range < fleeRange, attempt to move away to fleeRange + private boolean aggro = false; public boolean ignoreDungeonEffect = false; public String questStageID; @@ -77,11 +78,6 @@ public class EnemySprite extends CharacterSprite { } } - public Rectangle navigationBoundingRect() { - //This version of the bounds will be used for navigation purposes to allow mobile mobs to not need pixel perfect pathing - return new Rectangle(boundingRect).setSize(boundingRect.width * collisionHeight, boundingRect.height * collisionHeight); - } - @Override void updateBoundingRect() { //We want enemies to take the full tile. float scale = data == null ? 1f : data.scale; @@ -124,9 +120,9 @@ public class EnemySprite extends CharacterSprite { } if (threatRange > 0 || fleeRange > 0){ - - if (routeToPlayer.len() <= threatRange) + if (routeToPlayer.len() <= threatRange || (aggro && routeToPlayer.len() <= pursueRange)) { + aggro = true; return routeToPlayer; } if (routeToPlayer.len() <= fleeRange) @@ -291,6 +287,8 @@ public class EnemySprite extends CharacterSprite { @Override public void draw(Batch batch, float parentAlpha) { + if (inactive || hidden) + return; super.draw(batch, parentAlpha); if(Current.player().hasColorView() && !data.colors.isEmpty()) { drawColorHints(batch); @@ -303,7 +301,7 @@ public class EnemySprite extends CharacterSprite { if(effect != null){ //Draw a crown icon on top. Texture T = Current.world().getGlobalTexture(); TextureRegion TR = new TextureRegion(T, 16, 0, 16, 16); - batch.draw(TR, getX(), getY() + 16, 16, 16); + batch.draw(TR, getX(), getY() + 16, 16*getScaleX(), 16*getScaleY()); } } diff --git a/forge-gui-mobile/src/forge/adventure/character/EntryActor.java b/forge-gui-mobile/src/forge/adventure/character/EntryActor.java index 470ac54c2ca..e0ab361151a 100644 --- a/forge-gui-mobile/src/forge/adventure/character/EntryActor.java +++ b/forge-gui-mobile/src/forge/adventure/character/EntryActor.java @@ -8,15 +8,17 @@ import forge.adventure.stage.MapStage; * Used to teleport the player in and out of the map */ public class EntryActor extends MapActor{ - private final MapStage stage; + final MapStage stage; String targetMap; - private float x; - private float y; - private float w; - private float h; - private String direction; + float x; + float y; + float w; + float h; + String direction; + String currentMap; + int entryTargetObject; - public EntryActor(MapStage stage, int id,String targetMap,float x,float y,float w,float h,String direction) + public EntryActor(MapStage stage, int id,String targetMap,float x,float y,float w,float h,String direction, String currentMap, int entryTargetObject) { super(id); this.stage = stage; @@ -25,7 +27,8 @@ public class EntryActor extends MapActor{ this.y = y; this.w = w; this.h = h; - + this.currentMap = currentMap; + this.entryTargetObject = entryTargetObject; this.direction = direction; } @@ -44,7 +47,15 @@ public class EntryActor extends MapActor{ } else { - TileMapScene.instance().loadNext(targetMap); + if (targetMap.equals(currentMap)) + { + stage.spawn(entryTargetObject); + } + else + { + currentMap = targetMap; + TileMapScene.instance().loadNext(targetMap, entryTargetObject); + } } } diff --git a/forge-gui-mobile/src/forge/adventure/character/PortalActor.java b/forge-gui-mobile/src/forge/adventure/character/PortalActor.java new file mode 100644 index 00000000000..ef129fdf4e3 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/character/PortalActor.java @@ -0,0 +1,183 @@ +package forge.adventure.character; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.*; +import com.badlogic.gdx.utils.Array; +import forge.adventure.scene.TileMapScene; +import forge.adventure.stage.MapStage; +import forge.adventure.util.Config; +import forge.adventure.util.Paths; + +import java.util.HashMap; + +/** + * PortalActor + * Extension of EntryActor, visible on map, multiple states that change behavior + */ +public class PortalActor extends EntryActor{ + + private final HashMap> animations = new HashMap<>(); + private Animation currentAnimation = null; + private PortalAnimationTypes currentAnimationType = PortalAnimationTypes.Closed; + + float timer; + + float transitionTimer; + + public PortalActor(MapStage stage, int id, String targetMap, float x, float y, float w, float h, String direction, String currentMap, int portalTargetObject, String path) + { + super(stage, id, targetMap, x, y, w, h, direction, currentMap, portalTargetObject); + load(path); + } + + public MapStage getMapStage() + { + return stage; + } + + @Override + public void onPlayerCollide() + { + if(currentAnimationType == PortalAnimationTypes.Inactive) { + //Activate portal? Launch Dialog? + } + if(currentAnimationType == PortalAnimationTypes.Active) { + if (targetMap == null || targetMap.isEmpty()) { + stage.exitDungeon(); + } else { + if (targetMap.equals(currentMap)) + { + stage.spawn(entryTargetObject); + stage.getPlayerSprite().playEffect(Paths.EFFECT_TELEPORT, 0.5f); + stage.startPause(1.5f); + } + else + { + currentMap = targetMap; + TileMapScene.instance().loadNext(targetMap, entryTargetObject); + stage.getPlayerSprite().playEffect(Paths.EFFECT_TELEPORT, 0.5f); + } + } + } + } + + public void spawn() { + switch(direction) + { + case "up": + stage.getPlayerSprite().setPosition(x+w/2-stage.getPlayerSprite().getWidth()/2,y+h); + break; + case "down": + stage.getPlayerSprite().setPosition(x+w/2-stage.getPlayerSprite().getWidth()/2,y-stage.getPlayerSprite().getHeight()); + break; + case "right": + stage.getPlayerSprite().setPosition(x-stage.getPlayerSprite().getWidth(),y+h/2-stage.getPlayerSprite().getHeight()/2); + break; + case "left": + stage.getPlayerSprite().setPosition(x+w,y+h/2-stage.getPlayerSprite().getHeight()/2); + break; + + } + } + + protected void load(String path) { + if(path==null||path.isEmpty())return; + TextureAtlas atlas = Config.instance().getAtlas(path); + animations.clear(); + for (PortalAnimationTypes stand : PortalAnimationTypes.values()) { + Array anim = atlas.createSprites(stand.toString()); + if (anim.size != 0) { + animations.put(stand, new Animation<>(0.2f, anim)); + if(getWidth()==0.0)//init size onload + { + setWidth(anim.first().getWidth()); + setHeight(anim.first().getHeight()); + } + } + } + + setAnimation(PortalAnimationTypes.Closed); + updateAnimation(); + } + + public void setAnimation(PortalAnimationTypes type) { + if (currentAnimationType != type) { + currentAnimationType = type; + updateAnimation(); + } + } + + public void setAnimation(String typeName) { + switch(typeName.toLowerCase()){ + case "active": + setAnimation(PortalAnimationTypes.Active); + break; + case "inactive": + setAnimation(PortalAnimationTypes.Inactive); + break; + case "closed": + setAnimation(PortalAnimationTypes.Closed); + break; + case "opening": + setAnimation(PortalAnimationTypes.Opening); + break; + case "closing": + setAnimation(PortalAnimationTypes.Closing); + break; + } + } + + private void updateAnimation() { + PortalAnimationTypes aniType = currentAnimationType; + if (!animations.containsKey(aniType)) { + aniType = PortalAnimationTypes.Inactive; + } + if (!animations.containsKey(aniType)) { + return; + } + currentAnimation = animations.get(aniType); + } + + public enum PortalAnimationTypes { + Closed, + Active, + Inactive, + Opening, + Closing + } + + public void act(float delta) { + timer += delta; + super.act(delta); + } + + public void draw(Batch batch, float parentAlpha) { + if (currentAnimation == null) + { + return; + } + super.draw(batch,parentAlpha); + beforeDraw(batch,parentAlpha); + + TextureRegion currentFrame; + if (currentAnimationType.equals(PortalAnimationTypes.Opening) || currentAnimationType.equals(PortalAnimationTypes.Closing)) + { + currentFrame = currentAnimation.getKeyFrame(transitionTimer, false); + } + else + { + currentFrame = currentAnimation.getKeyFrame(timer, true); + } + + setHeight(currentFrame.getRegionHeight()); + setWidth(currentFrame.getRegionWidth()); + Color oldColor=batch.getColor().cpy(); + batch.setColor(getColor()); + batch.draw(currentFrame, getX(), getY(), getWidth(), getHeight()); + batch.setColor(oldColor); + super.draw(batch,parentAlpha); + //batch.draw(getDebugTexture(),getX(),getY()); + + } +} + diff --git a/forge-gui-mobile/src/forge/adventure/data/DialogData.java b/forge-gui-mobile/src/forge/adventure/data/DialogData.java index 33d9e1781f2..a4e702e7389 100644 --- a/forge-gui-mobile/src/forge/adventure/data/DialogData.java +++ b/forge-gui-mobile/src/forge/adventure/data/DialogData.java @@ -54,6 +54,7 @@ public class DialogData implements Serializable { 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 activateMapObject = 0; //Remove inactive state from ID. 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. @@ -77,6 +78,7 @@ public class DialogData implements Serializable { addLife = other.addLife; addGold = other.addGold; deleteMapObject = other.deleteMapObject; + activateMapObject = other.activateMapObject; battleWithActorID = other.battleWithActorID; giveBlessing = other.giveBlessing; setColorIdentity = other.setColorIdentity; diff --git a/forge-gui-mobile/src/forge/adventure/scene/TileMapScene.java b/forge-gui-mobile/src/forge/adventure/scene/TileMapScene.java index bbc611489da..12a53a1814e 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/TileMapScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/TileMapScene.java @@ -23,6 +23,7 @@ public class TileMapScene extends HudScene { TiledMap map; PointOfInterestMapRenderer tiledMapRenderer; private String nextMap; + private int nextSpawnPoint; private boolean autoheal = false; private TileMapScene() { @@ -56,8 +57,9 @@ public class TileMapScene extends HudScene { if (map == null) return; if (nextMap != null) { - load(nextMap); + load(nextMap, nextSpawnPoint); nextMap = null; + nextSpawnPoint = 0; } stage.act(Gdx.graphics.getDeltaTime()); hud.act(Gdx.graphics.getDeltaTime()); @@ -108,7 +110,7 @@ public class TileMapScene extends HudScene { ((MapStage) stage).setPointOfInterest(WorldSave.getCurrentSave().getPointOfInterestChanges(point.getID() + oldMap)); stage.getPlayerSprite().setPosition(0, 0); WorldSave.getCurrentSave().getWorld().setSeed(point.getSeedOffset()); - tiledMapRenderer.loadMap(map, ""); + tiledMapRenderer.loadMap(map, "", oldMap,0); stage.getPlayerSprite().stop(); } @@ -120,12 +122,12 @@ public class TileMapScene extends HudScene { public PointOfInterest rootPoint; String oldMap; - private void load(String targetMap) { + private void load(String targetMap, int nextSpawnPoint) { map = new TemplateTmxMapLoader().load(Config.instance().getFilePath(targetMap)); ((MapStage) stage).setPointOfInterest(WorldSave.getCurrentSave().getPointOfInterestChanges(rootPoint.getID() + targetMap)); stage.getPlayerSprite().setPosition(0, 0); WorldSave.getCurrentSave().getWorld().setSeed(rootPoint.getSeedOffset()); - tiledMapRenderer.loadMap(map, oldMap); + tiledMapRenderer.loadMap(map, oldMap, targetMap, nextSpawnPoint); oldMap = targetMap; stage.getPlayerSprite().stop(); } @@ -136,8 +138,9 @@ public class TileMapScene extends HudScene { return MapStage.getInstance().getDialogOnlyInput(); } - public void loadNext(String targetMap) { + public void loadNext(String targetMap, int entryTargetObject) { nextMap = targetMap; + nextSpawnPoint = entryTargetObject; } } diff --git a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java index 88165367576..fd3b5a7d41d 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java @@ -163,32 +163,6 @@ public class MapStage extends GameStage { return false; } - public float lengthWithoutCollision(EnemySprite mob, Vector2 end) { - Vector2 start = mob.pos(); - Vector2 safeVector = start.cpy().add(end); - - int segmentsToCheck = 100; - float safeLen = safeVector.len(); - float partialLength = safeLen / segmentsToCheck; - - for (Rectangle collision : collisionRect) { - float uncollidedLen = 0.0f; - while (uncollidedLen < safeLen) { - Rectangle mRect = new Rectangle(mob.navigationBoundingRect()); - Vector2 testVector = new Vector2(end).setLength(uncollidedLen + partialLength); - mRect.setPosition(mRect.x + testVector.x, mRect.y + testVector.y); - if (mRect.overlaps(collision)) { - break; - } - uncollidedLen += partialLength; - } - safeLen = Math.min(safeLen, uncollidedLen); - } - - return safeLen; - } - - @Override public void prepareCollision(Vector2 pos, Vector2 direction, Rectangle boundingRect) { @@ -330,7 +304,11 @@ public class MapStage extends GameStage { Array spawnClassified = new Array<>(); Array sourceMapMatch = new Array<>(); - public void loadMap(TiledMap map, String sourceMap) { + public void loadMap(TiledMap map, String sourceMap, String targetMap) { + loadMap(map, sourceMap, targetMap, 0); + } + + public void loadMap(TiledMap map, String sourceMap, String targetMap, int spawnTargetId) { isLoadingMatch = false; isInMap = true; GameHUD.getInstance().showHideMap(false); @@ -339,7 +317,7 @@ public class MapStage extends GameStage { actor.remove(); foregroundSprites.removeActor(actor); } - + positions.clear(); actors.clear(); collisionRect.clear(); @@ -390,15 +368,10 @@ public class MapStage extends GameStage { if (layer instanceof TiledMapTileLayer) { loadCollision((TiledMapTileLayer) layer); } else { - loadObjects(layer, sourceMap); + loadObjects(layer, sourceMap, targetMap); } } - if (!spawnClassified.isEmpty()) - spawnClassified.first().spawn(); - else if (!sourceMapMatch.isEmpty()) - sourceMapMatch.first().spawn(); - else if (!otherEntries.isEmpty()) - otherEntries.first().spawn(); + spawn(spawnTargetId); //reduce geometry in collision rectangles int oldSize; @@ -433,6 +406,28 @@ public class MapStage extends GameStage { getPlayerSprite().stop(); } + public void spawn(int targetId){ + boolean hasSpawned = false; + if (targetId > 0){ + for (int i = 0; i < actors.size; i++) { + if (actors.get(i).getObjectId() == targetId) { + if (actors.get(i) instanceof EntryActor) { + ((EntryActor)(actors.get(i))).spawn(); + hasSpawned = true; + } + } + } + } + if (!hasSpawned){ + if (!spawnClassified.isEmpty()) + spawnClassified.first().spawn(); + else if (!sourceMapMatch.isEmpty()) + sourceMapMatch.first().spawn(); + else if (!otherEntries.isEmpty()) + otherEntries.first().spawn(); + } + } + void replaceWaypoints() { for (EnemySprite enemy : enemies) { for (EnemySprite.MovementBehavior behavior : enemy.movementBehaviors) { @@ -479,7 +474,7 @@ public class MapStage extends GameStage { return true; } - private void loadObjects(MapLayer layer, String sourceMap) { + private void loadObjects(MapLayer layer, String sourceMap, String currentMap) { player.setMoveModifier(2); Array shopsAlreadyPresent = new Array<>(); for (MapObject obj : layer.getObjects()) { @@ -489,6 +484,7 @@ public class MapStage extends GameStage { int id = prop.get("id", int.class); if (changes.isObjectDeleted(id)) continue; + boolean hidden = !obj.isVisible(); //Check if the object is invisible. String rotatingShop = ""; @@ -511,19 +507,51 @@ public class MapStage extends GameStage { float h = Float.parseFloat(prop.get("height").toString()); String targetMap = prop.get("teleport").toString(); - boolean spawnPlayerThere = (targetMap == null || targetMap.isEmpty() && sourceMap.isEmpty()) ||//if target is null and "from world" + boolean canStillSpawnPlayerThere = (targetMap == null || targetMap.isEmpty() && sourceMap.isEmpty()) ||//if target is null and "from world" !sourceMap.isEmpty() && targetMap.equals(sourceMap); - EntryActor entry = new EntryActor(this, id, prop.get("teleport").toString(), x, y, w, h, prop.get("direction").toString()); - if ((prop.containsKey("spawn") && prop.get("spawn").toString().equals("true")) && spawnPlayerThere) { + int entryTargetId = (!prop.containsKey("teleportObjectId") || prop.get("teleportObjectId") ==null || prop.get("teleportObjectId").toString().isEmpty())? 0: Integer.parseInt(prop.get("teleportObjectId").toString()); + + EntryActor entry = new EntryActor(this, id, prop.get("teleport").toString(), x, y, w, h, prop.get("direction").toString(), currentMap, entryTargetId); + if (prop.containsKey("spawn") && prop.get("spawn").toString().equals("true")) { spawnClassified.add(entry); - } else if (spawnPlayerThere) { + } else if (canStillSpawnPlayerThere) { sourceMapMatch.add(entry); } else { otherEntries.add(entry); } addMapActor(obj, entry); break; + case "portal": + float px = Float.parseFloat(prop.get("x").toString()); + float py = Float.parseFloat(prop.get("y").toString()); + float pw = Float.parseFloat(prop.get("width").toString()); + float ph = Float.parseFloat(prop.get("height").toString()); + + Object portalSpriteProvided = prop.get("sprite"); + String portalSpriteToUse; + portalSpriteToUse = "sprites/portal.atlas"; + if (portalSpriteProvided != null && !portalSpriteProvided.toString().isEmpty()) portalSpriteToUse = portalSpriteProvided.toString(); + else + System.err.printf("No sprite defined for portal (ID:%s), defaulting to \"sprites/portal.atlas\"", id); + + String portalTargetMap = prop.get("teleport").toString(); + boolean validSpawnPoint = (portalTargetMap == null || portalTargetMap.isEmpty() && sourceMap.isEmpty()) ||//if target is null and "from world" + !sourceMap.isEmpty() && portalTargetMap.equals(sourceMap); + + int portalTargetId = (!prop.containsKey("teleportObjectId") || prop.get("teleportObjectId") ==null || prop.get("teleportObjectId").toString().isEmpty())? 0: Integer.parseInt(prop.get("teleportObjectId").toString()); + + PortalActor portal = new PortalActor(this, id, prop.get("teleport").toString(), px, py, pw, ph, prop.get("direction").toString(), currentMap, portalTargetId, portalSpriteToUse); + portal.setAnimation(prop.get("portalState").toString()); + if (prop.containsKey("spawn") && prop.get("spawn").toString().equals("true")) { + spawnClassified.add(portal); + } else if (validSpawnPoint) { + sourceMapMatch.add(portal); + } else { + otherEntries.add(portal); + } + addMapActor(obj, portal); + break; case "reward": if (!canSpawn(prop)) break; Object R = prop.get("reward"); @@ -577,13 +605,30 @@ public class MapStage extends GameStage { { mob.threatRange = Float.parseFloat(prop.get("threatRange").toString()); } + if (prop.containsKey("threatRange")) //Check for threat range. + { + mob.pursueRange = Float.parseFloat(prop.get("pursueRange").toString()); + } if (prop.containsKey("fleeRange")) //Check for flee range. { mob.fleeRange = Float.parseFloat(prop.get("fleeRange").toString()); } + if (prop.containsKey("speed")) //Check for flee range. + { + mob.getData().speed = Float.parseFloat(prop.get("speed").toString()); + } + if (prop.containsKey("flying")) + { + mob.getData().flying = Boolean.parseBoolean(prop.get("flying").toString()); + } if (prop.containsKey("hidden")) { - mob.hidden = Boolean.parseBoolean(prop.get("hidden").toString()); + hidden = Boolean.parseBoolean(prop.get("hidden").toString()); + } + if (prop.containsKey("inactive")) + { + mob.inactive = Boolean.parseBoolean(prop.get("inactive").toString()); + if (mob.inactive) mob.clearCollisionHeight(); } if (hidden){ mob.hidden = hidden; //Evil. @@ -601,6 +646,9 @@ public class MapStage extends GameStage { 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); + if (prop.containsKey("hidden")){ + D.setVisible(!Boolean.parseBoolean(prop.get("hidden").toString())); + } 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). @@ -642,8 +690,10 @@ public class MapStage extends GameStage { DialogActor dialog; if (prop.containsKey("sprite")) dialog = new DialogActor(this, id, prop.get("dialog").toString(), prop.get("sprite").toString()); - else + else { dialog = new DialogActor(this, id, prop.get("dialog").toString(), tiledObj.getTextureRegion()); + dialog.setVisible(false); + } addMapActor(obj, dialog); } break; @@ -780,6 +830,7 @@ public class MapStage extends GameStage { } public boolean exitDungeon() { + WorldSave.getCurrentSave().autoSave(); AdventureQuestController.instance().updateQuestsLeave(); AdventureQuestController.instance().showQuestDialogs(this); isLoadingMatch = false; @@ -876,6 +927,22 @@ public class MapStage extends GameStage { return false; } + public boolean activateMapObject(int id){ + if (changes.isObjectDeleted(id)){ + return false; + } + for (int i = 0; i < actors.size; i++) { + if (actors.get(i).getObjectId() == id && id > 0) { + if (actors.get(i) instanceof EnemySprite) { + ((EnemySprite)(actors.get(i))).inactive = false; + (actors.get(i)).resetCollisionHeight(); + return true; + } + } + } + return false; + } + public boolean lookForID(int id) { //Search actor by ID. for (MapActor A : new Array.ArrayIterator<>(actors)) { @@ -928,6 +995,8 @@ public class MapStage extends GameStage { for (Integer i : idsToRemove) deleteObject(i); } + final Rectangle tempBoundingRect = new Rectangle(); + @Override protected void onActing(float delta) { if (isPaused() || isDialogOnlyInput()) @@ -942,6 +1011,9 @@ public class MapStage extends GameStage { if (!matchJustEnded) { while (it.hasNext()) { EnemySprite mob = it.next(); + if (mob.inactive){ + continue; + } mob.updatePositon(); mob.targetVector = mob.getTargetVector(player, delta); Vector2 currentVector = new Vector2(mob.targetVector); @@ -951,29 +1023,33 @@ public class MapStage extends GameStage { continue; } - if (!mob.getData().flying)//if direct path is not possible - { - //Todo: fix below for collision logic - float safeLen = lengthWithoutCollision(mob, mob.targetVector); - if (safeLen > 0.1f) { - currentVector.setLength(Math.min(safeLen, mob.targetVector.len())); - } else { - currentVector = Vector2.Zero; - } - } currentVector.setLength(Math.min(mob.speed() * delta, mob.targetVector.len())); - mob.moveBy(currentVector.x, currentVector.y,delta); + + tempBoundingRect.set(mob.getX() + currentVector.x, mob.getY() + currentVector.y, mob.getWidth() * 0.4f, mob.getHeight() * 0.4f); + + if (!mob.getData().flying && isColliding(tempBoundingRect))//if direct path is not possible + { + currentVector = adjustMovement(currentVector,tempBoundingRect); + tempBoundingRect.set(mob.getX() + currentVector.x, mob.getY(), mob.getWidth() * 0.4f, mob.getHeight() * 0.4f); + if (isColliding(tempBoundingRect))//if only x path is not possible + { + tempBoundingRect.set(mob.getX(), mob.getY() + currentVector.y, mob.getWidth() * 0.4f, mob.getHeight() * 0.4f); + if (!isColliding(tempBoundingRect))//if y path is possible + { + mob.moveBy(0, currentVector.y, delta); + } + } else { + mob.moveBy(currentVector.x, 0, delta); + } + } else { + mob.moveBy(currentVector.x, currentVector.y, delta); + } } } float sprintingMod = currentModifications.containsKey(PlayerModification.Sprint) ? 2 : 1; player.setMoveModifier(2 * sprintingMod); -// oldPosition4.set(oldPosition3); -// oldPosition3.set(oldPosition2); -// oldPosition2.set(oldPosition); -// oldPosition.set(player.pos()); - positions.add(player.pos()); if (positions.size() > 4) positions.remove(); diff --git a/forge-gui-mobile/src/forge/adventure/stage/PointOfInterestMapRenderer.java b/forge-gui-mobile/src/forge/adventure/stage/PointOfInterestMapRenderer.java index d7662186351..aab8e148a7a 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/PointOfInterestMapRenderer.java +++ b/forge-gui-mobile/src/forge/adventure/stage/PointOfInterestMapRenderer.java @@ -31,8 +31,8 @@ public class PointOfInterestMapRenderer extends OrthogonalTiledMapRendererBleedi endRender(); } - public void loadMap(TiledMap map, String sourceMap) { - stage.loadMap(map, sourceMap); + public void loadMap(TiledMap map, String sourceMap, String targetMap, int spawnPoint) { + stage.loadMap(map, sourceMap, targetMap, spawnPoint); super.setMap(map); } diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index 92ea3d98181..c343b9430ad 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -201,6 +201,7 @@ public class WorldStage extends GameStage implements SaveFileContent { continue; } try { + WorldSave.getCurrentSave().autoSave(); TileMapScene.instance().load(point.getPointOfInterest()); stop(); Forge.switchScene(TileMapScene.instance()); diff --git a/forge-gui-mobile/src/forge/adventure/util/MapDialog.java b/forge-gui-mobile/src/forge/adventure/util/MapDialog.java index 897b5968461..abbcd4d57de 100644 --- a/forge-gui-mobile/src/forge/adventure/util/MapDialog.java +++ b/forge-gui-mobile/src/forge/adventure/util/MapDialog.java @@ -275,12 +275,15 @@ public class MapDialog { GameHUD.getInstance().fadeOut(); } - public void activate() { //Method for actors to show their dialogues. + public boolean activate() { //Method for actors to show their dialogues. + boolean dialogShown = false; for (DialogData dialog : data) { if (isConditionOk(dialog.condition)) { loadDialog(dialog); + dialogShown = true; } } + return dialogShown; } void setEffects(DialogData.ActionData[] data) { @@ -315,6 +318,9 @@ public class MapDialog { if (E.deleteMapObject < 0) stage.deleteObject(parentID); else stage.deleteObject(E.deleteMapObject); } + if (E.activateMapObject != 0){ + stage.activateMapObject(E.activateMapObject); + } 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)); diff --git a/forge-gui/res/adventure/Shandalar/custom_card_pics/Death Ring.fullborder.jpg b/forge-gui/res/adventure/Shandalar/custom_card_pics/Death Ring.fullborder.jpg new file mode 100644 index 0000000000000000000000000000000000000000..35676e69be5d2040d8c5fa4e23863ac28fd8e3bc GIT binary patch literal 575472 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