diff --git a/forge-gui-android/libs/arm64-v8a/libgdx-box2d.so b/forge-gui-android/libs/arm64-v8a/libgdx-box2d.so new file mode 100644 index 00000000000..e562acc0b86 Binary files /dev/null and b/forge-gui-android/libs/arm64-v8a/libgdx-box2d.so differ diff --git a/forge-gui-android/libs/armeabi-v7a/libgdx-box2d.so b/forge-gui-android/libs/armeabi-v7a/libgdx-box2d.so new file mode 100644 index 00000000000..eef089879ed Binary files /dev/null and b/forge-gui-android/libs/armeabi-v7a/libgdx-box2d.so differ diff --git a/forge-gui-android/libs/x86/libgdx-box2d.so b/forge-gui-android/libs/x86/libgdx-box2d.so new file mode 100644 index 00000000000..df1fef60837 Binary files /dev/null and b/forge-gui-android/libs/x86/libgdx-box2d.so differ diff --git a/forge-gui-android/libs/x86_64/libgdx-box2d.so b/forge-gui-android/libs/x86_64/libgdx-box2d.so new file mode 100644 index 00000000000..852d26455f4 Binary files /dev/null and b/forge-gui-android/libs/x86_64/libgdx-box2d.so differ diff --git a/forge-gui-mobile-dev/libs/gdx-box2d-platform-natives.jar b/forge-gui-mobile-dev/libs/gdx-box2d-platform-natives.jar new file mode 100644 index 00000000000..d2f8f105679 Binary files /dev/null and b/forge-gui-mobile-dev/libs/gdx-box2d-platform-natives.jar differ diff --git a/forge-gui-mobile-dev/pom.xml b/forge-gui-mobile-dev/pom.xml index 1f3ccfe4ad5..14aeb894349 100644 --- a/forge-gui-mobile-dev/pom.xml +++ b/forge-gui-mobile-dev/pom.xml @@ -256,5 +256,11 @@ gdx-controllers-desktop 2.2.3-SNAPSHOT + + com.badlogicgames.gdx + gdx-box2d-platform + 1.11.0 + natives-desktop + diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index 46790b274d2..6fd4c1c5cec 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -80,6 +80,16 @@ 5.2.3 compile + + com.badlogicgames.gdx + gdx-box2d + 1.11.0 + + + com.badlogicgames.gdx + gdx-ai + 1.8.2 + diff --git a/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java b/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java index 30d1ffe0699..42fdc921be0 100644 --- a/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java @@ -1,5 +1,11 @@ package forge.adventure.character; +import com.badlogic.gdx.ai.steer.Steerable; +import com.badlogic.gdx.ai.steer.SteeringAcceleration; +import com.badlogic.gdx.ai.steer.SteeringBehavior; +import com.badlogic.gdx.ai.steer.behaviors.*; +import com.badlogic.gdx.ai.steer.utils.paths.LinePath; +import com.badlogic.gdx.ai.utils.Location; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Batch; @@ -16,12 +22,16 @@ import forge.adventure.player.AdventurePlayer; import forge.adventure.util.Current; import forge.adventure.util.MapDialog; import forge.adventure.util.Reward; +import forge.adventure.util.pathfinding.MovementBehavior; +import forge.adventure.util.pathfinding.NavigationVertex; +import forge.adventure.util.pathfinding.ProgressableGraphPath; import forge.card.CardRarity; import forge.deck.Deck; import forge.item.PaperCard; import forge.util.Aggregates; import forge.util.MyRandom; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; @@ -30,7 +40,20 @@ import java.util.stream.Collectors; * EnemySprite * Character sprite that represents an Enemy */ -public class EnemySprite extends CharacterSprite { +public class EnemySprite extends CharacterSprite implements Steerable { + + private static final SteeringAcceleration steerOutput = + new SteeringAcceleration(new Vector2()); + + Vector2 position; + float orientation; + Vector2 linearVelocity = new Vector2(1, 0); + float angularVelocity; + float maxSpeed; + boolean independentFacing; + SteeringBehavior behavior; + boolean tagged; + EnemyData data; public MapDialog dialog; //Dialog to show on contact. Overrides standard battle (can be started as an action) public MapDialog defeatDialog; //Dialog to show on defeat. Overrides standard death (can be removed as an action) @@ -53,9 +76,12 @@ public class EnemySprite extends CharacterSprite { 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 float speedModifier = 0.0f; // Increase or decrease default speed + public boolean aggro = false; public boolean ignoreDungeonEffect = false; public String questStageID; + private ProgressableGraphPath navPath; + public Vector2 fleeTarget; public EnemySprite(EnemyData enemyData) { this(0,enemyData); @@ -64,16 +90,19 @@ public class EnemySprite extends CharacterSprite { public EnemySprite(int id, EnemyData enemyData) { super(id,enemyData.sprite); data = enemyData; + initializeBaseMovementBehavior(); } public void parseWaypoints(String waypoints){ String[] wp = waypoints.replaceAll("\\s", "").split(","); for (String s : wp) { movementBehaviors.addLast(new MovementBehavior()); - if (s.startsWith("wait")) { - movementBehaviors.peekLast().duration = Float.parseFloat(s.substring(4)); - } else { - movementBehaviors.peekLast().destination = Integer.parseInt(s); + if (!movementBehaviors.isEmpty()) { + if (s.startsWith("wait")) { + movementBehaviors.peekLast().duration = Float.parseFloat(s.substring(4)); + } else { + movementBehaviors.peekLast().destination = s; + } } } } @@ -83,7 +112,13 @@ public class EnemySprite extends CharacterSprite { float scale = data == null ? 1f : data.scale; if (scale < 0) scale = 1f; - boundingRect.set(getX(), getY(), getWidth()*scale, getHeight()*scale); + + float width = getWidth()*scale* collisionHeight; + float height = getHeight()*scale* collisionHeight; + float x = getX() + (getWidth() - width)/2; + float y = getY() + (getHeight() - height)/2; + + boundingRect.set(x, y, width, height); unfreezeRange = 30f * scale; } @@ -94,6 +129,183 @@ public class EnemySprite extends CharacterSprite { moveBy(diff.x, diff.y,delta); } + public void initializeBaseMovementBehavior() { + Location seekTarget = new Location() { + @Override + public Vector2 getPosition() { + return navPath.nodes.get(0).pos; + } + + @Override + public float getOrientation() { + return 0; + } + + @Override + public void setOrientation(float orientation) { + + } + + @Override + public float vectorToAngle(Vector2 vector) { + return 0; + } + + @Override + public Vector2 angleToVector(Vector2 outVector, float angle) { + return null; + } + + @Override + public Location newLocation() { + return null; + } + }; + Seek seek = new Seek<>(this); + seek.setTarget(seekTarget); + + Array wp = new Array<>(); + if (navPath != null && navPath.nodes != null) { + for (NavigationVertex v : navPath.nodes) + wp.add(v.pos); + } + LinePath linePath = null; + FollowPath followWaypoints = null; + if (wp.size == 1) { + wp.insert(0, pos()); + } + if (wp.size >= 2) { + linePath = new LinePath(wp, false); + followWaypoints = new FollowPath<>(this, linePath); + followWaypoints.setPathOffset(0.5f); + } + + Arrive moveDirectlyToDestination = new Arrive<>(this, new Location() { + @Override + public Vector2 getPosition() { + if (navPath == null || navPath.nodes.size == 0) + return pos(); + return navPath.get(0).pos; + } + + @Override + public float getOrientation() { + return 0; + } + + @Override + public void setOrientation(float orientation) { + + } + + @Override + public float vectorToAngle(Vector2 vector) { + return 0; + } + + @Override + public Vector2 angleToVector(Vector2 outVector, float angle) { + return null; + } + + @Override + public Location newLocation() { + return null; + } + }) + .setTimeToTarget(0.01f) + .setArrivalTolerance(0f) + .setDecelerationRadius(10); + + if (followWaypoints != null) + setBehavior(followWaypoints); + else + setBehavior(moveDirectlyToDestination); + } + + public void setBehavior(SteeringBehavior behavior) { + this.behavior = behavior; + } + + public SteeringBehavior getBehavior() { + return behavior; + } + + public void update(float delta) { + if(behavior != null) { + behavior.calculateSteering(steerOutput); + while (steerOutput.isZero() && navPath != null && navPath.getCount() > 1) { + navPath.remove(0); + behavior.calculateSteering(steerOutput); + } + applySteering(delta); + } + } + + private void applySteering(float delta) { + if(!steerOutput.linear.isZero()) { + Vector2 force = steerOutput.linear.scl(delta); + force.setLength(Math.min(speed() * delta, force.len())); + moveBy(force.x, force.y); + } + } + + @Override + public float vectorToAngle (Vector2 vector) { + return (float)Math.atan2(-vector.x, vector.y); + } + + @Override + public Vector2 angleToVector (Vector2 outVector, float angle) { + outVector.x = -(float)Math.sin(angle); + outVector.y = (float)Math.cos(angle); + return outVector; + } + + @Override + public Vector2 getLinearVelocity() { + return linearVelocity; + } + + @Override + public float getAngularVelocity() { + return angularVelocity; + } + @Override + public float getBoundingRadius() { + return getWidth()/2; + } + + @Override + public boolean isTagged() { + return tagged; + } + + @Override + public Vector2 getPosition() { + return pos(); + } + + @Override + public float getOrientation() { + return orientation; + } + + @Override + public void setOrientation(float value) { + orientation = value; + } + + @Override + public Location newLocation() { + return null; + } + + @Override + public void setTagged(boolean value) { + tagged = value; + } + public void freezeMovement(){ _freeze = true; setPosition(_previousPosition6.x, _previousPosition6.y); @@ -102,15 +314,15 @@ public class EnemySprite extends CharacterSprite { // Combined with player doing the same, should no longer be colliding to immediately re-enter battle if mob still present } - public Vector2 getTargetVector(PlayerSprite player, float delta) { + public Vector2 getTargetVector(PlayerSprite player, ArrayList sortedGraphNodes, float delta) { //todo - this can be integrated into overworld movement as well, giving flee behaviors or moving to generated waypoints Vector2 target = pos(); - Vector2 routeToPlayer = new Vector2(player.pos()).sub(target); + Vector2 spriteToPlayer = new Vector2(player.pos()).sub(target); if (_freeze){ //Mob has defeated player in battle, hold still until player has a chance to move away. //Without this moving enemies can immediately restart battle. - if (routeToPlayer.len() < unfreezeRange) { + if (spriteToPlayer.len() < unfreezeRange) { timer += delta; return Vector2.Zero; } @@ -119,53 +331,81 @@ public class EnemySprite extends CharacterSprite { } } + NavigationVertex targetPoint = null; if (threatRange > 0 || fleeRange > 0){ - if (routeToPlayer.len() <= threatRange || (aggro && routeToPlayer.len() <= pursueRange)) + if (spriteToPlayer.len() <= threatRange || (aggro && spriteToPlayer.len() <= pursueRange)) { + if (sortedGraphNodes != null) { + for (NavigationVertex candidate : sortedGraphNodes) { + Vector2 candidateToPlayer = new Vector2(candidate.pos).sub(player.pos()); + if ((candidateToPlayer.x * candidateToPlayer.x) + (candidateToPlayer.y * candidateToPlayer.y) < + (spriteToPlayer.x * spriteToPlayer.x) + (spriteToPlayer.y * spriteToPlayer.y)) { + targetPoint = candidate; + break; + } + } + } aggro = true; - return routeToPlayer; + if (targetPoint != null) { + return targetPoint.pos; + } + return new Vector2(player.pos()); } - if (routeToPlayer.len() <= fleeRange) + if (spriteToPlayer.len() <= fleeRange) { - Float fleeDistance = fleeRange - routeToPlayer.len(); - return new Vector2(target).sub(player.pos()).setLength(fleeDistance); + //todo: replace with inverse A* variant, seeking max total distance from player in X generations + // of movement, valuing each node by distance from player divided by closest distance(s) in path + // in order to make close passes to escape less appealing than maintaining moderate distance + float fleeDistance = fleeRange - spriteToPlayer.len(); + return new Vector2(pos()).sub(player.pos()).setLength(fleeDistance).add(pos()); + } + if (aggro && spriteToPlayer.len() > pursueRange) { + aggro = false; + initializeBaseMovementBehavior(); } } - if (movementBehaviors.size() > 0){ + if (movementBehaviors.peek() != null){ + MovementBehavior peek = movementBehaviors.peek(); + //TODO - This first block needs to be redone, doesn't work as intended and can also possibly skip behaviors in rare situations +// if (peek.getDuration() == 0 && target.equals(_previousPosition6) && timer >= _movementTimeout) +// { +// //stationary in an untimed behavior, move on to next behavior attempt to get unstuck +// if (movementBehaviors.size() > 1) { +// MovementBehavior current = movementBehaviors.pop(); +// current.currentTargetVector = null; +// movementBehaviors.addLast(current); +// } +// } + //else + if (peek.getDuration() == 0 && peek.getNextTargetVector(pos()).dst(pos()) < 2){ + //this is a location based behavior that has been completed. Move on to the next behavior + + MovementBehavior current = movementBehaviors.pop(); + current.currentTargetVector = null; + movementBehaviors.addLast(current); - if (movementBehaviors.peek().getDuration() == 0 && target.equals(_previousPosition6) && timer >= _movementTimeout) - { - //stationary in an untimed behavior, move on to next behavior attempt to get unstuck - if (movementBehaviors.size() > 1) { - movementBehaviors.addLast(movementBehaviors.pop()); - timer = 0.0f; - } } - else if (movementBehaviors.peek().pos().sub(pos()).len() < 0.3){ - //this is a location based behavior that has been completed. Move on if there are more behaviors - if (movementBehaviors.size() > 1) { - movementBehaviors.addLast(movementBehaviors.pop()); - timer = 0.0f; - } - } - else if ( movementBehaviors.peek().getDuration() > 0) + else if ( peek.getDuration() > 0) { - if (timer >= movementBehaviors.peek().getDuration() + delta) + if (timer >= peek.getDuration() + delta) { //this is a timed behavior that has been completed. Move to the next behavior and restart the timer - movementBehaviors.addLast(movementBehaviors.pop()); - timer = 0.0f; + MovementBehavior current = movementBehaviors.pop(); + current.currentTargetVector = null; + movementBehaviors.addLast(current); } else{ timer += delta;//this is a timed behavior that has not been completed, continue this behavior + return new Vector2(pos()); } } - if (movementBehaviors.peek().pos().len() > 0.3) - target = new Vector2(movementBehaviors.peek().pos()).sub(pos()); - else target = Vector2.Zero; + if (peek.getNextTargetVector(pos()).dst(pos()) > 0.3) { + target = new Vector2(peek.getNextTargetVector(pos())); + } + else target = new Vector2(pos()); } - else target = Vector2.Zero; + else target = new Vector2(pos()); return target; } public void updatePositon() @@ -313,7 +553,7 @@ public class EnemySprite extends CharacterSprite { } public float speed() { - return data.speed; + return Float.max(data.speed + speedModifier, 0); } public float getLifetime() { @@ -322,44 +562,71 @@ public class EnemySprite extends CharacterSprite { return Math.max(data.lifetime, lifetime); } + //Pathfinding integration below this line - public class MovementBehavior { - - //temporary placeholders for overworld behavior integration - public boolean wander = false; - public boolean flee = false; - public boolean stop = false; - //end temporary - - float duration = 0.0f; - float x = 0.0f; - float y = 0.0f; - - int destination = 0; - - public float getX(){ - return x; - } - public float getY(){ - return y; - } - public float getDuration(){ - return duration; - } - public int getDestination(){ - return destination; - } - - public void setX(float newVal){ - x = newVal; - } - public void setY(float newVal){ - y = newVal; - } - - public Vector2 pos() { - return new Vector2(getX(), getY()); - } + public void setNavPath(ProgressableGraphPath navPath) { + this.navPath = navPath; } + + public ProgressableGraphPath getNavPath() { + return navPath; + } + + @Override + public float getZeroLinearSpeedThreshold() { + return 0; + } + + @Override + public void setZeroLinearSpeedThreshold(float value) { + + } + + @Override + public float getMaxLinearSpeed() { + return 500; + } + + @Override + public void setMaxLinearSpeed(float maxLinearSpeed) { + + } + + @Override + public float getMaxLinearAcceleration() { + return 5000; + } + + @Override + public void setMaxLinearAcceleration(float maxLinearAcceleration) { + + } + + @Override + public float getMaxAngularSpeed() { + return 0; + } + + @Override + public void setMaxAngularSpeed(float maxAngularSpeed) { + + } + + @Override + public float getMaxAngularAcceleration() { + return 0; + } + + @Override + public void setMaxAngularAcceleration(float maxAngularAcceleration) { + + } + + public void steer(Vector2 currentVector) { + + } + + + } diff --git a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java index 8d9a047321e..481308f593f 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java @@ -316,6 +316,7 @@ public class RewardScene extends UIScene { if (type == Type.Shop) { this.shopActor = shopActor; this.changes = shopActor.getMapStage().getChanges(); + addToSelectable(restockButton); } for (Actor actor : new Array.ArrayIterator<>(generated)) { actor.remove(); @@ -323,6 +324,7 @@ public class RewardScene extends UIScene { ((RewardActor) actor).dispose(); } } + addToSelectable(doneButton); generated.clear(); Actor card = ui.findActor("cards"); diff --git a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java index 86e8018d38d..4de3e7c087a 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java @@ -1,6 +1,5 @@ package forge.adventure.stage; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.controllers.Controllers; import com.badlogic.gdx.graphics.g2d.Batch; @@ -14,6 +13,7 @@ import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; import com.badlogic.gdx.maps.tiled.objects.TiledMapTileMapObject; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.*; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Group; import com.badlogic.gdx.scenes.scene2d.InputEvent; @@ -23,9 +23,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Button; import com.badlogic.gdx.scenes.scene2d.ui.Dialog; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; -import com.badlogic.gdx.utils.Align; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.Scaling; +import com.badlogic.gdx.utils.*; import com.badlogic.gdx.utils.Timer; import com.github.tommyettinger.textra.TextraButton; import com.github.tommyettinger.textra.TextraLabel; @@ -37,6 +35,9 @@ import forge.adventure.data.*; import forge.adventure.pointofintrest.PointOfInterestChanges; import forge.adventure.scene.*; import forge.adventure.util.*; +import forge.adventure.util.pathfinding.NavigationMap; +import forge.adventure.util.pathfinding.NavigationVertex; +import forge.adventure.util.pathfinding.ProgressableGraphPath; import forge.adventure.world.WorldSave; import forge.assets.FBufferedImage; import forge.assets.FImageComplex; @@ -53,6 +54,7 @@ import forge.sound.SoundSystem; import java.time.LocalDate; import java.util.*; +import java.util.Queue; /** @@ -61,9 +63,10 @@ import java.util.*; public class MapStage extends GameStage { public static MapStage instance; final Array actors = new Array<>(); - - TiledMap map; - Array collisionRect = new Array<>(); + public com.badlogic.gdx.physics.box2d.World gdxWorld; + public TiledMap tiledMap; + public Array collisionRect = new Array<>(); + public Map navMaps = new HashMap<>(); private boolean isInMap = false; MapLayer spriteLayer; private PointOfInterestChanges changes; @@ -87,7 +90,13 @@ public class MapStage extends GameStage { private boolean respawnEnemies; private boolean canFailDungeon = false; protected ArrayList enemies = new ArrayList<>(); - protected Map waypoints = new HashMap<>(); + public Map waypoints = new HashMap<>(); + + //todo: add additional graphs for other sprite sizes if desired. Current implementation + // allows for mobs of any size to fit into 16x16 tiles for navigation purposes + float collisionWidthMod = 0.4f; + float defaultSpriteSize = 16f; + float navMapSize = defaultSpriteSize * collisionWidthMod; public boolean getDialogOnlyInput() { return dialogOnlyInput; @@ -126,6 +135,7 @@ public class MapStage extends GameStage { private boolean freezeAllEnemyBehaviors = false; protected MapStage() { + gdxWorld = new World(new Vector2(0, 0),false); dialog = Controls.newDialog(""); eventTouchDown = new InputEvent(); eventTouchDown.setPointer(-1); @@ -309,10 +319,11 @@ public class MapStage extends GameStage { } public void loadMap(TiledMap map, String sourceMap, String targetMap, int spawnTargetId) { + gdxWorld = new World(new Vector2(0, 0),false); isLoadingMatch = false; isInMap = true; GameHUD.getInstance().showHideMap(false); - this.map = map; + this.tiledMap = map; for (MapActor actor : new Array.ArrayIterator<>(actors)) { actor.remove(); foregroundSprites.removeActor(actor); @@ -320,6 +331,7 @@ public class MapStage extends GameStage { positions.clear(); actors.clear(); collisionRect.clear(); + waypoints.clear(); if (collisionGroup != null) collisionGroup.remove(); @@ -401,8 +413,9 @@ public class MapStage extends GameStage { } while (oldSize != collisionRect.size); if (spriteLayer == null) System.err.print("Warning: No spriteLayer present in map.\n"); - replaceWaypoints(); - + navMaps.clear(); + navMaps.put(navMapSize, new NavigationMap(navMapSize)); + navMaps.get(navMapSize).initializeGeometryGraph(); getPlayerSprite().stop(); } @@ -428,17 +441,6 @@ public class MapStage extends GameStage { } } - void replaceWaypoints() { - for (EnemySprite enemy : enemies) { - for (EnemySprite.MovementBehavior behavior : enemy.movementBehaviors) { - if (behavior.getDestination() > 0 && waypoints.containsKey(behavior.getDestination())) { - behavior.setX(waypoints.get(behavior.getDestination()).x); - behavior.setY(waypoints.get(behavior.getDestination()).y); - } - } - } - } - static public boolean containsOrEquals(Rectangle r1, Rectangle r2) { float xmi = r2.x; float xma = xmi + r2.width; @@ -456,7 +458,7 @@ public class MapStage extends GameStage { for (MapObject collision : cell.getTile().getObjects()) { if (collision instanceof RectangleMapObject) { Rectangle r = ((RectangleMapObject) collision).getRectangle(); - collisionRect.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))); + collisionRect.add(new Rectangle(((layer.getTileWidth() * x) + r.x), ((layer.getTileHeight() * y) + r.y), Math.round(r.width), Math.round(r.height))); } } } @@ -657,6 +659,10 @@ public class MapStage extends GameStage { if (dialogObject != null && !dialogObject.toString().isEmpty()) { mob.parseWaypoints(dialogObject.toString()); } + if (prop.containsKey("speedModifier")) //Increase or decrease default speed for this mob + { + mob.speedModifier = Float.parseFloat(prop.get("speedModifier").toString()); + } enemies.add(mob); addMapActor(obj, mob); @@ -1026,8 +1032,6 @@ 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()) @@ -1040,6 +1044,9 @@ public class MapStage extends GameStage { } else return; } + float mobSize = navMapSize; //todo: replace with actual size if multiple nav maps implemented + ArrayList verticesNearPlayer = new ArrayList<>(navMaps.get(mobSize).navGraph.getNodes()); + verticesNearPlayer.sort(Comparator.comparingInt(o -> Math.round((o.pos.x - player.pos().x) * (o.pos.x - player.pos().x) + (o.pos.y - player.pos().y) * (o.pos.y - player.pos().y)))); if (!freezeAllEnemyBehaviors) { while (it.hasNext()) { @@ -1048,35 +1055,52 @@ public class MapStage extends GameStage { continue; } mob.updatePositon(); - mob.targetVector = mob.getTargetVector(player, delta); - Vector2 currentVector = new Vector2(mob.targetVector); + + ProgressableGraphPath navPath = new ProgressableGraphPath<>(0); + if (mob.getData().flying) { + navPath.add(new NavigationVertex(mob.getTargetVector(player, null,delta))); + } else { + Vector2 destination = mob.getTargetVector(player, verticesNearPlayer, delta); + + if (destination.epsilonEquals(mob.pos()) && !mob.aggro) { + mob.setAnimation(CharacterSprite.AnimationTypes.Idle); + continue; + } + if (destination.equals(mob.targetVector) && mob.getNavPath() != null) + navPath = mob.getNavPath(); + + if (navPath.nodes.size == 0 || !destination.equals(mob.targetVector)) { + mob.targetVector = destination; + navPath = navMaps.get(mobSize).findShortestPath(mobSize, mob.pos(), mob.targetVector); + } + + if (mob.aggro) { + navPath.add(new NavigationVertex(player.pos())); + } + } + + if (navPath == null || navPath.getCount() == 0 || navPath.get(0) == null) { + mob.setAnimation(CharacterSprite.AnimationTypes.Idle); + continue; + } + Vector2 currentVector = null; + + while (navPath.getCount() > 0 && navPath.get(0) != null && (navPath.get(0).pos == null || navPath.get(0).pos.dst(mob.pos()) < 0.5f)) { + + navPath.remove(0); + + } + if (navPath.getCount() != 0) { + currentVector = new Vector2(navPath.get(0).pos).sub(mob.pos()); + } + mob.setNavPath(navPath); mob.clearActions(); - if (mob.targetVector.len() == 0.0f) { + if (currentVector == null || (currentVector.x == 0.0f && currentVector.y == 0.0f)) { mob.setAnimation(CharacterSprite.AnimationTypes.Idle); continue; } - - currentVector.setLength(Math.min(mob.speed() * delta, mob.targetVector.len())); - - 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); - } + mob.steer(currentVector); + mob.update(delta); } } @@ -1087,9 +1111,6 @@ public class MapStage extends GameStage { if (positions.size() > 4) positions.remove(); - - - for (MapActor actor : new Array.ArrayIterator<>(actors)) { if (actor.collideWithPlayer(player)) { if (actor instanceof EnemySprite) { diff --git a/forge-gui-mobile/src/forge/adventure/util/pathfinding/Box2dRaycastCollisionDetector.java b/forge-gui-mobile/src/forge/adventure/util/pathfinding/Box2dRaycastCollisionDetector.java new file mode 100644 index 00000000000..66371d5aa93 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/util/pathfinding/Box2dRaycastCollisionDetector.java @@ -0,0 +1,56 @@ +package forge.adventure.util.pathfinding; + +import com.badlogic.gdx.ai.utils.Collision; +import com.badlogic.gdx.ai.utils.Ray; +import com.badlogic.gdx.ai.utils.RaycastCollisionDetector; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Fixture; +import com.badlogic.gdx.physics.box2d.RayCastCallback; +import com.badlogic.gdx.physics.box2d.World; + +public class Box2dRaycastCollisionDetector implements RaycastCollisionDetector { + + World world; + Box2dRaycastCollisionDetector.Box2dRaycastCallback callback; + + public Box2dRaycastCollisionDetector (World world) { + this(world, new Box2dRaycastCollisionDetector.Box2dRaycastCallback()); + } + + public Box2dRaycastCollisionDetector (World world, Box2dRaycastCollisionDetector.Box2dRaycastCallback callback) { + this.world = world; + this.callback = callback; + } + + @Override + public boolean collides (Ray ray) { + return findCollision(null, ray); + } + + @Override + public boolean findCollision (Collision outputCollision, Ray inputRay) { + callback.collided = false; + if (!inputRay.start.epsilonEquals(inputRay.end, MathUtils.FLOAT_ROUNDING_ERROR)) { + callback.outputCollision = outputCollision; + world.rayCast(callback, inputRay.start, inputRay.end); + } + return callback.collided; + } + + public static class Box2dRaycastCallback implements RayCastCallback { + public Collision outputCollision; + public boolean collided; + + public Box2dRaycastCallback () { + } + + @Override + public float reportRayFixture (Fixture fixture, Vector2 point, Vector2 normal, float fraction) { + if (outputCollision != null) outputCollision.set(point, normal); + collided = true; + return fraction; + } + } +} + diff --git a/forge-gui-mobile/src/forge/adventure/util/pathfinding/EuclidianHeuristic.java b/forge-gui-mobile/src/forge/adventure/util/pathfinding/EuclidianHeuristic.java new file mode 100644 index 00000000000..eaf8b1af48a --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/util/pathfinding/EuclidianHeuristic.java @@ -0,0 +1,12 @@ +package forge.adventure.util.pathfinding; + +import com.badlogic.gdx.ai.pfa.Heuristic; + +public class EuclidianHeuristic implements Heuristic { + + @Override + public float estimate(NavigationVertex start, NavigationVertex end) { + return start.pos.dst(end.pos); + } +} + diff --git a/forge-gui-mobile/src/forge/adventure/util/pathfinding/MovementBehavior.java b/forge-gui-mobile/src/forge/adventure/util/pathfinding/MovementBehavior.java new file mode 100644 index 00000000000..a784b827c60 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/util/pathfinding/MovementBehavior.java @@ -0,0 +1,59 @@ +package forge.adventure.util.pathfinding; + +import com.badlogic.gdx.math.Vector2; +import forge.adventure.stage.MapStage; +import forge.util.Aggregates; + +public class MovementBehavior { + public float duration = 0.0f; + float x = 0.0f; + float y = 0.0f; + + public String destination = ""; + + public float getX(){ + return x; + } + public float getY(){ + return y; + } + public float getDuration(){ + return duration; + } + public Vector2 currentTargetVector; + public Vector2 getNextTargetVector(Vector2 currentPosition){ + if (currentTargetVector != null) { + return currentTargetVector; + } + if (destination.isEmpty()) { + currentTargetVector = new Vector2(currentPosition); + } else { + if (destination.startsWith("r")) { + String[] randomWaypoints = destination.replaceAll("r", "").split("-"); + if (randomWaypoints.length > 0) { + int selectedWaypoint = Integer.parseInt(Aggregates.random(randomWaypoints)); + if (MapStage.getInstance().waypoints.containsKey(selectedWaypoint)) { + currentTargetVector = new Vector2(MapStage.getInstance().waypoints.get(selectedWaypoint)); + } + } + else { + currentTargetVector = new Vector2(currentPosition); + } + } else if (destination.startsWith("w")) { + currentTargetVector = new Vector2(currentPosition); + duration = Float.parseFloat(destination.replaceAll("w", "")); + } else if (MapStage.getInstance().waypoints.containsKey(Integer.parseInt(destination))) { + currentTargetVector = new Vector2(MapStage.getInstance().waypoints.get(Integer.parseInt(destination))); + } + } + + return currentTargetVector; + } + + public void setX(float newVal){ + x = newVal; + } + public void setY(float newVal){ + y = newVal; + } +} \ No newline at end of file diff --git a/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationEdge.java b/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationEdge.java new file mode 100644 index 00000000000..6c6fbbf1903 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationEdge.java @@ -0,0 +1,31 @@ +package forge.adventure.util.pathfinding; + +import com.badlogic.gdx.ai.pfa.Connection; +import com.badlogic.gdx.math.Vector2; + +public class NavigationEdge implements Connection { + NavigationVertex fromVertex; + NavigationVertex toVertex; + float cost; + + public NavigationEdge(NavigationVertex from, NavigationVertex to) { + this.fromVertex = from; + this.toVertex = to; + cost = Vector2.dst(fromVertex.pos.x, fromVertex.pos.y, toVertex.pos.x, toVertex.pos.y); + } + + @Override + public float getCost() { + return cost; + } + + @Override + public NavigationVertex getFromNode() { + return fromVertex; + } + + @Override + public NavigationVertex getToNode() { + return toVertex; + } +} diff --git a/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationGraph.java b/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationGraph.java new file mode 100644 index 00000000000..88ebfdf2699 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationGraph.java @@ -0,0 +1,163 @@ +package forge.adventure.util.pathfinding; + +import com.badlogic.gdx.ai.pfa.Connection; +import com.badlogic.gdx.ai.pfa.indexed.IndexedAStarPathFinder; +import com.badlogic.gdx.ai.pfa.indexed.IndexedGraph; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class NavigationGraph implements IndexedGraph { + private int lastNodeIndex = 0; + Map nodes = new HashMap<>(); + + EuclidianHeuristic navigationHeuristic = new EuclidianHeuristic(); + + public NavigationVertex addVertex(NavigationVertex node){ + node.index = lastNodeIndex; + lastNodeIndex++; + nodes.put(node.index,node); + return node; + } + + public NavigationVertex addVertex(Vector2 position) { + return addVertex(new NavigationVertex(position)); + } + + public NavigationVertex addVertex(float x, float y) { + return addVertex(new NavigationVertex(x,y)); + } + + public void removeVertex(NavigationVertex node) { + for (NavigationVertex v : node.incomingEdges.keys()) { + v.removeEdges(node); + } + nodes.remove(node.index >=0? node.index: lookupIndex(node)); + } + + public void removeVertex(Vector2 position) { + removeVertex(getVertexByPosition(position)); + } + + public void removeVertex(float x, float y) { + removeVertex(new Vector2(x,y)); + } + + public void removeVertices(Collection vertices) { + for (NavigationVertex v : vertices) { + removeVertex(v); + } + } + + public void removeVertexIf(Predicate predicate) { + removeVertices(nodes.values().stream().filter(predicate).collect(Collectors.toList())); + } + + public int lookupIndex(NavigationVertex item) { + return lookupIndex(item.pos); + } + + public int lookupIndex(Vector2 pos) { + for (int i : nodes.keySet()) + if (nodes.get(i).pos.equals(pos)) return i; + + return -1; + } + + public void addEdge(NavigationVertex fromNode, NavigationVertex toNode) { + if (fromNode.index < 0) { + fromNode = getVertexByPosition(fromNode.pos); + } + if (toNode.index < 0) { + toNode = getVertexByPosition(toNode.pos); + } + + if (edgeExists(fromNode, toNode)) { + System.out.println(fromNode.pos + " is already connected to " + toNode.pos); + return; + } + + if (!(fromNode.index < 0) || toNode.index < 0) { + NavigationEdge fromAToB = new NavigationEdge(fromNode, toNode); + NavigationEdge fromBToA = new NavigationEdge(toNode, fromNode); + fromNode.outgoingEdges.put(toNode, fromAToB); + fromNode.incomingEdges.put(toNode, fromBToA); + toNode.outgoingEdges.put(fromNode, fromBToA); + toNode.incomingEdges.put(fromNode, fromAToB); + } + } + + public void addEdge(Vector2 fromNode, NavigationVertex toNode) { + addEdge(new NavigationVertex(fromNode), toNode); + } + + public void addEdge(NavigationVertex fromNode, Vector2 toNode) { + addEdge(fromNode, new NavigationVertex(toNode)); + } + + public void addEdgeUnchecked(NavigationVertex fromNode, NavigationVertex toNode) { + //Assumes that nodes are in graph, are not connected already, and have correct index + + NavigationEdge fromAToB = new NavigationEdge(fromNode, toNode); + NavigationEdge fromBToA = new NavigationEdge(toNode, fromNode); + + fromNode.outgoingEdges.put(toNode, fromAToB); + fromNode.incomingEdges.put(toNode, fromBToA); + toNode.outgoingEdges.put(fromNode, fromBToA); + toNode.incomingEdges.put(fromNode, fromAToB); + } + + public int getIndex(NavigationVertex node) { + return node.index; + } + + public int getNodeCount() { + return lastNodeIndex; + } + + @Override + public Array> getConnections(NavigationVertex fromNode) { + return fromNode.getAllConnections(); + } + + public boolean edgeExists(NavigationVertex fromNode, NavigationVertex toNode) { + if (fromNode.index < 0) { + fromNode = getVertexByPosition(fromNode.pos); + } + if (toNode.index < 0) { + toNode = getVertexByPosition(toNode.pos); + } + return fromNode.outgoingEdges.containsKey(toNode); + } + + public Collection getNodes() { + return nodes.values(); + } + + public ProgressableGraphPath findPath(Vector2 origin, Vector2 destination) { + ProgressableGraphPath navPath = new ProgressableGraphPath<>(); + + NavigationVertex originVertex = getVertexByPosition(origin); + NavigationVertex destinationVertex = getVertexByPosition(destination); + + if (originVertex.index > -1 && destinationVertex.index > -1) { + + new IndexedAStarPathFinder<>(this).searchNodePath(originVertex, destinationVertex, navigationHeuristic, navPath); + } + return navPath; + } + + public NavigationVertex getVertexByPosition(Vector2 position) { + return nodes.get(lookupIndex(position)); + } + + public boolean containsNode(Vector2 nodePosition) { + return nodes.containsKey(lookupIndex(nodePosition)); + } +} + diff --git a/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationMap.java b/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationMap.java new file mode 100644 index 00000000000..7984d6a43bb --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationMap.java @@ -0,0 +1,201 @@ +package forge.adventure.util.pathfinding; + +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.*; +import com.badlogic.gdx.utils.Array; +import forge.adventure.stage.MapStage; + +import java.util.ArrayList; +import java.util.Comparator; + +public class NavigationMap { + float spriteSize = 16f; + boolean rayCollided = false; + + public NavigationGraph navGraph = new NavigationGraph(); + + Array navBounds = new Array<>(); + float half = (spriteSize / 2); + + public NavigationMap(float spriteSize) { + this.spriteSize = spriteSize; + this.half = spriteSize / 2; + } + + RayCastCallback callback = new RayCastCallback() { + @Override + public float reportRayFixture(Fixture fixture, Vector2 vector2, Vector2 vector21, float v) { + if (v < 1.0) + rayCollided = true; + return 0; + } + }; + + public void initializeGeometryGraph() { + navGraph = new NavigationGraph(); + + for (int i = 0; i < MapStage.getInstance().collisionRect.size; i++) { + Rectangle r1 = MapStage.getInstance().collisionRect.get(i); + + if (r1.width < 3 && r1.height < 3) + continue; + int offsetX = -8; + int offsetY = 0; + + BodyDef bodyDef = new BodyDef(); + bodyDef.type = BodyDef.BodyType.StaticBody; + bodyDef.position.set(r1.x + r1.getWidth() / 2 + offsetX, r1.y + r1.getHeight() / 2 + offsetY); + Body body = MapStage.getInstance().gdxWorld.createBody(bodyDef); + + PolygonShape polygonShape = new PolygonShape(); + polygonShape.setAsBox(((r1.getWidth() + spriteSize) / 2), ((r1.getHeight() + spriteSize) / 2)); + FixtureDef fixture = new FixtureDef(); + fixture.shape = polygonShape; + fixture.density = 1; + + body.createFixture(fixture); + polygonShape.dispose(); + } + + float width = Float.parseFloat(MapStage.getInstance().tiledMap.getProperties().get("width").toString()); + float height = Float.parseFloat(MapStage.getInstance().tiledMap.getProperties().get("height").toString()); + float tileHeight = Float.parseFloat(MapStage.getInstance().tiledMap.getProperties().get("tileheight").toString()); + float tileWidth = Float.parseFloat(MapStage.getInstance().tiledMap.getProperties().get("tilewidth").toString()); + + NavigationVertex[][] points = new NavigationVertex[(int)width][(int)height]; + + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + points[i][j] = navGraph.addVertex(i* tileWidth + (tileWidth/ 2), j*tileHeight + (tileHeight/ 2)); + if (i > 0) { + navGraph.addEdgeUnchecked(points[i][j],points[i-1][j]); + } + + if (j > 0) { + navGraph.addEdgeUnchecked(points[i][j],points[i][j-1]); + } + + if (i > 0 && j > 0) { + navGraph.addEdgeUnchecked(points[i][j],points[i-1][j-1]); + } + + if (i > 0 && j + 1 < height) { + navGraph.addEdgeUnchecked(points[i][j],points[i-1][j+1]); + } + //remaining connections will be added by subsequent nodes + } + } + + Array fixtures = new Array<>(); + if (MapStage.getInstance().gdxWorld != null) { + MapStage.getInstance().gdxWorld.getFixtures(fixtures); + for (Fixture fix : fixtures) { + navGraph.removeVertexIf(vertex -> fix.testPoint(vertex.pos)); + } + } + + navGraph.removeVertexIf(v -> navGraph.getConnections(v).isEmpty()); + + //Add additional vertices for map waypoints + for (Vector2 waypointVector : MapStage.getInstance().waypoints.values()) { + NavigationVertex waypointVertex = navGraph.addVertex(waypointVector); + + ArrayList vertices = new ArrayList<>(navGraph.nodes.values()); + vertices.sort(Comparator.comparingInt(o -> Math.round((o.pos.x - waypointVector.x) * (o.pos.x - waypointVector.x) + (o.pos.y - waypointVector.y) * (o.pos.y - waypointVector.y)))); + + for (int i = 0, j=0; i < vertices.size() && j < 4; i++) { + if (waypointVector.epsilonEquals(vertices.get(i).pos)) + continue; //rayCast() crashes if params are equal + rayCollided = false; + MapStage.getInstance().gdxWorld.rayCast(callback, waypointVector, vertices.get(i).pos); + if (!rayCollided) { + navGraph.addEdgeUnchecked(waypointVertex, vertices.get(i)); + j++; + } + } + } + } + + + public ProgressableGraphPath findShortestPath(Float spriteSize, Vector2 origin, Vector2 destination) { + Array fixtures = new Array<>(); + MapStage.getInstance().gdxWorld.getFixtures(fixtures); + + boolean originPrecalculated = navGraph.containsNode(origin); + boolean destinationPrecalculated = navGraph.containsNode(destination); + + try { + if (!originPrecalculated) + navGraph.addVertex(origin); + + if (!destinationPrecalculated) + navGraph.addVertex(destination); + + ArrayList vertices = new ArrayList<>(); + + if (!(originPrecalculated && destinationPrecalculated)) { + vertices.addAll(navGraph.nodes.values()); + vertices.sort(Comparator.comparingInt(o -> Math.round((o.pos.x - origin.x) * (o.pos.x - origin.x) + (o.pos.y - origin.y) * (o.pos.y - origin.y)))); + } + + if (!originPrecalculated) { + for (int i = 0, j=0; i < vertices.size() && j < 10; i++) { + if (origin.epsilonEquals(vertices.get(i).pos)) + continue; //rayCast() crashes if params are equal + rayCollided = false; + MapStage.getInstance().gdxWorld.rayCast(callback, origin, vertices.get(i).pos); + if (!rayCollided) { + navGraph.addEdge(origin, vertices.get(i)); + j++; + } + } + } + + if (!destinationPrecalculated) { + for (int i = 0, j=0; i < vertices.size() && j < 10; i++) { + if (destination.epsilonEquals(vertices.get(i).pos)) + continue; //shouldn't happen, but would crash during rayCast if it did + rayCollided = false; + MapStage.getInstance().gdxWorld.rayCast(callback, vertices.get(i).pos, destination); + if (!rayCollided) { + navGraph.addEdge(destination, vertices.get(i)); + j++; + } + } + } + + + ProgressableGraphPath shortestPath = navGraph.findPath(origin, destination); + + if (false) { //todo - re-evaluate. 8-way node links may be smooth enough to skip the extra raycast overhead + //Trim path by cutting any unnecessary nodes + for (int i = 0; i < shortestPath.getCount(); i++) { + for (int j = shortestPath.getCount() - 1; j > i + 1; j--) { + rayCollided = false; + MapStage.getInstance().gdxWorld.rayCast(callback, shortestPath.get(i).pos, shortestPath.get(j).pos); + if (!rayCollided) { + shortestPath.remove(j - 1); + i = 0; + j = shortestPath.getCount(); + } + } + } + } + + if (!originPrecalculated) + navGraph.removeVertex(origin); + if (!destinationPrecalculated) + navGraph.removeVertex(destination); + return shortestPath; + } + catch(Exception e){ + if (!originPrecalculated && navGraph.lookupIndex(origin) > -1) + navGraph.removeVertex(origin); + if (!destinationPrecalculated && navGraph.lookupIndex(destination) > -1) + navGraph.removeVertex(destination); + throw(e); + } + } +} + diff --git a/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationVertex.java b/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationVertex.java new file mode 100644 index 00000000000..4a98adf04dd --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/util/pathfinding/NavigationVertex.java @@ -0,0 +1,43 @@ +package forge.adventure.util.pathfinding; + +import com.badlogic.gdx.ai.pfa.Connection; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.ObjectMap; + +public class NavigationVertex { + public Vector2 pos = Vector2.Zero; + public ObjectMap incomingEdges = new ObjectMap<>(); + public ObjectMap outgoingEdges = new ObjectMap<>(); + int index = -1; + + public NavigationVertex(Vector2 position) { + pos = position; + } + + public NavigationVertex(float x, float y) { + pos = new Vector2(x, y); + } + + public boolean hasEdgeTo(NavigationVertex otherNode) { + return incomingEdges.containsKey(otherNode); + } + + public Array> getAllConnections() { + + Array> ret = new Array<>(); + + for (NavigationEdge e : incomingEdges.values()) { + ret.add(e); + } + for (NavigationEdge e : outgoingEdges.values()) { + ret.add(e); + } + return ret; + } + + public void removeEdges(NavigationVertex node) { + outgoingEdges.remove(node); + incomingEdges.remove(node); + } +} \ No newline at end of file diff --git a/forge-gui-mobile/src/forge/adventure/util/pathfinding/ProgressableGraphPath.java b/forge-gui-mobile/src/forge/adventure/util/pathfinding/ProgressableGraphPath.java new file mode 100644 index 00000000000..dfca02fdfd6 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/util/pathfinding/ProgressableGraphPath.java @@ -0,0 +1,57 @@ +package forge.adventure.util.pathfinding; + +import com.badlogic.gdx.ai.pfa.GraphPath; +import com.badlogic.gdx.utils.Array; + +import java.util.Iterator; + +public class ProgressableGraphPath implements GraphPath { + public final Array nodes; + + /** Creates a {@code DefaultGraphPath} with no nodes. */ + public ProgressableGraphPath () { + this(new Array()); + } + + /** Creates a {@code DefaultGraphPath} with the given capacity and no nodes. */ + public ProgressableGraphPath (int capacity) { + this(new Array(capacity)); + } + + /** Creates a {@code DefaultGraphPath} with the given nodes. */ + public ProgressableGraphPath (Array nodes) { + this.nodes = nodes; + } + + @Override + public void clear () { + nodes.clear(); + } + + @Override + public int getCount () { + return nodes.size; + } + + @Override + public void add (N node) { + nodes.add(node); + } + + @Override + public N get (int index) { + return nodes.get(index); + } + + @Override + public void reverse () { + nodes.reverse(); + } + + @Override + public Iterator iterator () { + return nodes.iterator(); + } + + public void remove (int index) { nodes.removeIndex(index);} +} diff --git a/forge-gui/res/adventure/common/decks/standard/archivist.dck b/forge-gui/res/adventure/common/decks/standard/archivist.dck new file mode 100644 index 00000000000..99a13771b8a --- /dev/null +++ b/forge-gui/res/adventure/common/decks/standard/archivist.dck @@ -0,0 +1,36 @@ +[metadata] +Name=Archivist +[Main] +3 Ancient Den|BRC|1 +4 Archive Trap|PLIST|1 +3 Archivist|ULG|1 +2 Archivist of Oghma|CLB|2 +2 Automatic Librarian|DMU|1 +4 Bury in Books|J22|1 +4 Compulsive Research|CLB|1 +4 Field Research|ZNR|1 +3 Geist of the Archives|EMN|1 +2 Ghost Quarter|SLD|1 +2 Island|JMP|1 +1 Island|JMP|3 +1 Island|JMP|4 +1 Island|JMP|5 +2 Island|JMP|7 +4 Jace's Archivist|M12|1 +2 Key to the Archive|YMID|1 +3 Magus of the Moat|FUT|1 +2 Oath of Lieges|EXO|1 +2 Ormos, Archive Keeper|JMP|1 +4 Overwhelmed Archivist|MID|1 +1 Plains|JMP|1 +1 Plains|JMP|7 +1 Preston, the Vanisher|J22|1 +4 Razortide Bridge|BRC|1 +4 Seat of the Synod|J22|1 +2 Temple of Enlightenment|SCD|1 +1 Tolarian Academy|VMA|1 +1 Tome of the Infinite|J21|1 +4 Walking Archive|PLIST|1 +2 Winds of Abandon|PLIST|1 +[Sideboard] +1 Wizard's Spellbook|AFR|1 diff --git a/forge-gui/res/adventure/common/decks/standard/golem_sentinel.dck b/forge-gui/res/adventure/common/decks/standard/golem_sentinel.dck new file mode 100644 index 00000000000..590395187f1 --- /dev/null +++ b/forge-gui/res/adventure/common/decks/standard/golem_sentinel.dck @@ -0,0 +1,24 @@ +[metadata] +Name=Golem Sentinel +[Main] +4 Amaranthine Wall|DOM|1 +4 Consulate Skygate|BBD|1 +4 Living Wall|30A|1 +3 Plains|DMU|1 +7 Plains|DMU|2 +6 Plains|DMU|3 +5 Plains|DMU|4 +4 Rolling Stones|STH|1 +4 Secluded Steppe|J21|1 +4 Shield-Wall Sentinel|DMU|1 +4 Stalwart Shield-Bearers|ROE|1 +4 Steel Wall|TD2|1 +1 Sunweb|MIR|1 +4 Walking Bulwark|DMU|1 +4 Wall of Junk|DMR|1 +4 Wall of Spears|DPA|1 +1 Wall of Swords|30A|1 +4 Weathered Sentinels|NCC|1 +4 Wingmantle Chaplain|DMU|1 +[Sideboard] + diff --git a/forge-gui/res/adventure/common/decks/standard/golem_sentinel_2.dck b/forge-gui/res/adventure/common/decks/standard/golem_sentinel_2.dck new file mode 100644 index 00000000000..5eb7c1f4285 --- /dev/null +++ b/forge-gui/res/adventure/common/decks/standard/golem_sentinel_2.dck @@ -0,0 +1,20 @@ +[metadata] +Name=Golem Sentinel 2 +[Main] +4 Buried Ruin|ONC|1 +4 Chief of the Foundry|BRC|1 +4 Chronomaton|DDM|1 +4 Cryptic Caves|M20|1 +4 Darksteel Citadel|BRC|1 +4 Desert|AFC|1 +4 Haunted Guardian|AVR|1 +4 Lightning-Core Excavator|J21|1 +4 Locthwain Gargoyle|J22|1 +4 Patchwork Automaton|NEO|1 +4 Steel Overseer|J22|1 +4 Urza's Saga|MH2|1 +4 Walking Ballista|J22|1 +4 Wall of Forgotten Pharaohs|AKR|1 +4 Wall of Junk|DMR|1 +[Sideboard] + diff --git a/forge-gui/res/adventure/common/decks/standard/golem_sentinel_3.dck b/forge-gui/res/adventure/common/decks/standard/golem_sentinel_3.dck new file mode 100644 index 00000000000..a105a1f01d5 --- /dev/null +++ b/forge-gui/res/adventure/common/decks/standard/golem_sentinel_3.dck @@ -0,0 +1,20 @@ +[metadata] +Name=Golem Sentinel 3 +[Main] +4 Buried Ruin|ONC|1 +4 Chief of the Foundry|BRC|1 +4 Chronomaton|DDM|1 +4 Cryptic Caves|M20|1 +4 Custodian of the Trove|DTK|1 +4 Darksteel Citadel|BRC|1 +4 Desert|AFC|1 +4 Haunted Guardian|AVR|1 +4 Lightning-Core Excavator|J21|1 +4 Locthwain Gargoyle|J22|1 +4 Patchwork Automaton|NEO|1 +4 Steel Overseer|J22|1 +4 Urza's Saga|MH2|1 +4 Walking Ballista|J22|1 +4 Wall of Forgotten Pharaohs|AKR|1 +[Sideboard] + diff --git a/forge-gui/res/adventure/common/decks/standard/pirate2.dck b/forge-gui/res/adventure/common/decks/standard/pirate2.dck new file mode 100644 index 00000000000..245287e0533 --- /dev/null +++ b/forge-gui/res/adventure/common/decks/standard/pirate2.dck @@ -0,0 +1,34 @@ +[metadata] +Name=Pirate 2 +[Main] +2 Abrade|SCD|1 +2 Admiral Beckett Brass|PLIST|1 +4 Aether Hub|KLR|1 +1 Aethersphere Harvester|KLR|1 +1 Canyon Slough|AKR|1 +2 Captain Lannery Storm|J22|1 +1 Censor|J21|1 +3 Chandra, Torch of Defiance|Q06|1 +4 Deadeye Tracker|XLN|1 +4 Dire Fleet Captain|XLN|1 +2 Dire Fleet Ravager|XLN|1 +3 Dragonskull Summit|DMC|1 +2 Dreamcaller Siren|XLN|1 +3 Drowned Catacomb|SLD|1 +4 Fatal Push|F17|1 +3 Fathom Fleet Captain|XLN|1 +2 Fell Flagship|XLN|1 +1 Fetid Pools|AKR|1 +2 Fiery Cannonade|CMR|1 +3 Island|LTR|1 +3 Jace, Cunning Castaway|PS18|1 +3 Kari Zev, Skyship Raider|J22|1 +2 Lightning-Rig Crew|CMR|1 +3 Lookout's Dispersal|J22|1 +2 March of the Drowned|XLN|1 +2 Mountain|WHO|1 +4 Spirebluff Canal|KLR|1 +3 Swamp|LTR|1 +4 Unlicensed Disintegration|KLD|1 +[Sideboard] + diff --git a/forge-gui/res/adventure/common/decks/standard/pirate3.dck b/forge-gui/res/adventure/common/decks/standard/pirate3.dck new file mode 100644 index 00000000000..a75fe03feef --- /dev/null +++ b/forge-gui/res/adventure/common/decks/standard/pirate3.dck @@ -0,0 +1,29 @@ +[metadata] +Name=Pirate 3 +[Main] +4 Captain Lannery Storm|J22|1 +2 Captivating Crew|XLN|1 +4 Chart a Course|JMP|1 +2 Daring Saboteur|NCC|1 +3 Dire Fleet Hoarder|2XM|1 +4 Dragonskull Summit|DMC|1 +2 Dreamcaller Siren|XLN|1 +4 Drowned Catacomb|SLD|1 +2 Evolving Wilds|SIS|1 +4 Fatal Push|F17|1 +4 Fathom Fleet Captain|XLN|1 +2 Fell Flagship|XLN|1 +2 Island|LTR|1 +4 Kitesail Freebooter|XLN|1 +4 Lookout's Dispersal|J22|1 +2 Mountain|WHO|1 +4 Negate|MOM|1 +4 Ruin Raider|XLN|1 +4 Siren Stormtamer|CMR|1 +4 Spirebluff Canal|KLR|1 +2 Swamp|LTR|1 +4 Tezzeret the Schemer|KLR|1 +2 Walk the Plank|XLN|1 +2 Wanted Scoundrels|XLN|1 +[Sideboard] + diff --git a/forge-gui/res/adventure/common/decks/standard/pirate_captain_2.dck b/forge-gui/res/adventure/common/decks/standard/pirate_captain_2.dck new file mode 100644 index 00000000000..059aa3ae0bb --- /dev/null +++ b/forge-gui/res/adventure/common/decks/standard/pirate_captain_2.dck @@ -0,0 +1,29 @@ +[metadata] +Name=Pirate Captain 2 +[Main] +1 Blood Money|CLB|2 +2 Deadeye Tracker|XLN|1 +4 Deadly Derision|MOM|1 +4 Desperate Castaways|MB1|1 +2 Dire Fleet Hoarder|2XM|1 +2 Dire Fleet Interloper|XLN|1 +2 Dire Fleet Poisoner|J21|1 +1 Dire Fleet Ravager|XLN|1 +4 Drain Life|5ED|1 +4 Fathom Fleet Captain|XLN|1 +2 Sleek Schooner|XLN|1 +2 Kitesail Freebooter|XLN|1 +2 March of the Drowned|XLN|1 +1 Marut|CLB|1 +4 Pirate's Cutlass|CMR|1 +1 Pitiless Plunderer|RIX|1 +2 Reckoner Bankbuster|NEO|1 +1 Revel in Riches|XLN|1 +6 Swamp|XLN|1 +8 Swamp|XLN|2 +2 Swamp|XLN|3 +4 Swamp|XLN|4 +1 Treasure Chest|AFR|3 +1 Treasure Vault|AFR|1 +2 Undercity Scrounger|NEO|1 +[Sideboard] diff --git a/forge-gui/res/adventure/common/decks/standard/spirit.dck b/forge-gui/res/adventure/common/decks/standard/spirit.dck new file mode 100644 index 00000000000..0d401b34e38 --- /dev/null +++ b/forge-gui/res/adventure/common/decks/standard/spirit.dck @@ -0,0 +1,25 @@ +[metadata] +Name=Spirit +[Main] +2 Dreamshackle Geist|DBL|1 +4 Dungeon Geists|DKA|1 +4 Ephara's Dispersal|MOM|1 +2 Geist of the Archives|EMN|1 +10 Island|MOM|1 +4 Island|MOM|2 +4 Island|MOM|3 +1 Kira, Great Glass-Spinner|JMP|1 +4 Lantern Bearer|DBL|1 +1 Latch Seeker|AVR|1 +2 Mirrorhall Mimic|DBL|1 +1 Murmuring Phantasm|JMP|1 +4 Patrician Geist|DBL|1 +4 Shriekgeist|IMA|1 +4 Sinister Sabotage|SCD|1 +1 Stormbound Geist|DKA|1 +4 Supreme Phantom|M19|1 +2 Think Tank|ODY|1 +4 Thoughtbound Phantasm|GRN|1 +4 Tocasia's Dig Site|BRO|1 +[Sideboard] + diff --git a/forge-gui/res/adventure/common/maps/map/_template.tmx b/forge-gui/res/adventure/common/maps/map/_template.tmx new file mode 100644 index 00000000000..36c1b541012 --- /dev/null +++ b/forge-gui/res/adventure/common/maps/map/_template.tmx @@ -0,0 +1,38 @@ + + + + + eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ== + + + + + eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ== + + + + + + + + eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ== + + + + + eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ== + + + + + + + + + + + See https://github.com/Card-Forge/forge/wiki/Create-new-Maps for instructions & tips + + + + diff --git a/forge-gui/res/adventure/common/maps/map/main_story/templeofchandra.tmx b/forge-gui/res/adventure/common/maps/map/main_story/templeofchandra.tmx index 57fe3a1f26a..ef636fe4d17 100644 --- a/forge-gui/res/adventure/common/maps/map/main_story/templeofchandra.tmx +++ b/forge-gui/res/adventure/common/maps/map/main_story/templeofchandra.tmx @@ -1,5 +1,5 @@ - + { @@ -937,7 +937,7 @@ - + @@ -1560,6 +1560,10 @@ - + + + + + diff --git a/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_0.tmx b/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_0.tmx new file mode 100644 index 00000000000..3d72f464ba6 --- /dev/null +++ b/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_0.tmx @@ -0,0 +1,87 @@ + + + + + + + + + + eJyLZWFgiB3Fo3gUj+JRjBMnWgyMvaKWDAwSQHzecuDsPz1AdjdZDVy4g+yGhfm0Wdgxuh5i1RHCT61xm4dLD6X2ngP6NXkAwhrmV2ScxomK8cmhyxPr12YrwvYSwqTaa4jFrzB7J7ATh4m1F5Zvkiyw+5VW9oLKC0lLhgZ8aYkW9hKDR+2ln720zEejeBSP4lE8ikcxAMAE71k= + + + + + eJztlktOwzAQhr2gaQVsOQewQ+otWPJq98AdvOEAOE1bNSycBQgOE9hUPMqGozDFNh3cOH61pUj80q82ztjfTOyMQshMbGR2Cu6BM3AfPAAPwTu5+GVoPJPxfc0uYoLDhx45ZHK858nSlQluV2cqqxoxJ0VxoYJ1+EDjMlEbhXEK9ynkRoFLgUOZGPt+1qGC+bwvuc8Vz1sxXuX1ANXbi+BCXRzy7gbk+8UOlcw7mnvrMAfHyPPzcQ3vCgOnudg3dX6H8r8yk3vMIuvFUvup9vEF8VJxrqxnuBXJNnkVOi0I6RRxa1xtE3JACF01N0Q+3GZNTROPeid8xn3nrrP8dMzn7RJzEpBPOzDHGI3R897dIGRPs9JhIaykx+2jWBe1EbeEuY+aTdLjngyxdxVjY+1acR8SQi4awlNNip+/U6n790k910Ulyv2IV58f/SyVlnp9uWfcHt/5Y9y3X+LqWgbXpbWuQ70jWDO3+KaG27Sw8H21xlYy349M3lzg+xviGO55Y9aHsFVP0nsZ9mUjnGtS6VmXy3esSbif+3IXJRM39Ds1lrtItSq+u+q4MXtp07rtr60nLYu7bP1z/fUJ3KlgJA== + + + + + + + + eJzdld9OE0EUxmcv4a6F/qH/0Cvju5gYjZqAAone+AAlQRSF6iOgie2WtvRWo2JpLTa+g6RaLDwDGn0Bv+OeyR7b2W67hV7wJV92ujszvznnzExjJaVmikp9g492lTquOn6JNilfVSPL5jHbYr422m0wwnCs5PbV7MOCY1oDsYNyiUksPZ9mmkTssO2Y1kDMoFxyW8znxdTSOZg5A65mybwOI2J2RI2kk3DK8J58uOvWOIj+cbHmDurzHf7KpnqlK0rNw23xnnxE34vjc2M7MOoThUPCS2CuVJzahWy3jnGuZRCurke32n+uBkmem5Pq/3ONoo7Iqz5Xg5jy3FC+B+lySG16fYuJHPbeK73W90JI5NtPYPtK3ysU/y3b3Vd3bP97IYh67zSKZ1twX+mcFM1jhtUVxH51QPx6Ts0NytnLKlXLur8fhJV6GPYft1NWqlQenad1uqrUn1Xzt0XDvF28SyDOm+wkfByAT/HW4Ua2/9sy5nsRc9pb/FwAZ05wT9DnHuc7x32e47nis5b34N1AvLcNMS8bxhJzES6UHd9FO1Xp7+fHvQbedfjXkNzXYOThBM5rEi6gbQfgUqwfevaWvktM3B9gVKmm8H24S7kOwP0J7m+PvWXiDis/LumNYU9Nguuli8p9O6XUu6nJc0+ncY6mJ8/10nlzvf77L2q8XsqX3XtYeknMueDRxx6D6yWZh6BxbcHr3F6DH8HPzoG7yXMTLwfPW0o94XYG7Rh8yRqfuyEYpCjmnIUP4C/8jMB7cAPehz+fAZdiSMCfLIf/WDmMddGnhd9zQ8Q5CrfGcTU5tn1mxJmha5nkfPvVdlguiXJNNdUxNjn+p8qtbY3XQ7nIeU00ApeYlFvaL2nL+U28j5z/CMdO7xvMTlvuWFP8ftw1Zs6KWOh3StQ8yhz9zHCdN3htppoP4kom1bfGtY1YbuwZfk/7l/ZW3XLqHOen15kaxE1aLlPmKyq4LcOceh1NXmd9RG6LmaQmj9cxH4hvfwG8OnNz + + + + + eJztw0EJADAMBLCanLsam5s9TsKgj5JAqgB2O53TbicAAAB/HhT3BM0= + + + + + eJxjYBgcYPq8gTHzOpqasqkMDOVTibcDm3p0M4kB24BmbCfBXlLVDwZwg4pxTEp6ISc+6GHWQAD09EpqeicWoMc1enrFln6pUQagxw85ZQA1ADYzqZn+6Ql8lg20C+gPWFcMtAvwg8AFDAyzFwy0K4YfeLSQPDliALH5SGQBZfbAgDuRabgHj7uo5RZ0ILiAoQGZL0Qje4gFwnSwH58dnTQqY0Px2AkDYUSoGQWjYBSMglEwCgYTAADYSDkG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_1.tmx b/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_1.tmx new file mode 100644 index 00000000000..f7eb1294c9d --- /dev/null +++ b/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_1.tmx @@ -0,0 +1,244 @@ + + + + + + + eJzjVWdg4B3Fo3gUj+JRPIpH8SgexVTDAA08eeE= + + + + + eJxjYBhaYIsEBNMbbJeAYHoDeQEGBkUB6ph1EGjOISJxOz9DgqoAQwKx6g9TyY3U9O9A2dvIz8DQRCRWAdqpLEC8+mZ+/H5QoBHGFzZ7gXL7iMRtQPe38hOvfv9ouoKD0fxLH3tHwxk74FVH2Ati0wvA6t6BqoMpAQDikGk6 + + + + + + + + eJwz4WNgMBlCGAYoNccciC8BsbIKA4OqCoQG4Ut82DEMXELShwurQs0xw2KvKdSsgyr4MQgsF0XY2yJOvD5jPPbSEuCzFxQuSmjhhM5HB+jy6HGlRIR/QWFyAC2M0PnoAF0eHR8exOHMooZQh4uNCxDSOxj9i56WVCHsBnzpCkeexdCDz15GKfyYSQrTXmL1DMZwVsUSZugYHaDn9WRJzDxMyF5c+Q9f/sWV1w+rDP5ykhBoFMcUa8YiRqy9M3kZGKYRidEBsfpm8FKnzoeBgW6DkIIBPQOT6g== + + + + + eJztw7ENAAAIA6D+ov/f6NrVHRIS2m4yFQDg6wBDvwEe + + + + + + [ +{ + "text": "Anatomical studies of various mundane animals are found on this shelf. Open on top is a text on snakes. Why did it have to be snakes?", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "This shelf contains books of recipes, but many of the ingredients are unfamiliar to you.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "Here you find not so much books as collections of paperwork. It appears to consist of a series of caravan manifests and shipping ledgers affixed to maps. Comments and questions scribbled onto a set of calendars indicate that whomever collected these records suspected that the associated merchants were frequently conducting additional undocumented business along their routes.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "'The Impact of Personal Teleportation on Intercity Commerce' - Doesn't exactly sound like a page turner.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "Here you find a collection of copied plans for various goblin inventions. The transcriber added notes alongside each rating each on a scale between 'Will definitely explode' to 'Won't work well enough to explode'.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "Whatever knowledge was once contained in these texts is lost, their pages long ago having been soaked in the same dark liquid that appears to have stained the shelves below them.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "Dust covered tomes of nondescript subjects fill this shelf. You have a feeling these have been untouched for quite some time.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "This shelf holds a journal with a sturdy cover which stands apart from the faded scrolls around it. The entries are a mystery to you, however, as they are written in some form of code.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "'Azgothian poems from a Midsummer Morning'. This book gives you a creepy feeling and you wisely leave the cover closed.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "Here you find a collection of biographies of wizards you've never heard of, and a quick skim of the contents makes you wonder who would bother to write these.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "A collection of children's drawings fill this bookcase, although unlike most similar collections these all seem to depict arcane subjects.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + [ +{ + "text": "Here you find a blueprint of the library itself. Unfortunately, there doesn't seem to be any list of secret passages to take advantage of.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_2.tmx b/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_2.tmx new file mode 100644 index 00000000000..be4b6171229 --- /dev/null +++ b/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_2.tmx @@ -0,0 +1,144 @@ + + + + + + + eJzjVWdg4B3Fo3gUj+JRPIpH8SgexVTDAA08eeE= + + + + + eJxjYBhaYIsEBNMbbJeAYHoDeQEGBkUB6ph1EGjOISJxOz9DgqoAQwKx6g9TyY3U9O9A2dvIz8DQRCRWAdqpLEC8+mZ+/H5QoBHGFzZ7gXL7iMRtQPe38hOvfv9ouoKD0fxLH3tHwxk74FVH2Ati0wvA6t6BqoMpAQDikGk6 + + + + + + + + eJwz4WNgMBlCGAYoNccciC8BsbIKAquqoPJB+BJUHQxcwqIPHatC9ZlhsdcUatZBFfwYBJrEEfY2ihOvzxiPvbQE+OxVUmFowBdmyiqY5mGLD2QxJSL8e4BAeB3EYi8h9YM5nFnUEOr+SSLYyOK4AC69q0QJ20tLgM9e9PQBSmfo6QYdoKWnBmxsQvYySjEwMElBaHQME0cH2NSiY0L20hIQE87Y8iQx4QzKq8mSmPoJ2YsvDx4mIv+i539kPYMtnHNEGBiyRRDqkNkw0CKOKdaIJJYjgspGNgObvTN5GRimEYnRAbH6ZvBSp86HgYFug5CCARwpl9Q= + + + + + eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ== + + + + + + + + + + + + + [ +{ + "text": "'Magical Meteorology', 'The Destructive Power of the Heavens', these books all seem to focus on things falling from the sky.", + + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + + + [ +{ + "text": "Here you find a collection of biographies of wizards you've never heard of. None of them seem to have done anything significant.", + "options": [{ + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] +} +] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_3.tmx b/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_3.tmx new file mode 100644 index 00000000000..beda9840bfc --- /dev/null +++ b/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_3.tmx @@ -0,0 +1,138 @@ + + + + + + + eJzjVWdg4B3Fo3gUj+JRPIpH8SgexVTDAA08eeE= + + + + + eJxjYBhaYIsEBNMbbJeAYHoDeQEGBkUB6ph1EGjOISJxOz9DgqoAQwKx6g9TyY3U9O9A2dvIz8DQRCRWAdqpLEC8+mZ+/H5QoBHGFzZ7gXL7iMRtQPe38hOvfv9ouoKD0fxLH3tHwxk74FVH2Ati0wvA6t6BqoMpAQDikGk6 + + + + + + + + eJzVVlsOwiAQXI2/9c806WelXsCq10PjGYyewGtU7Qk4kRAgJSsL+Io4yQSa7DDphAXaKUD7R7R4d52NpJCcM4CG6dFHYeoshKOj2Bjd2uO7MmtdZE3P9OijwrYEbn335aALUWEZ8P0mQr4ql5oBx1nVzhyDytbVxnxVJh3KCH9jxDK+ZZzzZDHUUXMKMW2O/4v3ka+XMYh9xbEm5DuqwhxXj76pmhxzps5It6cxQudjas5U/6X2b+fRXZk+V3PMOYadcydYnGev+54KgEMiMVJ1x+Izd77Fr98gz/AOyNmTVw== + + + + + eJztwTEBAAAAwqD1T20JT6AAAHgaCWAAAQ== + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_4.tmx b/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_4.tmx new file mode 100644 index 00000000000..4938300b275 --- /dev/null +++ b/forge-gui/res/adventure/common/maps/map/main_story_explore/library_of_varsil_4.tmx @@ -0,0 +1,94 @@ + + + + + + + + + + eJzjVWdg4B1CGAbQxQbaXaN4FI/iUTyKR/EoHsUwDADG93lF + + + + + eJxjYBgFowATNPIzMDTz099eeQEGBkUB+toJ8qsK0E5lAfr6GeRXBSim1M/RNgNjLymA1vaK+FLX3hBrPHI+hPWTau91oH038NhJLKBlOE/B4296patQtHimhb1XaBC/lIIwX4aGgbAXBgbK3u0SqHgoAQAY1RaZ + + + + + + + + eJwz4WNgMBmB2ByIL9EYm2Gx1xSIaQ2MR+0dlvZetMZvb7QNcTjWBmFmJJC9wAbTrms+mGKU+jcOyZ54LHbiArSw9yowLEWh4XnRioEhBMq+Ys3QQIm94ta47b1mjapOEMq/DKXDfRkYInxJszfcjzj/ooMr1phitIxfYHpKwKWPVvai+3GSNaoYOfZKIKUPfP6VwBK+lNiLDKiZj2byMjBMIxKj20usvhm8lNXV6GCg2w6kYACuCn5U + + + + + eJxjYBgFo2AUjALaAHEf6qojFoQTaR6x6kYBdkDteCMWEBtvEaPxOwoGEAAAArYDtw== + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forge-gui/res/adventure/common/maps/map/main_story_explore/shard_mines.tmx b/forge-gui/res/adventure/common/maps/map/main_story_explore/shard_mines.tmx new file mode 100644 index 00000000000..e16ff8ff004 --- /dev/null +++ b/forge-gui/res/adventure/common/maps/map/main_story_explore/shard_mines.tmx @@ -0,0 +1,1406 @@ + + + + + + + + + +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893, +8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893,8893 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5016,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5173,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5174,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,5173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5498,5653,5653,0,0, +0,0,0,0,0,0,0,0,0,0,12181,0,0,0,0,0,0,0,0,0,0,0,5498,5653,5653,5654,1939,0,0,0, +0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,5498,5654,1941,24408,24409,24409,24729,0,0, +0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,5016,5015,5496,0,24408,24729,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,5496,2097,24724,24571,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,5015,0,0,0,0,0,5656,5337,5338,24724,24571,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,5656,5338,24724,24571,0,0,0, +0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,5016,0,0,0,5496,0,24566,0,0,0, +0,0,0,0,0,0,0,5020,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,5498,5654,24408,24729,0,0,0, +0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,5498,5654,0,24724,24571,0,0,0, +0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,5656,5338,0,24408,24729,0,0,0, +0,0,0,0,0,0,0,0,0,0,12372,12373,12373,12243,12373,12373,12373,12373,12245,12245,12247,12245,12311,5496,0,24566,12307,12373,12373,12245, +0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,12308,0,0,5656,5338,24724,24571,24570,24571,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,5177,0,0,0,0,12310,0,0,0,5496,0,24724,24726,24724,24725, +0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,12310,0,0,0,5656,5338,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,12437,0,0,0,0,0,0,12308,0,0,0,0,5656,5337,5337,24410,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,24728,24410, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5016,0,0,12310,0,0,0,0,0,0,0,0,24728, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5015,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12180,12373,12373,12373,12245,12245,12311,0,0,0, +0,0,0,0,0,0,0,0,0,0,5015,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,5016,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,5173,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5174,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,5015,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,8610,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,5025,5026,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,5183,5184,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8931,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0, +0,0,5016,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,2147492421,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12244,12373,12373,12374,0,0,0,0,0,0,0,5174,0, +0,0,0,0,5173,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,8931,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12244,12373,12374,0,0,5025,5026,0,0,0,0,5174,12181,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,5183,5184,0,0,0,0,0,12310,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,12244,12373,12374,0,0,0,0,0,0,0,0,0,0,0,12308,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,8609,0,0,0,0,0,0,0,0,0,12308,0,0, +0,0,0,0,0,0,0,0,0,12244,12245,12245,12245,12374,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0, +0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0, +0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0, +0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5178,0,0,12308,0,0, +0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,2147488821,0,0,0,0,0,0,0,12310,0,0, +0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,2147488664,8610,0,0,0,0,0,0,12308,0,0, +0,0,0,0,5016,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,12244,12245,12373,12245,12245,12374,0,0, +0,0,0,0,0,0,0,12244,12373,12374,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0, +0,0,0,0,8773,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0, +0,0,0,5173,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12372,12373,12246,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,8610,0,0,0,0, +0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,12372,12245,12373,12245,12373,12243,12373,12373,12245,12245,12373,12245,12245,12374,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,5178,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12244,12373,12373,12245,12243,12373,12373,12374,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12310,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12308,0,0,0,12308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12308,0,12307,12245,12374,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12310,0,0,0,6863,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + + +23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,23238,23238,4010,4324,4012,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,4166,4010,4325,0,4323,4324,4011,4011,4012,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,4010,4325,257,258,0,0,8611,8612,4323,4324,4324,4324,4012,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,4166,4010,4325,0,285,286,0,0,0,0,0,0,0,0,4323,4011,4011,4324,4012,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,4010,4325,8925,8926,0,0,9236,9237,0,0,0,0,0,0,0,0,0,0,4323,4324,4324,4324,4012,23238,23238,23238, +23238,23238,4166,4010,4325,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4323,4324,4012,23238, +23238,23238,4010,4325,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4007,4328,23238, +23238,23238,4167,0,0,8609,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4165,23238,23238, +23238,23238,4168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27947,0,0,0,0,0,0,0,0,4165,23238,23238, +23238,23238,4326,4009,2147511595,0,0,0,7179,0,16600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4165,23238,23238, +23238,23238,23238,4168,0,0,0,0,6863,0,16664,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4323,4011,4324, +23238,23238,23238,4326,4009,0,0,0,6863,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27681,0, +23238,23238,23238,4166,4168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28308,28309,0,0,0, +23238,23238,23238,4166,4326,4009,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +23238,23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2097,0,0,0,0, +23238,23238,23238,23238,23238,4326,4009,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2038,0,0,0, +23238,23238,23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27997,27998,0, +23238,23238,23238,23238,23238,23238,4326,4009,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1855,0,0,0,0,0, +23238,23238,23238,23238,23238,23238,4166,4167,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2038,0,0,0,0, +23238,23238,23238,23238,23238,23238,4010,4325,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2023,2023,2024,1865,1866,0,0,0, +23238,23238,23238,23238,23238,23238,4168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1862,0,0,0,0,0, +23238,23238,23238,23238,23238,4010,4325,0,0,0,0,8860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +23238,23238,23238,4166,4010,4325,0,0,0,0,0,0,9548,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27845,0, +23238,23238,23238,4010,4325,0,0,0,0,0,0,9547,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4007,4327,4009,0, +23238,23238,23238,4168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4323,4012,4168,0, +23238,23238,4010,4325,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4170,4326,4327, +23238,4010,4325,0,0,0,0,0,4007,4327,4009,0,0,0,0,0,0,0,0,0,0,0,0,0,8874,0,0,4323,4012,23238, +23238,4167,0,0,0,0,0,0,4165,4166,4326,4009,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4170,23238, +23238,4167,0,0,0,0,0,0,4165,23238,23238,4168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4170,23238, +23238,4167,0,0,0,0,0,4007,4328,23238,23238,4326,4009,0,0,0,0,0,0,0,0,0,0,6863,6863,2147492257,0,4007,4328,23238, +23238,4167,0,0,0,0,0,4165,23238,4010,4012,4166,4326,4009,0,0,0,0,0,0,0,0,0,0,0,0,0,4165,23238,23238, +23238,4168,0,27947,0,0,0,4165,23238,4167,4323,4012,23238,4168,0,2147492258,0,0,0,0,0,0,0,0,16983,16984,0,4170,23238,23238, +23238,4167,0,0,0,0,0,4165,23238,4168,0,4165,23238,4326,4009,0,0,0,0,0,0,0,0,0,0,0,0,4170,23238,23238, +23238,4167,0,0,0,0,0,4170,23238,4167,0,4323,4012,4166,4326,4009,0,0,0,0,0,0,0,0,0,0,0,4170,23238,23238, +23238,4167,0,0,0,0,4007,4328,23238,4168,0,0,4323,4012,23238,4168,0,27947,0,0,0,0,0,0,0,0,0,4170,23238,23238, +23238,4168,0,0,0,0,4170,23238,4010,4325,0,0,0,4165,23238,4326,4009,0,0,0,0,0,0,0,0,0,0,4323,4012,23238, +23238,4167,0,0,0,0,4165,23238,4167,0,0,0,0,4323,4012,23238,4167,0,0,0,0,0,0,0,0,0,0,0,4165,23238, +23238,4167,0,0,0,0,4165,23238,4168,0,0,0,0,0,4165,23238,4168,0,0,0,0,0,0,0,0,0,0,0,4165,23238, +23238,4168,0,0,0,0,4170,23238,4168,0,0,0,0,0,4170,23238,4326,4009,0,0,0,0,0,0,0,0,0,0,4165,23238, +23238,4168,0,0,0,4007,4328,23238,4167,0,0,0,0,0,4323,4012,23238,4167,0,0,0,0,0,0,0,0,0,0,4170,23238, +23238,4168,0,0,0,4165,23238,4010,4325,0,0,0,0,0,0,4170,23238,4167,0,0,0,0,0,0,0,0,0,0,4170,23238, +23238,4168,0,0,0,4170,23238,4167,0,0,0,0,0,0,0,4165,23238,4168,0,0,0,0,0,0,0,0,0,0,4323,4012, +23238,4168,0,0,0,4165,23238,4167,8931,0,0,0,0,0,4007,4328,23238,4326,4009,0,0,0,0,0,0,0,0,0,4007,4328, +23238,4167,0,0,0,4323,4324,4325,0,0,0,0,0,0,4170,23238,23238,23238,4168,0,0,0,0,0,0,0,0,0,4165,23238, +23238,4167,0,0,0,0,0,0,0,0,0,0,0,0,4170,23238,23238,23238,4167,0,0,0,0,0,27946,0,0,4007,4328,23238, +23238,4168,0,0,0,0,0,0,0,0,0,0,0,4007,4328,23238,23238,23238,4168,0,0,0,0,0,0,0,0,4170,23238,23238, +23238,4168,0,0,0,0,0,0,0,0,0,0,4007,4328,23238,23238,23238,23238,4326,4009,0,0,0,0,0,0,4007,4328,23238,23238, +23238,4168,0,0,0,0,0,0,8875,0,0,4007,4328,23238,23238,23238,23238,23238,23238,4168,0,0,0,0,0,4007,4328,4166,23238,23238, +23238,4168,0,0,0,0,0,0,0,0,0,4165,23238,23238,23238,23238,23238,23238,23238,4167,0,0,0,0,4007,4328,23238,23238,23238,23238, +23238,4168,0,0,0,0,0,0,0,0,4007,4328,23238,23238,23238,23238,23238,4010,4324,4325,0,0,0,0,4170,23238,23238,23238,23238,23238, +23238,4168,0,0,0,0,0,0,0,4007,4328,23238,23238,23238,23238,4010,4324,4325,0,0,0,0,0,4007,4328,23238,23238,4010,4324,4012, +23238,4168,0,0,0,0,0,4007,4008,4328,23238,23238,4010,4324,4011,4325,0,0,0,0,0,0,4007,4328,4166,23238,23238,4167,0,4165, +23238,4168,0,0,0,0,4007,4328,23238,23238,23238,23238,4168,0,0,0,0,0,0,0,0,0,4165,23238,23238,23238,4010,4325,0,4165, +23238,4167,261,262,0,4007,4328,23238,23238,23238,23238,23238,4168,0,0,0,0,0,0,0,0,0,4170,23238,23238,23238,4167,0,0,4165, +23238,4167,289,290,4007,4328,23238,23238,23238,23238,23238,4010,4325,0,0,0,0,0,0,0,0,0,4170,23238,23238,4010,4325,0,7179,4165, +23238,4167,4007,4008,4328,4166,23238,23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,0,0,4165,23238,23238,4167,5173,0,4007,4328, +23238,4326,4328,23238,23238,23238,23238,23238,23238,23238,4010,4325,0,0,0,0,0,0,0,0,0,0,4165,23238,23238,4326,4009,0,4323,4012, +23238,23238,23238,23238,23238,23238,23238,4010,4324,4324,4325,0,0,0,0,0,0,0,4007,4327,4327,4327,4328,23238,23238,23238,4167,0,0,4165, +23238,23238,23238,23238,23238,23238,23238,4168,0,0,0,0,0,0,0,0,4007,4008,4328,23238,23238,23238,23238,23238,23238,23238,4168,0,0,4170, +23238,23238,23238,23238,23238,23238,4010,4325,0,0,0,0,0,0,0,4007,4328,23238,23238,23238,23238,23238,23238,23238,23238,23238,4168,0,0,4165, +23238,23238,23238,23238,23238,23238,4168,0,0,0,0,0,0,0,4007,4328,23238,23238,23238,23238,23238,23238,23238,23238,23238,4010,4325,0,0,4170, +23238,23238,23238,23238,23238,23238,4168,0,0,0,0,0,4007,4327,4328,4166,23238,23238,23238,4010,4012,23238,23238,4010,4324,4325,0,0,4007,4328, +23238,23238,23238,23238,23238,4010,4325,0,0,0,0,4007,4328,23238,23238,23238,23238,4010,4011,4325,4323,4011,4011,4325,0,0,0,0,4170,23238, +23238,23238,23238,23238,23238,4167,0,0,0,0,0,4170,23238,23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,0,0,4170,23238, +23238,23238,23238,4010,4324,4325,0,0,0,0,0,4170,23238,23238,23238,23238,23238,4326,4009,0,0,0,0,0,0,0,0,0,4170,23238, +23238,23238,23238,4168,0,0,0,0,0,0,0,4323,4012,23238,23238,23238,23238,23238,4168,0,0,0,0,0,0,0,0,0,4165,23238, +23238,23238,4010,4325,0,0,0,0,0,0,0,0,4165,23238,23238,23238,23238,23238,4326,4009,0,0,0,0,0,0,0,0,4165,23238, +23238,23238,4168,0,0,0,0,0,0,0,0,0,4170,23238,23238,23238,23238,23238,23238,4168,0,0,0,0,0,0,0,0,4165,23238, +23238,23238,4326,4009,0,0,0,0,0,0,0,27947,4170,23238,23238,23238,23238,23238,23238,4168,0,0,16600,0,0,0,0,0,4170,23238, +23238,23238,23238,4167,0,0,0,0,0,0,0,0,4323,4012,23238,23238,23238,4010,4324,4325,0,0,16664,0,0,0,0,0,4170,23238, +23238,23238,23238,4326,4009,0,0,0,0,0,0,0,0,4170,23238,23238,23238,4167,0,0,0,0,0,0,0,0,27946,0,4165,23238, +23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,4165,23238,23238,23238,4168,0,0,0,0,0,0,0,0,0,0,4165,23238, +23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,4165,23238,23238,23238,4167,0,0,0,0,0,0,0,0,0,0,4165,23238, +23238,23238,23238,23238,4326,4009,0,0,0,0,0,0,0,4323,4012,23238,4166,4168,0,0,0,0,0,0,0,0,0,4007,4328,23238, +23238,23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,4170,23238,4010,4325,27947,0,0,0,0,0,0,0,0,4170,23238,23238, +23238,23238,23238,23238,23238,4326,4009,0,0,0,0,0,0,0,4323,4011,4325,0,0,0,0,0,0,0,0,0,4007,4328,23238,23238, +23238,23238,23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4165,23238,23238,23238, +23238,23238,23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4007,4328,23238,23238,23238, +23238,23238,23238,23238,23238,23238,4168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4165,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,4168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4007,4328,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4165,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,4010,4325,0,0,27947,0,0,0,0,0,0,0,0,0,0,0,0,261,262,4170,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,289,290,4165,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,4326,4009,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4007,4328,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,4166,4326,4327,4327,4327,4009,0,0,0,0,0,0,0,27947,0,0,0,0,4170,4166,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,4167,0,0,0,0,0,0,0,0,0,0,0,4007,4328,4166,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,4326,4009,0,0,0,0,0,0,0,0,0,0,4170,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,4166,4167,0,0,0,0,0,0,0,0,0,4007,4328,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,4010,4325,0,0,0,0,0,0,0,0,4007,4328,4166,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,23238,23238,4010,4011,4325,0,0,0,0,0,0,0,0,4007,4328,4166,4166,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,4010,4324,4325,0,0,0,0,0,0,0,0,0,4007,4328,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,23238,4168,0,0,0,0,0,0,0,0,0,0,4007,4328,4166,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,4010,4325,16600,0,0,0,0,0,0,0,0,4007,4328,4166,4166,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,4168,0,16664,0,0,0,0,0,0,0,0,4170,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,23238,4167,0,0,0,12439,12440,0,0,0,0,4007,4328,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,4010,4325,0,0,0,16983,16984,0,0,27947,4007,4328,4166,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,23238,4167,0,0,0,0,26093,26093,0,0,4007,4328,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,4010,4325,0,0,0,0,28090,2147509583,8860,4007,4328,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238, +23238,23238,23238,4168,5242,0,0,0,0,28090,27932,4007,4328,4166,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238,23238 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,27839,27840,0,0,28150,28151,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28150,28151,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27839,27840,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12439,12440,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,16983,16984,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + [ + { + "type": "shards", + "count": 1, + "addMaxCount": 1 + } +] + + + + + [ + { + "type": "shards", + "count": 1, + "addMaxCount": 1 + } +] + + + + + [ + { + "type": "shards", + "count": 1, + "addMaxCount": 1 + } +] + + + + + [ + { + "type": "shards", + "count": 1, + "addMaxCount": 1 + } +] + + + + + [ + { + "type": "shards", + "count": 1, + "addMaxCount": 1 + } +] + + + + + [ + { + "type": "shards", + "count": 1, + "addMaxCount": 1 + } +] + + + + + + + [ + { + "type": "shards", + "count": 1, + "addMaxCount": 1 + } +] + + + + + + [{ + "count":3, + "type":"Union", + "probability": 1, + "cardUnion": [ + { + "count":1, + "cardName": "Mine Worker" + }, + { + "count":1, + "cardName": "Aethergeode Miner" + }, + { + "count":1, + "cardName": "Dwarven Blastminer" + }, + { + "count":1, + "cardName": "Dwarven Miner" + }, + { + "count":1, + "cardName": "Goblin Kaboomist" + }, + { + "count":1, + "cardName": "Pardic Miner" + }, + { + "count":1, + "cardName": "Duergar Mine-Captain" + }, + { + "count":1, + "cardName": "Akki Underminer" + }, + { + "count":1, + "cardName": "Miner's Bane" + }, + { + "count":1, + "cardName": "Mine Excavation" + }, + { + "count":1, + "cardName": "Howling Mine" + }, + { + "count":1, + "cardName": "Orcish Mine" + }, + { + "count":1, + "cardName": "Dwarven Mine" + }, + { + "count":1, + "cardName": "Gemstone Mine" + }, + { + "count":1, + "cardName": "Strip Mine" + }, + { + "count":1, + "cardName": "Urza's Mine" + }, + { + "count":1, + "cardName": "Excavator" + }, + { + "count":1, + "cardName": "Excavation Explosion" + }, + { + "count":1, + "cardName": "Soldevi Digger" + }, + { + "count":1, + "cardName": "Dig Up" + }, + { + "count":1, + "cardName": "Goblin Digging Team" + }, + { + "count":1, + "cardName": "Digsite Engineer" + }, + { + "count":1, + "cardName": "Destructive Digger" + }, + { + "count":1, + "cardName": "Crystal Grotto" + }, + { + "count":1, + "cardName": "Crystal Quarry" + }, + { + "count":1, + "cardName": "Crystal Vein" + }, + { + "count":1, + "cardName": "Stone Quarry" + }, + { + "count":1, + "cardName": "Duergar Cave-Guard" + }, + { + "count":1, + "cardName": "Gilded Assault Cart" + }, + { + "count":1, + "cardName": "Aggressive Mining" + } + ] +}] + + + + + [{ + "count":3, + "type":"Union", + "probability": 1, + "cardUnion": [ + { + "count":1, + "cardName": "Mine Worker" + }, + { + "count":1, + "cardName": "Aethergeode Miner" + }, + { + "count":1, + "cardName": "Dwarven Blastminer" + }, + { + "count":1, + "cardName": "Dwarven Miner" + }, + { + "count":1, + "cardName": "Goblin Kaboomist" + }, + { + "count":1, + "cardName": "Pardic Miner" + }, + { + "count":1, + "cardName": "Duergar Mine-Captain" + }, + { + "count":1, + "cardName": "Akki Underminer" + }, + { + "count":1, + "cardName": "Miner's Bane" + }, + { + "count":1, + "cardName": "Mine Excavation" + }, + { + "count":1, + "cardName": "Howling Mine" + }, + { + "count":1, + "cardName": "Orcish Mine" + }, + { + "count":1, + "cardName": "Dwarven Mine" + }, + { + "count":1, + "cardName": "Gemstone Mine" + }, + { + "count":1, + "cardName": "Strip Mine" + }, + { + "count":1, + "cardName": "Urza's Mine" + }, + { + "count":1, + "cardName": "Excavator" + }, + { + "count":1, + "cardName": "Excavation Explosion" + }, + { + "count":1, + "cardName": "Soldevi Digger" + }, + { + "count":1, + "cardName": "Dig Up" + }, + { + "count":1, + "cardName": "Goblin Digging Team" + }, + { + "count":1, + "cardName": "Digsite Engineer" + }, + { + "count":1, + "cardName": "Destructive Digger" + }, + { + "count":1, + "cardName": "Crystal Grotto" + }, + { + "count":1, + "cardName": "Crystal Quarry" + }, + { + "count":1, + "cardName": "Crystal Vein" + }, + { + "count":1, + "cardName": "Stone Quarry" + }, + { + "count":1, + "cardName": "Duergar Cave-Guard" + }, + { + "count":1, + "cardName": "Gilded Assault Cart" + }, + { + "count":1, + "cardName": "Aggressive Mining" + } + + ] +}] + + + + + [{ + "count":3, + "type":"Union", + "probability": 1, + "cardUnion": [ + { + "count":1, + "cardName": "Mine Worker" + }, + { + "count":1, + "cardName": "Aethergeode Miner" + }, + { + "count":1, + "cardName": "Dwarven Blastminer" + }, + { + "count":1, + "cardName": "Dwarven Miner" + }, + { + "count":1, + "cardName": "Goblin Kaboomist" + }, + { + "count":1, + "cardName": "Pardic Miner" + }, + { + "count":1, + "cardName": "Duergar Mine-Captain" + }, + { + "count":1, + "cardName": "Akki Underminer" + }, + { + "count":1, + "cardName": "Miner's Bane" + }, + { + "count":1, + "cardName": "Mine Excavation" + }, + { + "count":1, + "cardName": "Howling Mine" + }, + { + "count":1, + "cardName": "Orcish Mine" + }, + { + "count":1, + "cardName": "Dwarven Mine" + }, + { + "count":1, + "cardName": "Gemstone Mine" + }, + { + "count":1, + "cardName": "Strip Mine" + }, + { + "count":1, + "cardName": "Urza's Mine" + }, + { + "count":1, + "cardName": "Excavator" + }, + { + "count":1, + "cardName": "Excavation Explosion" + }, + { + "count":1, + "cardName": "Soldevi Digger" + }, + { + "count":1, + "cardName": "Dig Up" + }, + { + "count":1, + "cardName": "Goblin Digging Team" + }, + { + "count":1, + "cardName": "Digsite Engineer" + }, + { + "count":1, + "cardName": "Destructive Digger" + }, + { + "count":1, + "cardName": "Crystal Grotto" + }, + { + "count":1, + "cardName": "Crystal Quarry" + }, + { + "count":1, + "cardName": "Crystal Vein" + }, + { + "count":1, + "cardName": "Stone Quarry" + }, + { + "count":1, + "cardName": "Duergar Cave-Guard" + }, + { + "count":1, + "cardName": "Gilded Assault Cart" + }, + { + "count":1, + "cardName": "Aggressive Mining" + } + + ] +}] + + + + + [{ + "count":3, + "type":"Union", + "probability": 1, + "cardUnion": [ + { + "count":1, + "cardName": "Mine Worker" + }, + { + "count":1, + "cardName": "Aethergeode Miner" + }, + { + "count":1, + "cardName": "Dwarven Blastminer" + }, + { + "count":1, + "cardName": "Dwarven Miner" + }, + { + "count":1, + "cardName": "Goblin Kaboomist" + }, + { + "count":1, + "cardName": "Pardic Miner" + }, + { + "count":1, + "cardName": "Duergar Mine-Captain" + }, + { + "count":1, + "cardName": "Akki Underminer" + }, + { + "count":1, + "cardName": "Miner's Bane" + }, + { + "count":1, + "cardName": "Mine Excavation" + }, + { + "count":1, + "cardName": "Howling Mine" + }, + { + "count":1, + "cardName": "Orcish Mine" + }, + { + "count":1, + "cardName": "Dwarven Mine" + }, + { + "count":1, + "cardName": "Gemstone Mine" + }, + { + "count":1, + "cardName": "Strip Mine" + }, + { + "count":1, + "cardName": "Urza's Mine" + }, + { + "count":1, + "cardName": "Excavator" + }, + { + "count":1, + "cardName": "Excavation Explosion" + }, + { + "count":1, + "cardName": "Soldevi Digger" + }, + { + "count":1, + "cardName": "Dig Up" + }, + { + "count":1, + "cardName": "Goblin Digging Team" + }, + { + "count":1, + "cardName": "Digsite Engineer" + }, + { + "count":1, + "cardName": "Destructive Digger" + }, + { + "count":1, + "cardName": "Crystal Grotto" + }, + { + "count":1, + "cardName": "Crystal Quarry" + }, + { + "count":1, + "cardName": "Crystal Vein" + }, + { + "count":1, + "cardName": "Stone Quarry" + }, + { + "count":1, + "cardName": "Duergar Cave-Guard" + }, + { + "count":1, + "cardName": "Gilded Assault Cart" + }, + { + "count":1, + "cardName": "Aggressive Mining" + } + + ] +}] + + + + + [{ + "count":3, + "type":"Union", + "probability": 1, + "cardUnion": [ + { + "count":1, + "cardName": "Mine Worker" + }, + { + "count":1, + "cardName": "Aethergeode Miner" + }, + { + "count":1, + "cardName": "Dwarven Blastminer" + }, + { + "count":1, + "cardName": "Dwarven Miner" + }, + { + "count":1, + "cardName": "Goblin Kaboomist" + }, + { + "count":1, + "cardName": "Pardic Miner" + }, + { + "count":1, + "cardName": "Duergar Mine-Captain" + }, + { + "count":1, + "cardName": "Akki Underminer" + }, + { + "count":1, + "cardName": "Miner's Bane" + }, + { + "count":1, + "cardName": "Mine Excavation" + }, + { + "count":1, + "cardName": "Howling Mine" + }, + { + "count":1, + "cardName": "Orcish Mine" + }, + { + "count":1, + "cardName": "Dwarven Mine" + }, + { + "count":1, + "cardName": "Gemstone Mine" + }, + { + "count":1, + "cardName": "Strip Mine" + }, + { + "count":1, + "cardName": "Urza's Mine" + }, + { + "count":1, + "cardName": "Excavator" + }, + { + "count":1, + "cardName": "Excavation Explosion" + }, + { + "count":1, + "cardName": "Soldevi Digger" + }, + { + "count":1, + "cardName": "Dig Up" + }, + { + "count":1, + "cardName": "Goblin Digging Team" + }, + { + "count":1, + "cardName": "Digsite Engineer" + }, + { + "count":1, + "cardName": "Destructive Digger" + }, + { + "count":1, + "cardName": "Crystal Grotto" + }, + { + "count":1, + "cardName": "Crystal Quarry" + }, + { + "count":1, + "cardName": "Crystal Vein" + }, + { + "count":1, + "cardName": "Stone Quarry" + }, + { + "count":1, + "cardName": "Duergar Cave-Guard" + }, + { + "count":1, + "cardName": "Gilded Assault Cart" + }, + { + "count":1, + "cardName": "Aggressive Mining" + } + + ] +}] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forge-gui/res/adventure/common/maps/map/main_story/waste_town_abandoned.tmx b/forge-gui/res/adventure/common/maps/map/main_story_explore/waste_town_abandoned.tmx similarity index 62% rename from forge-gui/res/adventure/common/maps/map/main_story/waste_town_abandoned.tmx rename to forge-gui/res/adventure/common/maps/map/main_story_explore/waste_town_abandoned.tmx index aac9e1d3a7e..52994567ec7 100644 --- a/forge-gui/res/adventure/common/maps/map/main_story/waste_town_abandoned.tmx +++ b/forge-gui/res/adventure/common/maps/map/main_story_explore/waste_town_abandoned.tmx @@ -1,7 +1,7 @@ - + - + @@ -13,12 +13,12 @@ - eJztk0EKwjAURLN3p+cQREHrzQqCincQT+E99CAuvIUJrRDEtjHWziTO4pEufmEe/085MqYkZl4Ys1vhc/TBcY3P8C1bu4vJEp9Du6i4F/gMfZBTz53L1XbkVr8O322cWH/Om+p13Z/VTnv7fUqsQ24vF5t98dKZaUYdQmcQQggRx8EjZMaf7fqPhXf5m5yYYfYIzdZ0Qyx3FZIx1AV9VzE7yeGuGF1ib+dfPIZ2yeGmfuWD9PjUqW0Onf+Zrc2ryxudP8YvReTBhTy4kAcX8uBiKI8HlhcNkA== + eJztmUsOgjAURTt3pK7D/4e6BHfEx6hxCRrjKlyGiS7EgbuQFyBpCIUCr320YXCDA0zuyX23H/UHjPkd1pIzdvLofWDovqP30FbHOIvxlt5Hn0WiH6f3gCGXeg4sn7gj3/QJEtlGlvXnGSVP6P48ZTrHnx+WdQhyecfeV7nOTBzqELUHLGW9iRxaE/YhY0PLul/G48p6ffDcYIEzjQvnGmCA+bK9K9m+UieTiyCVd8R3q77XVK9tkgVW54v8y5iwBQywp2D0hJIjy2Uh2fNVvclmyMRciZLloeJRlcUEx7SkI00yoZgrkSW/BmMzmGKBPX7D1TjacOpkgPvXLNd3XRy6WK4BY7dAfzd0ZgE55O+QOnl0cdS996p6NckRFnSiiqGMq4pbVxZY53YTa6lMmL8NU3HUnaeucmDfA3uOngMUIP9OQsVRdLa1kQOEOVtUHGuO+7+iKY4/AhwTSA== - eJzVWc1uEzEQdtpDtT95hg03pPIMRaENPEGFOC+8B6WPwA0O20q0Vd6plVBDzj2gcgKJddejTgaPPf5JGkay4v0bzzf/dpQKo7ZU6n0/DmqldqrVsVsFMgukrud/XedZZ2RkvqkHnjvo+nzNOGD9l/1aH8o0PlonZ9UgM8zhehOU0yZPTWAT7d+pdnlKAj/QdrH5GMTw/4KxY3x6tMF4XSeNmNz5rVBqzzMuCztP17cXAr54PO/HrcdXWlMTYvPAlOHP3fc9iyXO16T0vbTr0KU/H47c8dqi+p0rb/9u3DhgzVzx2pIeJGf9ceHInXOgD4Fhqz9at3+acN4cDtBdjv4D86P9ILXLl4lSXyfh/DkcI2adWKK24HpCV6505VYuB2wCR6i/+nLS2/G/96AX5HDY8ljryGuYH9gB02dGtp9j9VGKgyNXHQC5IFb18PWOkDdiawvg+MHgwfeXaM7pCPRO90E+G3K9ipQ0jqoYho8+CdYBveN61lWPzyCnUpt0xA6LctDha+aXzl8xdd7Wnz0jfsvhAP+gPuKzCaZ5Meit6H8n9eMoi2HAXP9qG2h79PHygOlNOXyrxwxd67k0jqhegbT+Q/oOwHFK3lta5GjqQb7SgRnjtfGQEvY1CY6TahXH3Qv3+xI9A95ZAhacVyU4GqM/jUOyLzkUxseRyQdXgnxgI1zrpH2Z9q3jMa/rAskisccvw2tuwfDO//kDxfQAc2MPTsYZui+N39Q9VcwZ1AnKMff7vT730+Wblv764eo9YghihNsDxsTHrcGB4wPkxmexuc/fGpJDNa4ZqYVLY7MFuo/fgdy0MLWkILWQ1u6U/le6R27q1RoBuKZIRlw/MG4bBryvPYvwfUr4PDXEPxtU36iM8BzXf/p8Hee42L4he825wUFrf8i6uXDY9rYh+TkFB9dLxfKCM+HQPWEqjpxE/38K0c824cD28GGge+1UHPeWvXsqdRGybJM9UmjbcMSeF28bDnzOEoJFikPHVWos/AX21dQX + eJzVWUtOG0EQ7SELNB+fYcwOCc5A5IDDCRBiPXAPPkdgRxZDpJDIdwIpwnjNAsEKJKaZLlEudfXfYEoquedX3a/+3RbCj5pCiMOOtyohVsp5/lZ6CvOktpN/XaWZJ1Nrvql6mSvo+veCccD837u5joo4OVInl2W/ZhjD9UdQSpt8NoFNpH/H2uUzCfxA2kXnYxDDXwVjy/h09oHxukjKmNz5Jxdi1cJ/c71M07dXDnIxr3d8a/GVRtWE0DwwYuRz923PQonzNSBb7Pwv9Do06c+GI3W8Nqh+p8rbz7UZB8yZKl4b0oOkrD8mHKlzDvQhwLr6I3X7UvvL5nCA7lL0H1ge7QepXS6GQvwa+svncGTMPKFEbQH9IM0Hplxpyq1cDkiNA3qymN7clpP2B+Z5dfPp8lhjyWtZyffm58w3DwNx7IqDI1MdAJwQq5JtvWNsbw447hg8+P4MjTkdgd7pPshmw1iSOMq8ZxudOswPesf1rC3fn0FOteW5adHr8CfzS8c/mDqv68/WKjcckGuoj/jYZJL3esu732H1zkXeM4zlr7SBtEcXL2+Ydov+W8ljdC3HrnHUMv4t9e/TdwCOM/LeTLOOuurXVxgwY7w6Ga6Efc0Fx0k5j+N+0/y+i54B7zgCi299qJX+JA6Xfcm2Y3zsqHzwzyEf6MhUHziSvrU34HWdo7W42ONJyZpoMBzYP3+jkB5gouzBrXGM7rvGb+yeKqTOnaAc87jR6XMjfn2jwl4/bL2HL0GMcHvAkPi4VThwfMC68Vls6lpdkxwqcY1JLZwpm03RffwO5KapqiU5qYW0dsf0HK575LqarxGAa4TWiOsHxq3DgPe1lwG+Twmfp/r4Z43qG10jPMf1nz5fxDkutq/PXnOicNDa7zNvKhy6va1Pfo7BwfVSobLgTBhwuMqOxZGS6P9PPvpZJhzYHjYMdK8di+NRs3ePpTZgLctkjxhaNhyh58XLhgOfs/hgccUh4yo2Fl4BWmjU8A== @@ -26,7 +26,7 @@ - eJztmE1OAjEUx58JRDCBlQvDmDCyQnBjNG5040ov4MLLmLkDRghH0Avgx4KNew8gxngGFRea2AITam2nr18zY+SXNAxD6fTf/2tfpwALFuDohRBl3YcsGBQAgj9abgpzHSdFsb7zkv8x3C7b/Z/tO3vdKWUTkztbALukBNXk54+aAE/N+XeZDh9chLh6e0v6bevoOFwBqFUnY/WDOvO9S8q4DfDRVj/7KgC4rarrJUHWsgkYHY9kDo0KUx0uiOfbkGi4I/HTD+3bxOg4q0w/XelgITEUfdbt21Hp6DBrFdURz0OX8H50DNZH3fnhC53xEeUBVzpInEMPIML2x5WvL6vTT5EOma/PRMdyOblkRZr5wyc6Oi4Du2f53N8k6YhzjIyGZQ5zCcYPfr6sW/ZfNMdDpk0T32Q64nXAFFlfXORuEXmZ53XO46Gm5zo6agbxpJubTfcorvzgY36/BXDQUtej0H0vf3/Dox8Y6DtGN9T/zRZTHdT/r1kM9BXnGaez/fK4gmtbladE7ywmOt5w1Sak8W5PcR1X12SsjjYBjkm5X/v9OzsPZNcm5GXdZXlo4OqRHBfF10k6sGcx2PODWd1IdL8ruY9dt239wMS/qi8DB/s0l3GFGTvbPbMMtu+vRb/nlRRfZ6/vmh7wY66KK95jE89Nzh1c40JHHtDRkVbONOE/+sGSN2/+ux95I20d3yTbck0= + eJztWElOwzAU/UitaJHaFQvUIDV01YENArGBDSu4AAsug3KHIlr1CHCBMiy6Yc8BKEKcASgLkHAm1Zg4/p6SoPZJVibH+c/vD44BllgCh6ELXt425IFxCcD5p+22NOdxWk7md1GxP4c7Vb33advp834lH5/c3QbYI82pp39/2gZ4bs+veTxs4NLF9dtfkR9bhsfRGkCjHszVLzSp6wFpsx7AZ0/87WsH4K4u7pcGkssCYHg8kRialkIeJhDH24RwuCf+M3L1x8TwOK+FR1M8aBAf8r6a+uOIePSpXOXziOPQJFg9+gr5MYlHh5MDbegRQ2Z+kuqAbJzzQPwchgAe1h5Tur6uh0eWR5qmL4THajW95YUs64dNyPC4cvS+ZXN9k8YjrjE8tDRrmElg9GBjZlPT/qQYd6kxVXTj8YjzgCp4tpio3UkoSpw3GY0nkprL8Ggo+JNsbVZdo5jSg/X5gy7AYVfcz4e/7mXvb1nUAwP/H2Pgyj/ThSoPX//vyAdGgv2Ms2i9PKvhxhbVqaR/FhUe77huAbL4t/fB48HGdLsaNhFuyHvHHYAT0h42/j6n44B3roKi5F0ajy1cP1LjvPg8jQd2Lwa7fxD19ZLuDzj3sXlbVw+M/4tsGRtYp5n0K8zcYdfMstxo29/KdvcrA/ss7Yt+SGrAzrnIr1iNi5JLZLGIPLKqmSpYRD1oFE2bRdejaMiaxw9yRHM0 @@ -35,7 +35,7 @@ - + [{ @@ -110,48 +110,60 @@ + + + + + + + - + + + + - + + + @@ -159,42 +171,46 @@ [ { + "condition": [{"checkMapFlag": {"key":"demonsActive"}, "not": true}] "text": "A fountain borders the walkway here. The stonework is chipped and dirty, but the water appears to be surprisingly clean and clear.", "options": [{ - "name": "(Continue)"}] + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] } ] - + [ { + "condition": [{"checkMapFlag": {"key":"demonsActive"}, "not": true}], "text": "One of the few sounds in the area, the water wheel on this old mill creaks as it spins gradually in the slowly moving and oddly colored water.", "options": [{ - "name": "(Continue)"}] + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] } ] - + [ { + "condition": [{"checkMapFlag": {"key":"demonsActive"}, "not": true}], "text": "These shops are as lifeless as the rest of the town, but it looks as though there might be some items left behind, suspiciously untouched after however long.", "options": [{ - "name": "(Continue)"}] + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] } ] - + [ { + "condition": [{"checkMapFlag": {"key":"demonsActive"}, "not": true}], "text": "The inn is locked up tightly. The town hall in contrast is missing its' front door, but you find nothing out of the ordinary inside, just well organized crumbling papers coveered in illegibly smeared ink.", "options": [{ - "name": "(Continue)"}] + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] } ] @@ -203,9 +219,10 @@ [ { + "condition": [{"checkMapFlag": {"key":"demonsActive"}, "not": true}], "text": "The vines covering these houses look sickly, as if they are searching for sustenance not found in the soil here.", "options": [{ - "name": "(Continue)"}] + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] } ] @@ -224,32 +241,31 @@ [ { + "condition": [{"checkMapFlag": {"key":"demonsActive"}, "not": true}], "text": "'Deathly still' seems a fitting description for the graveyard. You find yourself almost wishing for the dead to rise just to have something happen.", "options": [{ - "name": "(Continue)"}] + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] } ] - + - [ -{ - "condition": [{"checkQuestFlag": {"key":"demonsActive"}},{"checkQuestFlag": {"key":"escaped", "not": true}}], - "action": ["setQuestFlag": {"key":"demonsActive", "val": 0}] + [{ + "condition": [{"checkMapFlag":"demonsActive"},{"checkMapFlag": "escaped", "not": true}], + "action": [{"setMapFlag": {"key":"demonsActive", "val": 0}}] }, { - "condition": [{"checkQuestFlag": {"key":"introShown", "not": true}}], - "action": ["setQuestFlag": {"key":"introShown", "val": 1}], + "condition": [{"checkMapFlag": "introShown", "not": true}], + "action": [{"advanceMapFlag": "introShown"}], "text": "Just as the merchant described, an empty town lies behind these gates. Even the wind seems more still here as if afraid to disturb anything.", - "options": [{ - "name": "(Continue)", + "options": [{"name": "(Continue)", "text": "As you move closer, it becomes obvious that most of the buildings are intact but in a state of disrepair or are outright overgrown. It is doubtful that anyone has resided here in quite some time.", "options": [{"name": "Time to go portal hunting. I don't guess I can ask anyone for directions..."}] - } - ] -} -] + }] +}] + + @@ -293,14 +309,21 @@ - + + + + + + + [ { + "condition": [{"checkMapFlag": {"key":"demonsActive"}, "not": true}], "text": "Perhaps just a trick of the mind, you can't shake the feeling that you're being watched as you explore the area.", "options": [{ - "name": "(Continue)"}] + "name": "(Continue)", "action": [{"deleteMapObject":-1}]}] } ] @@ -309,13 +332,14 @@ [ { + "condition": [{"checkMapFlag": {"key":"demonsActive"}, "not": true}] "text": "And here lies gruesome confirmation of the merchant's tale, by way of the remains of a merfolk tail. It appears that there was indeed one of the aquatic people here far from their normal territory which it will never return to.", "options": [{ "name": "(Continue)", "text": "Investigating the scene will have to wait, however, as it appears you have determined the cause of death. Seemingly out of nowhere, demons come running at you from all directions.", "options": [{ "name": "RUN!!!", - "action": ["setQuestFlag": {"key":"demonsActive", "val": 1},{"deleteMapObject": 258}, {"activateMapObject": 230},{"activateMapObject": 248},{"activateMapObject": 246},{"activateMapObject": 247},{"deleteMapObject": -1},{"setMapFlag": 258}] + "action": [{"setMapFlag": {"key":"demonsActive", "val": 1}},{"deleteMapObject": -1}, {"activateMapObject": 67},{"activateMapObject": 68},{"activateMapObject": 69},{"activateMapObject": 70},{"activateMapObject": 71},{"activateMapObject": 72},{"activateMapObject": 73},{"activateMapObject": 74},{"activateMapObject": 93},{"activateMapObject": 98},{"activateMapObject": 99},{"activateMapObject": 100},{"activateMapObject": 101},{"activateMapObject": 102},{"activateMapObject": 103}] }] }] } @@ -326,8 +350,8 @@ [ { - "condition": [{"checkQuestFlag": {"key":"demonsActive"}},{"checkQuestFlag": {"key":"escaped"}, "not": true}] - "action": ["setQuestFlag": {"key":"escaped", "val": 1}] + "condition": [{"checkMapFlag": {"key":"demonsActive"}},{"checkMapFlag": {"key":"escaped"}, "not": true}] + "action": [{"setMapFlag": {"key":"escaped", "val": 1}}] } ] @@ -353,38 +377,51 @@ + + + - + - + + + + + + + + - + + + + diff --git a/forge-gui/res/adventure/common/maps/tileset/main.tsx b/forge-gui/res/adventure/common/maps/tileset/main.tsx index dfa6eeb7899..1debc2b0fd5 100644 --- a/forge-gui/res/adventure/common/maps/tileset/main.tsx +++ b/forge-gui/res/adventure/common/maps/tileset/main.tsx @@ -4697,9 +4697,8 @@ - - - + + @@ -4711,9 +4710,8 @@ - - - + + @@ -5020,9 +5018,8 @@ - - - + + @@ -5036,7 +5033,6 @@ - @@ -5743,8 +5739,7 @@ - - + diff --git a/forge-gui/res/adventure/common/maps/tileset/rivers.tsx b/forge-gui/res/adventure/common/maps/tileset/rivers.tsx index 345dca600ff..210cc1c154d 100644 --- a/forge-gui/res/adventure/common/maps/tileset/rivers.tsx +++ b/forge-gui/res/adventure/common/maps/tileset/rivers.tsx @@ -837,17 +837,17 @@ - + - + - + @@ -962,7 +962,7 @@ - + @@ -1003,7 +1003,7 @@ - + @@ -1064,7 +1064,7 @@ - + @@ -1160,7 +1160,7 @@ - + @@ -1200,7 +1200,7 @@ - + @@ -11242,4 +11242,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forge-gui/res/adventure/common/sprites/enemy/construct/golem_4.atlas b/forge-gui/res/adventure/common/sprites/enemy/construct/golem_4.atlas new file mode 100644 index 00000000000..9f8f5bd3ccd --- /dev/null +++ b/forge-gui/res/adventure/common/sprites/enemy/construct/golem_4.atlas @@ -0,0 +1,68 @@ +golem_4.png +size: 64,96 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +Avatar + xy: 0, 0 + size: 16, 16 +Idle + xy: 0, 16 + size: 16, 16 +Idle + xy: 16, 16 + size: 16, 16 +Idle + xy: 32, 16 + size: 16, 16 +Idle + xy: 48, 16 + size: 16, 16 +Walk + xy: 0, 32 + size: 16, 16 +Walk + xy: 16, 32 + size: 16, 16 +Walk + xy: 32, 32 + size: 16, 16 +Walk + xy: 48, 32 + size: 16, 16 +Attack + xy: 0, 48 + size: 16, 16 +Attack + xy: 16, 48 + size: 16, 16 +Attack + xy: 32, 48 + size: 16, 16 +Attack + xy: 48, 48 + size: 16, 16 +Hit + xy: 0, 64 + size: 16, 16 +Hit + xy: 16, 64 + size: 16, 16 +Hit + xy: 32, 64 + size: 16, 16 +Hit + xy: 48, 64 + size: 16, 16 +Death + xy: 0, 80 + size: 16, 16 +Death + xy: 16, 80 + size: 16, 16 +Death + xy: 32, 80 + size: 16, 16 +Death + xy: 48, 80 + size: 16, 16 \ No newline at end of file diff --git a/forge-gui/res/adventure/common/sprites/enemy/construct/golem_4.png b/forge-gui/res/adventure/common/sprites/enemy/construct/golem_4.png new file mode 100644 index 00000000000..dd96f467e01 Binary files /dev/null and b/forge-gui/res/adventure/common/sprites/enemy/construct/golem_4.png differ diff --git a/forge-gui/res/adventure/common/sprites/enemy/construct/myr.atlas b/forge-gui/res/adventure/common/sprites/enemy/construct/myr.atlas new file mode 100644 index 00000000000..21bac833aba --- /dev/null +++ b/forge-gui/res/adventure/common/sprites/enemy/construct/myr.atlas @@ -0,0 +1,68 @@ +myr.png +size: 64,96 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +Avatar + xy: 0, 0 + size: 16, 16 +Idle + xy: 0, 16 + size: 16, 16 +Idle + xy: 16, 16 + size: 16, 16 +Idle + xy: 32, 16 + size: 16, 16 +Idle + xy: 48, 16 + size: 16, 16 +Walk + xy: 0, 32 + size: 16, 16 +Walk + xy: 16, 32 + size: 16, 16 +Walk + xy: 32, 32 + size: 16, 16 +Walk + xy: 48, 32 + size: 16, 16 +Attack + xy: 0, 48 + size: 16, 16 +Attack + xy: 16, 48 + size: 16, 16 +Attack + xy: 32, 48 + size: 16, 16 +Attack + xy: 48, 48 + size: 16, 16 +Hit + xy: 0, 64 + size: 16, 16 +Hit + xy: 16, 64 + size: 16, 16 +Hit + xy: 32, 64 + size: 16, 16 +Hit + xy: 48, 64 + size: 16, 16 +Death + xy: 0, 80 + size: 16, 16 +Death + xy: 16, 80 + size: 16, 16 +Death + xy: 32, 80 + size: 16, 16 +Death + xy: 48, 80 + size: 16, 16 \ No newline at end of file diff --git a/forge-gui/res/adventure/common/sprites/enemy/construct/myr.png b/forge-gui/res/adventure/common/sprites/enemy/construct/myr.png new file mode 100644 index 00000000000..6c6fb0f8e6d Binary files /dev/null and b/forge-gui/res/adventure/common/sprites/enemy/construct/myr.png differ diff --git a/forge-gui/res/adventure/common/sprites/enemy/humanoid/human/rogue/pirate2.atlas b/forge-gui/res/adventure/common/sprites/enemy/humanoid/human/rogue/pirate2.atlas new file mode 100644 index 00000000000..cf29dbdfdbf --- /dev/null +++ b/forge-gui/res/adventure/common/sprites/enemy/humanoid/human/rogue/pirate2.atlas @@ -0,0 +1,68 @@ +pirate2.png +size: 64,96 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +Avatar + xy: 0, 0 + size: 16, 16 +Idle + xy: 0, 16 + size: 16, 16 +Idle + xy: 16, 16 + size: 16, 16 +Idle + xy: 32, 16 + size: 16, 16 +Idle + xy: 48, 16 + size: 16, 16 +Walk + xy: 0, 32 + size: 16, 16 +Walk + xy: 16, 32 + size: 16, 16 +Walk + xy: 32, 32 + size: 16, 16 +Walk + xy: 48, 32 + size: 16, 16 +Attack + xy: 0, 48 + size: 16, 16 +Attack + xy: 16, 48 + size: 16, 16 +Attack + xy: 32, 48 + size: 16, 16 +Attack + xy: 48, 48 + size: 16, 16 +Hit + xy: 0, 64 + size: 16, 16 +Hit + xy: 16, 64 + size: 16, 16 +Hit + xy: 32, 64 + size: 16, 16 +Hit + xy: 48, 64 + size: 16, 16 +Death + xy: 0, 80 + size: 16, 16 +Death + xy: 16, 80 + size: 16, 16 +Death + xy: 32, 80 + size: 16, 16 +Death + xy: 48, 80 + size: 16, 16 diff --git a/forge-gui/res/adventure/common/sprites/enemy/humanoid/human/wizard/archivist.atlas b/forge-gui/res/adventure/common/sprites/enemy/humanoid/human/wizard/archivist.atlas new file mode 100644 index 00000000000..c037fad125b --- /dev/null +++ b/forge-gui/res/adventure/common/sprites/enemy/humanoid/human/wizard/archivist.atlas @@ -0,0 +1,68 @@ +archivist.png +size: 64,96 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +Avatar + xy: 0, 0 + size: 16, 16 +Idle + xy: 0, 16 + size: 16, 16 +Idle + xy: 16, 16 + size: 16, 16 +Idle + xy: 32, 16 + size: 16, 16 +Idle + xy: 48, 16 + size: 16, 16 +Walk + xy: 0, 32 + size: 16, 16 +Walk + xy: 16, 32 + size: 16, 16 +Walk + xy: 32, 32 + size: 16, 16 +Walk + xy: 48, 32 + size: 16, 16 +Attack + xy: 0, 48 + size: 16, 16 +Attack + xy: 16, 48 + size: 16, 16 +Attack + xy: 32, 48 + size: 16, 16 +Attack + xy: 48, 48 + size: 16, 16 +Hit + xy: 0, 64 + size: 16, 16 +Hit + xy: 16, 64 + size: 16, 16 +Hit + xy: 32, 64 + size: 16, 16 +Hit + xy: 48, 64 + size: 16, 16 +Death + xy: 0, 80 + size: 16, 16 +Death + xy: 16, 80 + size: 16, 16 +Death + xy: 32, 80 + size: 16, 16 +Death + xy: 48, 80 + size: 16, 16 \ No newline at end of file diff --git a/forge-gui/res/adventure/common/sprites/enemy/humanoid/human/wizard/archivist.png b/forge-gui/res/adventure/common/sprites/enemy/humanoid/human/wizard/archivist.png new file mode 100644 index 00000000000..8c93d119633 Binary files /dev/null and b/forge-gui/res/adventure/common/sprites/enemy/humanoid/human/wizard/archivist.png differ diff --git a/forge-gui/res/adventure/common/world/enemies.json b/forge-gui/res/adventure/common/world/enemies.json index de3c9ff9e43..ce0008f932b 100644 --- a/forge-gui/res/adventure/common/world/enemies.json +++ b/forge-gui/res/adventure/common/world/enemies.json @@ -190,6 +190,13 @@ "Mythic Rare" ] } + ], + "questTags": [ + "Wizard", + "Human", + "IdentityBlue", + "BiomeBlue", + "BiomeColorless" ] }, { @@ -1743,6 +1750,57 @@ "BiomeBlack" ] }, +{ + "name": "Archivist", + "sprite": "sprites/enemy/humanoid/human/wizard/archivist.atlas", + "deck": [ + "decks/standard/archivist.dck" + ], + "life": 20, + "rewards": [ + { + "type": "deckCard", + "probability": 1, + "count": 2, + "addMaxCount": 4, + "rarity": [ + "common", + "uncommon" + ] + }, + { + "type": "deckCard", + "probability": 0.5, + "count": 2, + "addMaxCount": 4, + "rarity": [ + "uncommon", + "rare" + ], + "cardTypes": [ + "Creature", + "Artifact", + "Enchantment", + "Instant", + "Sorcery" + ] + }, + { + "type": "gold", + "probability": 0.3, + "count": 100, + "addMaxCount": 200 + } + ], + "colors": "U", + "questTags": [ + "Human", + "Wizard", + "Mystic", + "IdentityBlue", + "Dungeon" + ] +}, { "name": "Armored Knight", "sprite": "sprites/enemy/humanoid/knight.atlas", @@ -3238,11 +3296,7 @@ "Furnace", "IdentityColorless", "Construct", - "Robot", - null, - null, - null, - null + "Robot" ] }, { @@ -4080,7 +4134,7 @@ "difficulty": 0.1, "speed": 15, "scale": 0.4, - "flying":true + "flying":true, "life": 25, "rewards": [ { @@ -12930,65 +12984,54 @@ ] }, { - "name": "Golem that is Generous", - "nameOverride": "Shiny Golem", - "sprite": "sprites/enemy/construct/golem.atlas", + "name": "Golem Sentinel", + "sprite": "sprites/enemy/construct/golem_4.atlas", "deck": [ - "decks/standard/golem.json" + "decks/standard/golem_sentinel.dck", + "decks/standard/golem_sentinel_2.dck", + "decks/standard/golem_sentinel_3.dck" ], "ai": "", - "spawnRate": 0.1, + "spawnRate": 1, "difficulty": 0.1, "speed": 20, - "life": 13, + "life": 20, "rewards": [ - { - "type": "card", - "probability": 1, - "count": 1, - "editions": [ - "M22", - "M21" - ], - "colors": [ - "red" - ], - "rarity": [ - "rare" - ] - }, - { - "type": "life", - "probability": 1, - "count": 1, - "addMaxCount": 3 - }, { "type": "deckCard", "probability": 1, - "count": 3, - "addMaxCount": 3 + "count": 1, + "addMaxCount": 4 + }, + { + "type": "gold", + "probability": 0.7, + "count": 100, + "addMaxCount": 200 }, { "type": "card", "probability": 1, - "count": 2, - "cardName": "Black Lotus" + "count": 3, + "rarity": [ + "Uncommon" + ] }, { - "type": "gold", - "probability": 1, - "count": 10, - "addMaxCount": 90 + "type": "card", + "probability": 0.5, + "count": 3, + "rarity": [ + "Rare" + ] } ], - "colors": "GW", + "colors": "C", "questTags": [ "Golem", + "IdentityColorless", "Construct", - "IdentityGreen", - "IdentityWhite", - "IdentitySelesnya" + "Dungeon" ] }, { @@ -18726,6 +18769,58 @@ "BiomeBlack" ] }, +{ + "name": "Myr Superion", + "sprite": "sprites/enemy/construct/myr.atlas", + "deck": [ + "decks/standard/Myr_Superion.dck" + ], + "boss": true, + "ai": "", + "spawnRate": 1, + "difficulty": 0.5, + "speed": 20, + "life": 25, + "rewards": [ + { + "type": "deckCard", + "probability": 1, + "count": 1, + "addMaxCount": 4 + }, + { + "type": "gold", + "probability": 0.7, + "count": 100, + "addMaxCount": 200 + }, + { + "type": "card", + "probability": 1, + "count": 3, + "rarity": [ + "Uncommon" + ] + }, + { + "type": "card", + "probability": 0.5, + "count": 3, + "rarity": [ + "Rare" + ] + } + ], + "colors": "C", + "questTags": [ + "Myr", + "IdentityColorless", + "Construct", + "Robot", + "Dungeon", + "Boss" + ] +}, { "name": "Naga Warrior", "sprite": "sprites/enemy/humanoid/naga/nagawarrior.atlas", @@ -19678,6 +19773,168 @@ "Pirate" ] }, +{ + "name": "Pirate 2", + "nameOverride": "Buccaneer", + "sprite": "sprites/enemy/humanoid/human/rogue/pirate2.atlas", + "deck": [ + "decks/standard/pirate2.dck" + ], + "ai": "", + "spawnRate": 0.8, + "difficulty": 0.1, + "speed": 24, + "life": 16, + "rewards": [ + { + "type": "deckCard", + "probability": 1, + "count": 1, + "rarity": [ + "Common" + ], + "cardTypes": [ + "Creature", + "Artifact", + "Enchantment", + "Instant", + "Sorcery" + ] + }, + { + "type": "deckCard", + "probability": 0.25, + "count": 1, + "rarity": [ + "Rare" + ], + "cardTypes": [ + "Creature", + "Artifact", + "Enchantment", + "Instant", + "Sorcery" + ] + }, + { + "type": "gold", + "probability": 1, + "count": 30, + "addMaxCount": 100 + }, + { + "type": "card", + "probability": 0.5, + "count": 2, + "colors": [ + "Red" + ] + }, + { + "type": "card", + "probability": 0.5, + "count": 1, + "colors": [ + "Blue" + ] + } + ], + "colors": "BRU", + "questTags": [ + "Aggressive", + "Human", + "Warrior", + "Water", + "Bandit", + "Thief", + "IdentityBlack", + "IdentityBlue", + "IdentityRed", + "IdentityGrixis", + "Dungeon" + ] +}, +{ + "name": "Pirate 3", + "nameOverride": "Plunderer", + "sprite": "sprites/enemy/humanoid/human/rogue/pirate3.atlas", + "deck": [ + "decks/standard/pirate3.dck" + ], + "ai": "", + "spawnRate": 0.8, + "difficulty": 0.1, + "speed": 24, + "life": 16, + "rewards": [ + { + "type": "deckCard", + "probability": 1, + "count": 1, + "rarity": [ + "Common" + ], + "cardTypes": [ + "Creature", + "Artifact", + "Enchantment", + "Instant", + "Sorcery" + ] + }, + { + "type": "deckCard", + "probability": 0.25, + "count": 1, + "rarity": [ + "Rare" + ], + "cardTypes": [ + "Creature", + "Artifact", + "Enchantment", + "Instant", + "Sorcery" + ] + }, + { + "type": "gold", + "probability": 1, + "count": 30, + "addMaxCount": 100 + }, + { + "type": "card", + "probability": 0.5, + "count": 2, + "colors": [ + "Red" + ] + }, + { + "type": "card", + "probability": 0.5, + "count": 1, + "colors": [ + "Blue" + ] + } + ], + "colors": "BRU", + "questTags": [ + "Aggressive", + "Human", + "Warrior", + "Water", + "Bandit", + "Thief", + "IdentityBlack", + "IdentityBlue", + "IdentityRed", + "IdentityGrixis", + "Dungeon" + ] +}, { "name": "Pirate Captain", "nameOverride": "", @@ -19752,6 +20009,85 @@ "Pirate" ] }, +{ + "name": "Pirate Captain 2", + "nameOverride": "Pirate Captain", + "sprite": "sprites/enemy/humanoid/human/rogue/pirate3.atlas", + "deck": [ + "decks/standard/pirate_captain_2.dck" + ], + "ai": "", + "spawnRate": 0.8, + "difficulty": 0.1, + "speed": 24, + "life": 20, + "rewards": [ + { + "type": "deckCard", + "probability": 1, + "count": 1, + "rarity": [ + "Common" + ], + "cardTypes": [ + "Creature", + "Artifact", + "Enchantment", + "Instant", + "Sorcery" + ] + }, + { + "type": "deckCard", + "probability": 0.25, + "count": 1, + "rarity": [ + "Rare" + ], + "cardTypes": [ + "Creature", + "Artifact", + "Enchantment", + "Instant", + "Sorcery" + ] + }, + { + "type": "gold", + "probability": 1, + "count": 30, + "addMaxCount": 100 + }, + { + "type": "card", + "probability": 0.5, + "count": 2, + "colors": [ + "Black" + ] + }, + { + "type": "card", + "probability": 0.5, + "count": 1, + "colors": [ + "Black" + ] + } + ], + "colors": "B", + "questTags": [ + "Leader", + "Aggressive", + "Human", + "Warrior", + "Water", + "Bandit", + "Thief", + "IdentityBlack", + "Dungeon" + ] +}, { "name": "Plant", "sprite": "sprites/enemy/plant/plant.atlas", @@ -23086,6 +23422,63 @@ "BiomeBlack" ] }, +{ + "name": "Spirit", + "sprite": "sprites/enemy/undead/ghost_3.atlas", + "deck": [ + "decks/standard/spirit.dck" + ], + "ai": "", + "flying": true, + "spawnRate": 1, + "difficulty": 0.1, + "speed": 31, + "life": 20, + "rewards": [ + { + "type": "deckCard", + "probability": 1, + "count": 2, + "addMaxCount": 4, + "rarity": [ + "common", + "uncommon" + ] + }, + { + "type": "deckCard", + "probability": 0.5, + "count": 2, + "addMaxCount": 4, + "rarity": [ + "uncommon", + "rare" + ], + "cardTypes": [ + "Creature", + "Artifact", + "Enchantment", + "Instant", + "Sorcery" + ] + }, + { + "type": "gold", + "probability": 0.3, + "count": 100, + "addMaxCount": 200 + } + ], + "colors": "U", + "questTags": [ + "Undead", + "Spirit", + "Flying", + "Ghost", + "IdentityBlue", + "Dungeon" + ] +}, { "name": "Stegosaurus", "sprite": "sprites/enemy/beast/dinosaur/dinosaur_stegosaurus.atlas", diff --git a/forge-gui/res/adventure/common/world/points_of_interest.json b/forge-gui/res/adventure/common/world/points_of_interest.json index 6e714d030ae..bc3414a44c1 100644 --- a/forge-gui/res/adventure/common/world/points_of_interest.json +++ b/forge-gui/res/adventure/common/world/points_of_interest.json @@ -2867,6 +2867,18 @@ "map": "../common/maps/map/towns/plains_town.tmx", "radiusFactor": 0.8 }, +{ + "name": "Quest_APortalToNowhere", + "type": "dungeon", + "count": 1, + "spriteAtlas": "../common/maps/tileset/buildings.atlas", + "sprite": "WasteTown", + "map": "../common/maps/map/main_story/waste_town_abandoned.tmx", + "radiusFactor": 0.8, + "questTags": [ + "Quest_APortalToNowhere" + ] +}, { "name": "Red Castle", "type": "castle",