From f35e6c5a9a7022a8ecd347d9eca3c0d80b0822b5 Mon Sep 17 00:00:00 2001 From: simon Date: Sun, 4 Mar 2018 14:56:02 -0500 Subject: [PATCH] Objects can enter & leave vaults --- .../net/simon987/npcplugin/NpcPlugin.java | 2 + .../java/net/simon987/npcplugin/Portal.java | 93 +++++++++++++++++++ .../simon987/npcplugin/VaultDimension.java | 43 ++++++++- .../net/simon987/npcplugin/VaultDoor.java | 64 +++++++++---- .../npcplugin/VaultWorldGenerator.java | 2 +- .../event/WorldCreationListener.java | 11 +-- .../server/event/ObjectDeathEvent.java | 2 +- .../net/simon987/server/game/GameObject.java | 4 + .../net/simon987/server/game/Location.java | 28 ++++++ .../net/simon987/server/game/TileMap.java | 2 +- .../java/net/simon987/server/game/World.java | 77 ++++++++++++++- .../server/webserver/DebugHandler.java | 3 + 12 files changed, 301 insertions(+), 30 deletions(-) create mode 100644 Plugin NPC/src/main/java/net/simon987/npcplugin/Portal.java create mode 100644 Server/src/main/java/net/simon987/server/game/Location.java diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java index e4d32d0..b6e5ce7 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java @@ -50,6 +50,8 @@ public class NpcPlugin extends ServerPlugin implements GameObjectDeserializer, C return Obstacle.deserialize(obj); } else if (objType == ElectricBox.ID) { return ElectricBox.deserialize(obj); + } else if (objType == Portal.ID) { + return Portal.deserialize(obj); } return null; diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/Portal.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/Portal.java new file mode 100644 index 0000000..06972e7 --- /dev/null +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/Portal.java @@ -0,0 +1,93 @@ +package net.simon987.npcplugin; + +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; +import net.simon987.server.GameServer; +import net.simon987.server.game.*; +import org.json.simple.JSONObject; + +public class Portal extends GameObject implements Enterable { + + private Location dst; + + public static final int MAP_INFO = 0x0020; + + public static final int ID = 8; + + @Override + public boolean enter(GameObject object) { + + World world = GameServer.INSTANCE.getGameUniverse().getWorld(dst.worldX, dst.worldY, false, dst.dimension); + + if (object instanceof Updatable) { + object.getWorld().decUpdatable(); + world.incUpdatable(); + } + object.getWorld().removeObject(object); + object.setWorld(world); + world.addObject(object); + + object.setX(dst.x); + object.setY(dst.y); + + return true; + } + + @Override + public char getMapInfo() { + return MAP_INFO; + } + + @Override + public BasicDBObject mongoSerialise() { + BasicDBObject dbObject = new BasicDBObject(); + + dbObject.put("i", getObjectId()); + dbObject.put("x", getX()); + dbObject.put("y", getY()); + dbObject.put("t", ID); + dbObject.put("dstWorldX", dst.worldX); + dbObject.put("dstWorldY", dst.worldY); + dbObject.put("dstX", dst.x); + dbObject.put("dstY", dst.y); + dbObject.put("dstDimension", dst.dimension); + + return dbObject; + } + + public static Portal deserialize(DBObject obj) { + + Portal portal = new Portal(); + + portal.dst = new Location( + (int) obj.get("dstWorldX"), + (int) obj.get("dstWorldY"), + (String) obj.get("dstDimension"), + (int) obj.get("dstX"), + (int) obj.get("dstY")); + portal.setX((int) obj.get("x")); + portal.setY((int) obj.get("y")); + + return portal; + } + + @Override + public JSONObject serialise() { + JSONObject json = new JSONObject(); + + json.put("i", getObjectId()); + json.put("x", getX()); + json.put("y", getY()); + json.put("t", ID); + + return json; + } + + public Location getDst() { + return dst; + } + + public void setDst(Location dst) { + this.dst = dst; + } +} diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDimension.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDimension.java index 504f4e5..36feb04 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDimension.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDimension.java @@ -2,7 +2,10 @@ package net.simon987.npcplugin; import net.simon987.server.GameServer; import net.simon987.server.game.Direction; +import net.simon987.server.game.Location; +import net.simon987.server.game.TileMap; import net.simon987.server.game.World; +import net.simon987.server.logging.LogManager; import java.awt.*; import java.util.ArrayList; @@ -19,9 +22,12 @@ public class VaultDimension { private World homeWorld; - public VaultDimension(long vaultDoorId) { + private int homeX; + private int homeY; - name = "v" + vaultDoorId + "-"; + public VaultDimension(VaultDoor vaultDoor) { + + name = "v" + vaultDoor.getObjectId() + "-"; /* * Creates a group of vault worlds and pieces them together with openings. @@ -35,6 +41,7 @@ public class VaultDimension { * 2. For each world in the current layer, attach a random number of new worlds * 3. Repeat the same step for the newly added layer * 4. Choose a random world from the last layer and create the vault box there (objective) + * 5. Create an exit portal in the home world * * This process is actually done in 2 passes, in the first pass, worlds are defined * as a set of coordinates + a list of opening directions, then they are actually generated @@ -125,6 +132,31 @@ public class VaultDimension { //4. Choose a random world from the last layer and create the vault box there (objective) World objectiveWorld = lastLayerWorlds.get(random.nextInt(lastLayerWorlds.size())); + + //5. Create an exit portal in the home World + Point homePortalPt = homeWorld.getRandomTileWithAdjacent(8, TileMap.VAULT_FLOOR); + if (homePortalPt != null) { + + Point exitCoords = vaultDoor.getAdjacentTile(); + Location exitLocation = new Location(vaultDoor.getWorld().getX(), vaultDoor.getWorld().getY(), vaultDoor + .getWorld().getDimension(), exitCoords.x, exitCoords.y); + + Portal homePortal = new Portal(); + homePortal.setDst(exitLocation); + homePortal.setX(homePortalPt.x); + homePortal.setY(homePortalPt.y); + homePortal.setWorld(homeWorld); + homeWorld.addObject(homePortal); + + Point entryCoords = homePortal.getAdjacentTile(); + homeX = entryCoords.x; + homeY = entryCoords.y; + + } else { + LogManager.LOGGER.severe("FIXME: Couldn't create home exit portal for world " + homeWorld.getId()); + } + + LogManager.LOGGER.severe("DONE"); } private boolean worldExists(Point coords, HashMap> worldLayers) { @@ -137,6 +169,13 @@ public class VaultDimension { return homeWorld; } + public int getHomeX() { + return homeX; + } + + public int getHomeY() { + return homeY; + } /** * Helper class to plan the layout of a vault dimension */ diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDoor.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDoor.java index b1f71f9..bdd7cad 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDoor.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDoor.java @@ -28,8 +28,11 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up */ private boolean open = false; + private int homeX; + private int homeY; private World homeWorld; + /** * Number of ticks to remain the door open */ @@ -38,26 +41,12 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up private int openedTimer = 0; private int cypherId; - public VaultDoor(int cypherId, long objectId) { + public VaultDoor(int cypherId) { this.cypherId = cypherId; + this.randomStringGenerator = new RandomStringGenerator(); - setObjectId(objectId); this.password = "12345678".toCharArray(); - - - //Get or generate vault world - World world = GameServer.INSTANCE.getGameUniverse().getWorld(0x7FFF, 0x7FFF, - false, "v" + getObjectId() + "-"); - - if (world != null) { - homeWorld = world; - } else { - - VaultDimension vaultDimension = new VaultDimension(getObjectId()); - homeWorld = vaultDimension.getHomeWorld(); - } - } @@ -119,7 +108,8 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up homeWorld.incUpdatable(); homeWorld.addObject(object); object.setWorld(homeWorld); - + object.setX(homeX); + object.setY(homeY); return true; } else { @@ -140,6 +130,8 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up dbObject.put("i", getObjectId()); dbObject.put("x", getX()); dbObject.put("y", getY()); + dbObject.put("homeX", getHomeX()); + dbObject.put("homeY", getHomeY()); dbObject.put("t", ID); dbObject.put("pw", new String(password)); @@ -162,12 +154,48 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up public static VaultDoor deserialize(DBObject obj) { - VaultDoor vaultDoor = new VaultDoor(0, (long) obj.get("i")); //cypherId ? + VaultDoor vaultDoor = new VaultDoor(0); //cypherId ? vaultDoor.setX((int) obj.get("x")); vaultDoor.setY((int) obj.get("y")); + + + if (obj.containsField("homeX") && obj.containsField("homeY")) { + vaultDoor.setHomeX((int) obj.get("homeX")); + vaultDoor.setHomeY((int) obj.get("homeY")); + } + vaultDoor.password = ((String) obj.get("pw")).toCharArray(); return vaultDoor; } + @Override + public void initialize() { + //Get or generate vault world + homeWorld = GameServer.INSTANCE.getGameUniverse().getWorld(0x7FFF, 0x7FFF, + false, "v" + getObjectId() + "-"); + + if (homeWorld == null) { + VaultDimension vaultDimension = new VaultDimension(this); + homeWorld = vaultDimension.getHomeWorld(); + homeX = vaultDimension.getHomeX(); + homeY = vaultDimension.getHomeY(); + } + } + + public int getHomeX() { + return homeX; + } + + public void setHomeX(int homeX) { + this.homeX = homeX; + } + + public int getHomeY() { + return homeY; + } + + public void setHomeY(int homeY) { + this.homeY = homeY; + } } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultWorldGenerator.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultWorldGenerator.java index 264961c..cd33c92 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultWorldGenerator.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultWorldGenerator.java @@ -230,7 +230,7 @@ public class VaultWorldGenerator { for (int y = 0; y < worldSize; y++) { if (map.getTileAt(x, y) != floorTile && map.getTileAt(x, y) != wallTile) { - map.setTileAt(-1, x, y); + map.setTileAt(TileMap.VOID, x, y); } } } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java index 83c9129..49caf6b 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java @@ -99,13 +99,9 @@ public class WorldCreationListener implements GameEventListener { p = world.getRandomPassableTile(); if (p != null) { - VaultDoor vaultDoor = new VaultDoor(0, GameServer.INSTANCE.getGameUniverse().getNextObjectId()); //todo cypherId ? + VaultDoor vaultDoor = new VaultDoor(0); //todo cypherId ? - vaultDoor.setWorld(world); - vaultDoor.setX(p.x); - vaultDoor.setY(p.y); - - int counter = 300; + int counter = 700; while (p.x == 0 || p.x == world.getWorldSize() - 1 || p.y == world.getWorldSize() - 1 || p.y == 0 || vaultDoor.getAdjacentTileCount(true) < 8) { p = world.getRandomPassableTile(); @@ -128,6 +124,9 @@ public class WorldCreationListener implements GameEventListener { world.addObject(vaultDoor); world.incUpdatable(); //In case the Factory & Radio Tower couldn't be spawned. + vaultDoor.setWorld(world); + + vaultDoor.initialize(); LogManager.LOGGER.info("Spawned Vault Door at (" + world.getX() + ", " + world.getY() + ") (" + p.x + ", " + p.y + ")"); diff --git a/Server/src/main/java/net/simon987/server/event/ObjectDeathEvent.java b/Server/src/main/java/net/simon987/server/event/ObjectDeathEvent.java index a9885e6..1ffb8aa 100644 --- a/Server/src/main/java/net/simon987/server/event/ObjectDeathEvent.java +++ b/Server/src/main/java/net/simon987/server/event/ObjectDeathEvent.java @@ -5,7 +5,7 @@ package net.simon987.server.event; */ public class ObjectDeathEvent extends GameEvent { /** - * The GameObject type ID of object that init this event + * The GameObject type ID of object that initialize this event */ private long sourceObjectId; diff --git a/Server/src/main/java/net/simon987/server/game/GameObject.java b/Server/src/main/java/net/simon987/server/game/GameObject.java index 4567a50..51426d7 100755 --- a/Server/src/main/java/net/simon987/server/game/GameObject.java +++ b/Server/src/main/java/net/simon987/server/game/GameObject.java @@ -259,4 +259,8 @@ public abstract class GameObject implements JSONSerialisable, MongoSerialisable public boolean onDeadCallback() { return false; } + + public void initialize() { + + } } \ No newline at end of file diff --git a/Server/src/main/java/net/simon987/server/game/Location.java b/Server/src/main/java/net/simon987/server/game/Location.java new file mode 100644 index 0000000..7ad9a10 --- /dev/null +++ b/Server/src/main/java/net/simon987/server/game/Location.java @@ -0,0 +1,28 @@ +package net.simon987.server.game; + +/** + * Represents a location in the game universe + */ +public class Location { + + public int worldX; + public int worldY; + + public String dimension; + + public int x; + public int y; + + public Location(int worldX, int worldY, String dimension, int x, int y) { + this.worldX = worldX; + this.worldY = worldY; + this.dimension = dimension; + this.x = x; + this.y = y; + } + + public String getWorldId() { + return World.idFromCoordinates(worldX, worldY, dimension); + } + +} diff --git a/Server/src/main/java/net/simon987/server/game/TileMap.java b/Server/src/main/java/net/simon987/server/game/TileMap.java index 4bf0990..79c791c 100755 --- a/Server/src/main/java/net/simon987/server/game/TileMap.java +++ b/Server/src/main/java/net/simon987/server/game/TileMap.java @@ -21,6 +21,7 @@ import java.util.zip.DeflaterOutputStream; */ public class TileMap implements JSONSerialisable, MongoSerialisable { + public static final int VOID = -1; public static final int PLAIN_TILE = 0; public static final int WALL_TILE = 1; public static final int IRON_TILE = 2; @@ -186,6 +187,5 @@ public class TileMap implements JSONSerialisable, MongoSerialisable { return new Point(rx, ry); } } - } } diff --git a/Server/src/main/java/net/simon987/server/game/World.java b/Server/src/main/java/net/simon987/server/game/World.java index 9778159..0ec02e9 100644 --- a/Server/src/main/java/net/simon987/server/game/World.java +++ b/Server/src/main/java/net/simon987/server/game/World.java @@ -69,7 +69,7 @@ public class World implements MongoSerialisable { int tile = tileMap.getTileAt(x, y); return getGameObjectsBlockingAt(x, y).size() > 0 || tile == TileMap.WALL_TILE || - tile == TileMap.VAULT_WALL; + tile == TileMap.VAULT_WALL || tile == TileMap.VOID; } /** @@ -229,6 +229,8 @@ public class World implements MongoSerialisable { object.setWorld(world); world.addObject(object); + + object.initialize(); } return world; @@ -439,7 +441,80 @@ public class World implements MongoSerialisable { return res; } + public Point getAdjacentTile(int x, int y) { + + if (!isTileBlocked(x + 1, y)) { + return new Point(x + 1, y); + + } else if (!isTileBlocked(x, y + 1)) { + return new Point(x, getY() + 1); + + } else if (!isTileBlocked(x - 1, y)) { + return new Point(x - 1, getY()); + + } else if (!isTileBlocked(x, y - 1)) { + return new Point(x, y - 1); + } else { + return null; + } + } + public Collection getGameObjects() { return gameObjects.values(); } + + + /** + * Get a random tile with N adjacent non-blocked tile + * + * @param n Number of adjacent tiles of type X + * @return null if no tile is found + */ + public Point getRandomTileWithAdjacent(int n, int tile) { + int counter = 0; + while (true) { + counter++; + + //Prevent infinite loop + if (counter >= 2500) { + return null; + } + + Point rTile = getTileMap().getRandomTile(tile); + + if (rTile != null) { + int adjacentTiles = 0; + + if (!isTileBlocked(rTile.x, rTile.y - 1)) { + adjacentTiles++; + } + if (!isTileBlocked(rTile.x + 1, rTile.y)) { + adjacentTiles++; + } + if (!isTileBlocked(rTile.x, rTile.y + 1)) { + adjacentTiles++; + } + if (!isTileBlocked(rTile.x - 1, rTile.y)) { + adjacentTiles++; + } + if (!isTileBlocked(rTile.x + 1, rTile.y + 1)) { + adjacentTiles++; + } + if (!isTileBlocked(rTile.x - 1, rTile.y + 1)) { + adjacentTiles++; + } + if (!isTileBlocked(rTile.x + 1, rTile.y - 1)) { + adjacentTiles++; + } + if (!isTileBlocked(rTile.x - 1, rTile.y - 1)) { + adjacentTiles++; + } + + if (adjacentTiles >= n) { + return rTile; + } + } + } + + } } diff --git a/Server/src/main/java/net/simon987/server/webserver/DebugHandler.java b/Server/src/main/java/net/simon987/server/webserver/DebugHandler.java index 7d59d00..cdefe37 100644 --- a/Server/src/main/java/net/simon987/server/webserver/DebugHandler.java +++ b/Server/src/main/java/net/simon987/server/webserver/DebugHandler.java @@ -156,6 +156,9 @@ public class DebugHandler implements MessageHandler { if (object != null) { world.addObject(object); + object.setWorld(world); + + object.initialize(); return "Created object " + object.getObjectId();