From 7bd78d6ad589e1849b8e87b8e0dfe56b12b7d706 Mon Sep 17 00:00:00 2001 From: Peter Riewe Date: Sat, 10 Jan 2026 20:31:50 -0500 Subject: [PATCH 01/12] Separate AtlasPosition from Atlas --- src/main/java/neon/ai/AI.java | 11 +- src/main/java/neon/ai/PathFinder.java | 6 +- .../java/neon/core/DefaultGameContext.java | 6 + src/main/java/neon/core/Engine.java | 25 +++- src/main/java/neon/core/Game.java | 21 ++- src/main/java/neon/core/GameContext.java | 55 +------- src/main/java/neon/core/GameLoader.java | 24 +++- src/main/java/neon/core/GameSaver.java | 4 +- .../java/neon/core/handlers/MagicHandler.java | 17 +-- .../neon/core/handlers/MotionHandler.java | 23 ++-- .../java/neon/core/handlers/TurnHandler.java | 10 +- src/main/java/neon/maps/Atlas.java | 125 +++--------------- src/main/java/neon/maps/AtlasPosition.java | 103 +++++++++++++++ src/main/java/neon/maps/ZoneActivator.java | 10 +- .../maps/services/EnginePhysicsManager.java | 14 +- .../java/neon/resources/ResourceManager.java | 3 +- .../neon/systems/files/JacksonMapper.java | 4 +- .../neon/systems/physics/PhysicsSystem.java | 2 +- src/main/java/neon/ui/GamePanel.java | 6 +- src/main/java/neon/ui/states/AimState.java | 12 +- src/main/java/neon/ui/states/BumpState.java | 2 +- .../java/neon/ui/states/ContainerState.java | 4 +- src/main/java/neon/ui/states/GameState.java | 3 +- .../java/neon/ui/states/InventoryState.java | 2 +- src/main/java/neon/ui/states/MoveState.java | 14 +- .../java/neon/maps/AtlasIntegrationTest.java | 79 ++++++----- src/test/java/neon/maps/AtlasTest.java | 100 ++++++++------ .../java/neon/maps/MapPerformanceTest.java | 77 +++++++---- .../maps/generators/DungeonGeneratorTest.java | 20 ++- .../DungeonGeneratorXmlIntegrationTest.java | 12 +- .../java/neon/test/TestEngineContext.java | 62 +++++---- 31 files changed, 454 insertions(+), 402 deletions(-) create mode 100644 src/main/java/neon/maps/AtlasPosition.java diff --git a/src/main/java/neon/ai/AI.java b/src/main/java/neon/ai/AI.java index ef09abd..8af6c75 100644 --- a/src/main/java/neon/ai/AI.java +++ b/src/main/java/neon/ai/AI.java @@ -306,7 +306,7 @@ protected void flee(Creature hunter) { } Point p = new Point(cBounds.x + dx, cBounds.y + dy); - if (Engine.getAtlas().getCurrentZone().getCreature(p) == null) { + if (Engine.getAtlasPosition().getCurrentZone().getCreature(p) == null) { byte result = MotionHandler.move(creature, p); if (result == MotionHandler.BLOCKED) { // try a random direction once (or multiple times?) @@ -322,7 +322,7 @@ protected void flee(Creature hunter) { private boolean open(Point p) { Door door = null; - for (long uid : Engine.getAtlas().getCurrentZone().getItems(p)) { + for (long uid : Engine.getAtlasPosition().getCurrentZone().getItems(p)) { if (Engine.getStore().getEntity(uid) instanceof Door) { door = (Door) Engine.getStore().getEntity(uid); } @@ -383,7 +383,7 @@ protected void wander() { Point p = new Point(cBounds.x + dx, cBounds.y + dy); Point player = pBounds.getLocation(); - if (Engine.getAtlas().getCurrentZone().getCreature(p) == null && !player.equals(p)) { + if (Engine.getAtlasPosition().getCurrentZone().getCreature(p) == null && !player.equals(p)) { MotionHandler.move(creature, p); } } @@ -397,7 +397,8 @@ protected void wander(Point destination) { Point player = pBounds.getLocation(); Point next = PathFinder.findPath(creature, cBounds.getLocation(), destination)[0]; - if (Engine.getAtlas().getCurrentZone().getCreature(next) == null && !player.equals(next)) { + if (Engine.getAtlasPosition().getCurrentZone().getCreature(next) == null + && !player.equals(next)) { MotionHandler.move(creature, next); } } @@ -466,7 +467,7 @@ protected void hunt(Creature prey) { equip(Slot.WEAPON); } Engine.post(new CombatEvent(creature, prey)); - } else if (Engine.getAtlas().getCurrentZone().getCreature(p) == null) { + } else if (Engine.getAtlasPosition().getCurrentZone().getCreature(p) == null) { if (MotionHandler.move(creature, p) == MotionHandler.DOOR) { open(p); // open door if necessary } diff --git a/src/main/java/neon/ai/PathFinder.java b/src/main/java/neon/ai/PathFinder.java index 395f088..ce9bc2d 100644 --- a/src/main/java/neon/ai/PathFinder.java +++ b/src/main/java/neon/ai/PathFinder.java @@ -63,7 +63,7 @@ public static Point[] findPath(Creature creature, Point origin, Point destinatio links.put(to, next); next = null; break; - } else if (Engine.getAtlas().getCurrentZone().getRegion(neighbour).getMovMod() + } else if (Engine.getAtlasPosition().getCurrentZone().getRegion(neighbour).getMovMod() == Region.Modifier.BLOCK) { continue; // if terrain is blocked, skip to next point } @@ -125,7 +125,7 @@ private static int manhattan(Point one, Point two) { private static int terrainPenalty(Point neighbour) { // better modifiers? - switch (Engine.getAtlas().getCurrentZone().getRegion(neighbour).getMovMod()) { + switch (Engine.getAtlasPosition().getCurrentZone().getRegion(neighbour).getMovMod()) { case SWIM: return (100 - mover.getSkill(Skill.SWIMMING)) / 5; case CLIMB: @@ -136,7 +136,7 @@ private static int terrainPenalty(Point neighbour) { } private static int doorPenalty(Point neighbour) { - for (long uid : Engine.getAtlas().getCurrentZone().getItems(neighbour)) { + for (long uid : Engine.getAtlasPosition().getCurrentZone().getItems(neighbour)) { if (Engine.getStore().getEntity(uid) instanceof Door) { Door door = (Door) Engine.getStore().getEntity(uid); if (door.lock.isLocked()) { diff --git a/src/main/java/neon/core/DefaultGameContext.java b/src/main/java/neon/core/DefaultGameContext.java index aac7f34..496ded9 100644 --- a/src/main/java/neon/core/DefaultGameContext.java +++ b/src/main/java/neon/core/DefaultGameContext.java @@ -23,6 +23,7 @@ import neon.entities.Player; import neon.entities.UIDStore; import neon.maps.Atlas; +import neon.maps.AtlasPosition; import neon.narrative.QuestTracker; import neon.resources.ResourceManager; import neon.systems.physics.PhysicsSystem; @@ -62,6 +63,11 @@ public Atlas getAtlas() { return game != null ? game.getAtlas() : null; } + @Override + public AtlasPosition getAtlasPosition() { + return game != null ? game.getAtlasPosition() : null; + } + @Override public UIDStore getStore() { return game != null ? game.getStore() : null; diff --git a/src/main/java/neon/core/Engine.java b/src/main/java/neon/core/Engine.java index bb8dd9f..6a74bba 100644 --- a/src/main/java/neon/core/Engine.java +++ b/src/main/java/neon/core/Engine.java @@ -18,6 +18,7 @@ package neon.core; +import java.awt.*; import java.io.IOException; import java.util.EventObject; import javax.script.*; @@ -30,6 +31,9 @@ import neon.entities.Player; import neon.entities.UIDStore; import neon.maps.Atlas; +import neon.maps.AtlasPosition; +import neon.maps.services.EnginePhysicsManager; +import neon.maps.services.PhysicsManager; import neon.narrative.EventAdapter; import neon.narrative.QuestTracker; import neon.resources.ResourceManager; @@ -61,12 +65,13 @@ public class Engine implements Runnable { private static org.graalvm.polyglot.Engine polyengine; private static FileSystem files; // virtual file system private static PhysicsSystem physics; // the physics engine + private static PhysicsManager physicsManager; private static QuestTracker quests; private static MBassador bus; // event bus private static ResourceManager resources; - private TaskQueue queue; - private Configuration config; + private static TaskQueue queue; + private final Configuration config; // set externally private static Game game; @@ -98,6 +103,7 @@ public Engine(Port port) throws IOException { files = new FileSystem(); physics = new PhysicsSystem(); + physicsManager = new EnginePhysicsManager(physics); queue = new TaskQueue(); // create a resourcemanager to keep track of all the resources @@ -192,6 +198,11 @@ public static Timer getTimer() { return game.getTimer(); } + @Deprecated + public static TaskQueue getTaskQueue() { + return queue; + } + /** * @return the virtual filesystem of the engine */ @@ -209,6 +220,11 @@ public static PhysicsSystem getPhysicsEngine() { return physics; } + @Deprecated + public static PhysicsManager getPhysicsManager() { + return physicsManager; + } + /** * @return the script engine * @deprecated Use {@link GameContext#getScriptEngine()} instead @@ -245,6 +261,11 @@ public static Atlas getAtlas() { return game.getAtlas(); } + @Deprecated + public static AtlasPosition getAtlasPosition() { + return game.getAtlasPosition(); + } + public TaskQueue getQueue() { return queue; } diff --git a/src/main/java/neon/core/Game.java b/src/main/java/neon/core/Game.java index 707ddb9..f49d6e1 100644 --- a/src/main/java/neon/core/Game.java +++ b/src/main/java/neon/core/Game.java @@ -24,6 +24,11 @@ import neon.entities.Player; import neon.entities.UIDStore; import neon.maps.Atlas; +import neon.maps.AtlasPosition; +import neon.maps.ZoneActivator; +import neon.maps.services.PhysicsManager; +import neon.narrative.QuestTracker; +import neon.resources.ResourceManager; import neon.systems.files.FileSystem; import neon.systems.timing.Timer; @@ -33,11 +38,20 @@ public class Game implements Closeable { private final Player player; private final Timer timer = new Timer(); private final Atlas atlas; + private final AtlasPosition atlasPosition; - public Game(Player player, FileSystem files) { + public Game( + Player player, + FileSystem files, + PhysicsManager physicsManager, + ResourceManager resourceManager, + QuestTracker questTracker) { store = new UIDStore(files.getFullPath("uidstore")); - atlas = new Atlas(files, files.getFullPath("atlas")); + atlas = new Atlas(files, files.getFullPath("atlas"), store); this.player = player; + this.atlasPosition = + new AtlasPosition( + atlas, new ZoneActivator(physicsManager), resourceManager, questTracker, store); } /** @@ -47,10 +61,11 @@ public Game(Player player, FileSystem files) { * @param atlas the atlas * @param store the UID store */ - public Game(Player player, Atlas atlas, UIDStore store) { + public Game(Player player, Atlas atlas, UIDStore store, AtlasPosition atlasPosition) { this.player = player; this.atlas = atlas; this.store = store; + this.atlasPosition = atlasPosition; } @Override diff --git a/src/main/java/neon/core/GameContext.java b/src/main/java/neon/core/GameContext.java index 1c3a1b1..26c9939 100644 --- a/src/main/java/neon/core/GameContext.java +++ b/src/main/java/neon/core/GameContext.java @@ -22,6 +22,7 @@ import neon.entities.Player; import neon.entities.UIDStore; import neon.maps.Atlas; +import neon.maps.AtlasPosition; import neon.narrative.QuestTracker; import neon.resources.ResourceManager; import neon.systems.physics.PhysicsSystem; @@ -37,74 +38,24 @@ */ public interface GameContext { - // ========== Game State Accessors ========== - - /** - * Returns the player entity. - * - * @return the player, or null if no game is active - */ Player getPlayer(); - /** - * Returns the atlas (map/world manager). - * - * @return the atlas - */ Atlas getAtlas(); - /** - * Returns the entity store. - * - * @return the UID store containing all game entities - */ + AtlasPosition getAtlasPosition(); + UIDStore getStore(); - /** - * Returns the game timer. - * - * @return the timer - */ Timer getTimer(); - // ========== System Accessors ========== - - /** - * Returns the resource manager. - * - * @return the resource manager - */ ResourceManager getResources(); - /** - * Returns the quest tracker. - * - * @return the quest tracker - */ QuestTracker getQuestTracker(); - /** - * Returns the physics engine. - * - * @return the physics system - */ PhysicsSystem getPhysicsEngine(); - /** - * Returns the script engine (GraalVM Polyglot context). - * - * @return the script engine context - */ Context getScriptEngine(); - // ========== Actions ========== - - /** - * Executes a JavaScript script. - * - * @param script the script to execute - * @return the result of the script execution - */ Object execute(String script); /** Quits the application. */ diff --git a/src/main/java/neon/core/GameLoader.java b/src/main/java/neon/core/GameLoader.java index 7a033b2..c4b4a43 100644 --- a/src/main/java/neon/core/GameLoader.java +++ b/src/main/java/neon/core/GameLoader.java @@ -121,7 +121,13 @@ public void initGame( new RCreature(((RCreature) Engine.getResources().getResource(race)).toElement()); Player player = new Player(species, name, gender, spec, profession); player.species.text = "@"; - engine.startGame(new Game(player, Engine.getFileSystem())); + engine.startGame( + new Game( + player, + Engine.getFileSystem(), + Engine.getPhysicsManager(), + Engine.getResources(), + engine.getContext().getQuestTracker())); setSign(player, sign); for (Skill skill : Skill.values()) { SkillHandler.checkFeat(skill, player); @@ -148,8 +154,8 @@ public void initGame( bounds.setLocation(game.getStartPosition().x, game.getStartPosition().y); Map map = Engine.getAtlas().getMap(Engine.getStore().getMapUID(game.getStartMap())); Engine.getScriptEngine().getBindings("js").putMember("map", map); - Engine.getAtlas().setMap(map); - Engine.getAtlas().setCurrentZone(game.getStartZone()); + Engine.getAtlasPosition().setMap(map); + Engine.getAtlasPosition().setCurrentZone(game.getStartZone(), player); } catch (RuntimeException re) { log.error("Error during initGame", re); } @@ -270,15 +276,21 @@ private void loadPlayer(SaveGameModel.PlayerSaveData playerData) { Gender.valueOf(playerData.gender.toUpperCase()), Player.Specialisation.valueOf(playerData.specialisation), playerData.profession); - engine.startGame(new Game(player, Engine.getFileSystem())); + engine.startGame( + new Game( + player, + Engine.getFileSystem(), + Engine.getPhysicsManager(), + Engine.getResources(), + engine.getContext().getQuestTracker())); Rectangle bounds = player.getShapeComponent(); bounds.setLocation(playerData.x, playerData.y); player.setSign(playerData.sign); player.species.text = "@"; // start map - Engine.getAtlas().setMap(Engine.getAtlas().getMap(playerData.map)); - Engine.getAtlas().setCurrentZone(playerData.level); + Engine.getAtlasPosition().setMap(Engine.getAtlas().getMap(playerData.map)); + Engine.getAtlasPosition().setCurrentZone(playerData.level, player); // stats Stats stats = player.getStatsComponent(); diff --git a/src/main/java/neon/core/GameSaver.java b/src/main/java/neon/core/GameSaver.java index e6693aa..0c90dde 100644 --- a/src/main/java/neon/core/GameSaver.java +++ b/src/main/java/neon/core/GameSaver.java @@ -31,7 +31,7 @@ import neon.entities.property.Feat; import neon.entities.property.Skill; import neon.magic.Spell; -import neon.maps.Atlas; +import neon.maps.AtlasPosition; import neon.resources.RSpell; import neon.systems.files.JacksonMapper; import neon.systems.files.StringTranslator; @@ -153,7 +153,7 @@ private SaveGameModel.PlayerSaveData buildPlayerData(Player player) { data.sign = player.getSign(); // Position - Atlas atlas = Engine.getAtlas(); + AtlasPosition atlas = Engine.getAtlasPosition(); data.map = atlas.getCurrentMap().getUID(); data.level = atlas.getCurrentZoneIndex(); Rectangle bounds = player.getShapeComponent(); diff --git a/src/main/java/neon/core/handlers/MagicHandler.java b/src/main/java/neon/core/handlers/MagicHandler.java index d2fe044..59d26ea 100644 --- a/src/main/java/neon/core/handlers/MagicHandler.java +++ b/src/main/java/neon/core/handlers/MagicHandler.java @@ -93,12 +93,12 @@ public void cast(MagicEvent.OnPoint me) { if (spell.effect == Effect.SCRIPTED) { Engine.execute(spell.script); } else if (spell.effect.getHandler().onItem()) { - Collection items = game.getAtlas().getCurrentZone().getItems(box); + Collection items = game.getAtlasPosition().getCurrentZone().getItems(box); for (long uid : items) { castSpell((Item) game.getStore().getEntity(uid), spell); } } else { - Collection creatures = game.getAtlas().getCurrentZone().getCreatures(box); + Collection creatures = game.getAtlasPosition().getCurrentZone().getCreatures(box); for (Creature creature : creatures) { castSpell(creature, null, spell); } @@ -111,8 +111,6 @@ public void cast(MagicEvent.OnPoint me) { /** * This method lets a creature cast a spell on a target. * - * @param caster the creature casting the spell - * @param target the position of the target * @return the result of the casting */ @Handler @@ -166,12 +164,12 @@ public void cast(MagicEvent.CreatureOnPoint me) { if (formula.effect == Effect.SCRIPTED) { Engine.execute(formula.script); } else if (formula.effect.getHandler().onItem()) { - Collection items = game.getAtlas().getCurrentZone().getItems(box); + Collection items = game.getAtlasPosition().getCurrentZone().getItems(box); for (long uid : items) { castSpell((Item) game.getStore().getEntity(uid), formula); } } else { - Collection creatures = game.getAtlas().getCurrentZone().getCreatures(box); + Collection creatures = game.getAtlasPosition().getCurrentZone().getCreatures(box); if (box.contains(game.getPlayer().getShapeComponent())) { creatures.add(game.getPlayer()); } @@ -188,9 +186,6 @@ public void cast(MagicEvent.CreatureOnPoint me) { /** * This methods lets a creature using a magic item cast a spell on a point. * - * @param caster the spell caster - * @param item the spell caster's magic item - * @param target the target of the spell * @return the result of the cast */ @Handler @@ -229,12 +224,12 @@ public void cast(MagicEvent.ItemOnPoint me) { if (formula.effect == Effect.SCRIPTED) { Engine.execute(formula.script); } else if (formula.effect.getHandler().onItem()) { - Collection items = game.getAtlas().getCurrentZone().getItems(box); + Collection items = game.getAtlasPosition().getCurrentZone().getItems(box); for (long uid : items) { castSpell((Item) game.getStore().getEntity(uid), formula); } } else { - Collection creatures = game.getAtlas().getCurrentZone().getCreatures(box); + Collection creatures = game.getAtlasPosition().getCurrentZone().getCreatures(box); if (box.contains(game.getPlayer().getShapeComponent())) { creatures.add(game.getPlayer()); } diff --git a/src/main/java/neon/core/handlers/MotionHandler.java b/src/main/java/neon/core/handlers/MotionHandler.java index f82889e..71c6267 100644 --- a/src/main/java/neon/core/handlers/MotionHandler.java +++ b/src/main/java/neon/core/handlers/MotionHandler.java @@ -27,6 +27,7 @@ import neon.entities.Creature; import neon.entities.Door; import neon.entities.Entity; +import neon.entities.Player; import neon.entities.components.Lock; import neon.entities.property.Condition; import neon.entities.property.Habitat; @@ -60,9 +61,9 @@ public class MotionHandler { * @param door the portal that the creature used * @return the result */ - public static byte teleport(Creature creature, Door door) { + public static byte teleport(Player creature, Door door) { if (door.portal.isPortal()) { - Zone previous = Engine.getAtlas().getCurrentZone(); // briefly buffer current zone + Zone previous = Engine.getAtlasPosition().getCurrentZone(); // briefly buffer current zone if (door.portal.getDestMap() != 0) { // load map and have door refer back Map map = Engine.getAtlas().getMap(door.portal.getDestMap()); @@ -70,24 +71,24 @@ public static byte teleport(Creature creature, Door door) { for (long uid : zone.getItems(door.portal.getDestPos())) { Entity i = Engine.getStore().getEntity(uid); if (i instanceof Door) { - ((Door) i).portal.setDestMap(Engine.getAtlas().getCurrentMap()); + ((Door) i).portal.setDestMap(Engine.getAtlasPosition().getCurrentMap()); } } - Engine.getAtlas().setMap(map); + Engine.getAtlasPosition().setMap(map); Engine.getScriptEngine().getBindings("js").putMember("map", map); - door.portal.setDestMap(Engine.getAtlas().getCurrentMap()); + door.portal.setDestMap(Engine.getAtlasPosition().getCurrentMap()); } else if (door.portal.getDestTheme() != null) { Dungeon dungeon = MapLoader.loadDungeon(door.portal.getDestTheme()); - Engine.getAtlas().setMap(dungeon); - door.portal.setDestMap(Engine.getAtlas().getCurrentMap()); + Engine.getAtlasPosition().setMap(dungeon); + door.portal.setDestMap(Engine.getAtlasPosition().getCurrentMap()); } - Engine.getAtlas().enterZone(door, previous); + Engine.getAtlasPosition().enterZone(door, previous, creature); walk(creature, door.portal.getDestPos()); // check if there is a door at the destination, if so, unlock and open this door Rectangle bounds = creature.getShapeComponent(); - for (long uid : Engine.getAtlas().getCurrentZone().getItems(bounds)) { + for (long uid : Engine.getAtlasPosition().getCurrentZone().getItems(bounds)) { Entity i = Engine.getStore().getEntity(uid); if (i instanceof Door) { ((Door) i).lock.open(); @@ -121,13 +122,13 @@ public static byte teleport(Creature creature, Door door) { * @return the result of the movement */ public static byte move(Creature actor, Point p) { - Region region = Engine.getAtlas().getCurrentZone().getRegion(p); + Region region = Engine.getAtlasPosition().getCurrentZone().getRegion(p); if (p == null || region == null) { return NULL; } // check if there is no closed door present - Collection items = Engine.getAtlas().getCurrentZone().getItems(p); + Collection items = Engine.getAtlasPosition().getCurrentZone().getItems(p); for (long uid : items) { Entity i = Engine.getStore().getEntity(uid); if (i instanceof Door) { diff --git a/src/main/java/neon/core/handlers/TurnHandler.java b/src/main/java/neon/core/handlers/TurnHandler.java index b091352..a2f91f4 100644 --- a/src/main/java/neon/core/handlers/TurnHandler.java +++ b/src/main/java/neon/core/handlers/TurnHandler.java @@ -82,7 +82,7 @@ public void tick(TurnEvent te) { // monsters controleren Player player = panel.getContext().getPlayer(); - for (long uid : panel.getContext().getAtlas().getCurrentZone().getCreatures()) { + for (long uid : panel.getContext().getAtlasPosition().getCurrentZone().getCreatures()) { Creature creature = (Creature) panel.getContext().getStore().getEntity(uid); if (!creature.hasCondition(Condition.DEAD)) { HealthComponent health = creature.getHealthComponent(); @@ -93,7 +93,11 @@ public void tick(TurnEvent te) { if (pBounds.getLocation().distance(cBounds.getLocation()) < range) { int spd = getSpeed(creature); Region region = - panel.getContext().getAtlas().getCurrentZone().getRegion(cBounds.getLocation()); + panel + .getContext() + .getAtlasPosition() + .getCurrentZone() + .getRegion(cBounds.getLocation()); if (creature.species.habitat == Habitat.LAND && region.getMovMod() == Modifier.SWIM) { spd = spd / 4; // zwemmende creatures hebben penalty } @@ -134,7 +138,7 @@ public void run() { */ private boolean checkRegions() { // die boolean is eigenlijk maar louche Rectangle window = panel.getVisibleRectangle(); - Zone zone = panel.getContext().getAtlas().getCurrentZone(); + Zone zone = panel.getContext().getAtlasPosition().getCurrentZone(); boolean fixed = true; boolean generated = false; // om aan te geven dat er iets gegenereerd werd diff --git a/src/main/java/neon/maps/Atlas.java b/src/main/java/neon/maps/Atlas.java index 6397fbe..fff1962 100644 --- a/src/main/java/neon/maps/Atlas.java +++ b/src/main/java/neon/maps/Atlas.java @@ -21,16 +21,9 @@ import java.io.Closeable; import java.io.IOException; import lombok.extern.slf4j.Slf4j; -import neon.core.Engine; -import neon.entities.Door; -import neon.maps.generators.DungeonGenerator; import neon.maps.services.EngineEntityStore; -import neon.maps.services.EngineQuestProvider; -import neon.maps.services.EngineResourceProvider; import neon.maps.services.EntityStore; import neon.maps.services.MapAtlas; -import neon.maps.services.QuestProvider; -import neon.maps.services.ResourceProvider; import neon.systems.files.FileSystem; import org.h2.mvstore.MVMap; import org.h2.mvstore.MVStore; @@ -44,107 +37,54 @@ public class Atlas implements Closeable, MapAtlas { private final MVStore db; private final MVMap maps; - private int currentZone = 0; - private int currentMap = 0; - private final FileSystem files; private final EntityStore entityStore; - private final ResourceProvider resourceProvider; - private final QuestProvider questProvider; - private final ZoneActivator zoneActivator; + private final FileSystem fileSystem; /** * Initializes this {@code Atlas} with the given {@code FileSystem} and cache path. The cache is * lazy initialised. * - * @param files a {@code FileSystem} + * @param fileSystem a {@code FileSystem} * @param path the path to the file used for caching * @deprecated Use {@link #Atlas(FileSystem, String, EntityStore, ZoneActivator)} to avoid * dependency on Engine singleton */ @Deprecated - public Atlas(FileSystem files, String path) { - this( - files, - getMVStore(files, path), - new EngineEntityStore(), - new EngineResourceProvider(), - new EngineQuestProvider(), - createDefaultZoneActivator()); + public Atlas(FileSystem fileSystem, String path) { + this(fileSystem, path, new EngineEntityStore()); } /** * Initializes this {@code Atlas} with dependency injection. * - * @param files the file system + * @param fileSystem the file system * @param atlasStore the MVStore for caching * @param entityStore the entity store service - * @param resourceProvider the resource provider service - * @param questProvider the quest provider service - * @param zoneActivator the zone activator for physics management */ - public Atlas( - FileSystem files, - MVStore atlasStore, - EntityStore entityStore, - ResourceProvider resourceProvider, - QuestProvider questProvider, - ZoneActivator zoneActivator) { - this.files = files; + public Atlas(FileSystem fileSystem, String path, EntityStore entityStore) { + this.fileSystem = fileSystem; this.entityStore = entityStore; - this.resourceProvider = resourceProvider; - this.questProvider = questProvider; - this.zoneActivator = zoneActivator; - this.db = atlasStore; + this.db = getMVStore(fileSystem, path); // files.delete(path); // String fileName = files.getFullPath(path); // log.warn("Creating new MVStore at {}", fileName); // db = MVStore.open(fileName); - maps = atlasStore.openMap("maps"); + maps = db.openMap("maps"); } - private static MVStore getMVStore(FileSystem files, String path) { - files.delete(path); + private static MVStore getMVStore(FileSystem files, String fileName) { + files.delete(fileName); - log.warn("Creating new MVStore at {}", path); + log.warn("Creating new MVStore at {}", fileName); - return MVStore.open(path); - } - - /** - * Creates a default zone activator using Engine singleton (for backward compatibility). - * - * @return a zone activator - */ - static ZoneActivator createDefaultZoneActivator() { - return new ZoneActivator(new neon.maps.services.EnginePhysicsManager(), Engine::getPlayer); + return MVStore.open(fileName); } public MVStore getCache() { return db; } - /** - * @return the current map - */ - public Map getCurrentMap() { - return maps.get(currentMap); - } - - /** - * @return the current zone - */ - public Zone getCurrentZone() { - return maps.get(currentMap).getZone(currentZone); - } - - /** - * @return the current zone - */ - public int getCurrentZoneIndex() { - return currentZone; - } - /** * @param uid the unique identifier of a map * @return the map with the given uid @@ -152,53 +92,18 @@ public int getCurrentZoneIndex() { @Override public Map getMap(int uid) { if (!maps.containsKey(uid)) { - Map map = MapLoader.loadMap(entityStore.getMapPath(uid), uid, files); + Map map = MapLoader.loadMap(entityStore.getMapPath(uid), uid, fileSystem); System.out.println("Loaded map " + map.toString()); maps.put(uid, map); } return maps.get(uid); } - /** - * Sets the current zone. - * - * @param i the index of the current zone - */ - public void setCurrentZone(int i) { - currentZone = i; - zoneActivator.activateZone(getCurrentZone()); - } - - /** - * Enter a new zone through a door. - * - * @param door - * @param previousZone - */ - public void enterZone(Door door, Zone previousZone) { - if (door.portal.getDestZone() > -1) { - setCurrentZone(door.portal.getDestZone()); - } else { - setCurrentZone(0); - } - - if (getCurrentMap() instanceof Dungeon && getCurrentZone().isRandom()) { - new DungeonGenerator(getCurrentZone(), entityStore, resourceProvider, questProvider) - .generate(door, previousZone, this); - } - } - - /** - * Set the current map. - * - * @param map the new current map - */ - public void setMap(Map map) { + public void putMapIfNeeded(Map map) { if (!maps.containsKey(map.getUID())) { // could be a random map that's not in the database yet maps.put(map.getUID(), map); } - currentMap = map.getUID(); } @Override diff --git a/src/main/java/neon/maps/AtlasPosition.java b/src/main/java/neon/maps/AtlasPosition.java new file mode 100644 index 0000000..fb42e20 --- /dev/null +++ b/src/main/java/neon/maps/AtlasPosition.java @@ -0,0 +1,103 @@ +package neon.maps; + +import neon.entities.Door; +import neon.entities.Player; +import neon.maps.generators.DungeonGenerator; +import neon.maps.services.EntityStore; +import neon.maps.services.PhysicsManager; +import neon.maps.services.QuestProvider; +import neon.narrative.QuestTracker; +import neon.resources.ResourceManager; + +public class AtlasPosition { + private int currentZone = 0; + private int currentMap = 0; + private final Atlas atlas; + private final ZoneActivator zoneActivator; + private final ResourceManager resourceProvider; + private final QuestTracker questProvider; + private final EntityStore entityStore; + + public AtlasPosition( + Atlas atlas, + ZoneActivator zoneActivator, + ResourceManager resourceProvider, + QuestTracker questProvider, + EntityStore entityStore) { + this.atlas = atlas; + this.zoneActivator = zoneActivator; + this.resourceProvider = resourceProvider; + this.questProvider = questProvider; + this.entityStore = entityStore; + } + + /** + * Creates a default zone activator using Engine singleton (for backward compatibility). + * + * @return a zone activator + */ + static ZoneActivator createDefaultZoneActivator(PhysicsManager physicsManager) { + return new ZoneActivator(physicsManager); + } + + /** + * @return the current map + */ + public Map getCurrentMap() { + return atlas.getMap(currentMap); + } + + /** + * @return the current zone + */ + public Zone getCurrentZone() { + return atlas.getMap(currentMap).getZone(currentZone); + } + + /** + * @return the current zone + */ + public int getCurrentZoneIndex() { + return currentZone; + } + + /** + * Sets the current zone. + * + * @param i the index of the current zone + */ + public void setCurrentZone(int i, Player player) { + currentZone = i; + zoneActivator.activateZone(getCurrentZone(), player); + } + + /** + * Enter a new zone through a door. + * + * @param door + * @param previousZone + */ + public void enterZone(Door door, Zone previousZone, Player player) { + if (door.portal.getDestZone() > -1) { + setCurrentZone(door.portal.getDestZone(), player); + } else { + setCurrentZone(0, player); + } + + if (getCurrentMap() instanceof Dungeon && getCurrentZone().isRandom()) { + new DungeonGenerator( + getCurrentZone(), entityStore, resourceProvider, (QuestProvider) questProvider) + .generate(door, previousZone, atlas); + } + } + + /** + * Set the current map. + * + * @param map the new current map + */ + public void setMap(Map map) { + atlas.putMapIfNeeded(map); + currentMap = map.getUID(); + } +} diff --git a/src/main/java/neon/maps/ZoneActivator.java b/src/main/java/neon/maps/ZoneActivator.java index ee48587..9f8bc97 100644 --- a/src/main/java/neon/maps/ZoneActivator.java +++ b/src/main/java/neon/maps/ZoneActivator.java @@ -18,7 +18,6 @@ package neon.maps; -import java.util.function.Supplier; import neon.entities.Player; import neon.maps.services.PhysicsManager; @@ -30,17 +29,14 @@ */ public class ZoneActivator { private final PhysicsManager physicsManager; - private final Supplier player; /** * Creates a new ZoneActivator with the given dependencies. * * @param physicsManager the physics system manager - * @param player the player entity */ - public ZoneActivator(PhysicsManager physicsManager, Supplier player) { + public ZoneActivator(PhysicsManager physicsManager) { this.physicsManager = physicsManager; - this.player = player; } /** @@ -49,7 +45,7 @@ public ZoneActivator(PhysicsManager physicsManager, Supplier player) { * * @param zone the zone to activate */ - public void activateZone(Zone zone) { + public void activateZone(Zone zone, Player player) { physicsManager.clear(); // Register all active regions with the physics system @@ -60,6 +56,6 @@ public void activateZone(Zone zone) { } // Re-register the player - physicsManager.register(player.get().getPhysicsComponent()); + physicsManager.register(player.getPhysicsComponent()); } } diff --git a/src/main/java/neon/maps/services/EnginePhysicsManager.java b/src/main/java/neon/maps/services/EnginePhysicsManager.java index bffd796..9cdb4d4 100644 --- a/src/main/java/neon/maps/services/EnginePhysicsManager.java +++ b/src/main/java/neon/maps/services/EnginePhysicsManager.java @@ -19,9 +19,9 @@ package neon.maps.services; import java.awt.Rectangle; -import neon.core.Engine; import neon.entities.components.PhysicsComponent; import neon.maps.Region; +import neon.systems.physics.PhysicsSystem; /** * Adapter implementation of PhysicsManager that delegates to the Engine singleton. This class @@ -30,18 +30,24 @@ * @author mdriesen */ public class EnginePhysicsManager implements PhysicsManager { + private final PhysicsSystem physicsSystem; + + public EnginePhysicsManager(PhysicsSystem physicsSystem) { + this.physicsSystem = physicsSystem; + } + @Override public void clear() { - Engine.getPhysicsEngine().clear(); + physicsSystem.clear(); } @Override public void register(Region region, Rectangle bounds, boolean fixed) { - Engine.getPhysicsEngine().register(region, bounds, fixed); + physicsSystem.register(region, bounds, fixed); } @Override public void register(PhysicsComponent component) { - Engine.getPhysicsEngine().register(component.getTheBody()); + physicsSystem.register(component.getTheBody()); } } diff --git a/src/main/java/neon/resources/ResourceManager.java b/src/main/java/neon/resources/ResourceManager.java index 1b1683f..aceb3fd 100644 --- a/src/main/java/neon/resources/ResourceManager.java +++ b/src/main/java/neon/resources/ResourceManager.java @@ -20,8 +20,9 @@ import java.util.HashMap; import java.util.Vector; +import neon.maps.services.ResourceProvider; -public class ResourceManager { +public class ResourceManager implements ResourceProvider { private HashMap resources = new HashMap(); public Resource getResource(String id) { diff --git a/src/main/java/neon/systems/files/JacksonMapper.java b/src/main/java/neon/systems/files/JacksonMapper.java index 3c00a73..a59fcf7 100644 --- a/src/main/java/neon/systems/files/JacksonMapper.java +++ b/src/main/java/neon/systems/files/JacksonMapper.java @@ -121,15 +121,15 @@ public T fromXml(String xmlString, Class valueType) { public void parseMultiTypeXml(InputStream input, ElementHandler elementHandler) throws IOException { try { + ByteArrayInputStream byteInput = new ByteArrayInputStream(input.readAllBytes()); // Read the entire stream into a string for manipulation - String xmlContent = new String(input.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8); input.close(); // Parse with basic XML parsing to extract individual elements javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); javax.xml.parsers.DocumentBuilder builder = factory.newDocumentBuilder(); - org.w3c.dom.Document doc = builder.parse(new ByteArrayInputStream(xmlContent.getBytes())); + org.w3c.dom.Document doc = builder.parse(byteInput); org.w3c.dom.Element root = doc.getDocumentElement(); org.w3c.dom.NodeList children = root.getChildNodes(); diff --git a/src/main/java/neon/systems/physics/PhysicsSystem.java b/src/main/java/neon/systems/physics/PhysicsSystem.java index 4c96417..a59cb83 100644 --- a/src/main/java/neon/systems/physics/PhysicsSystem.java +++ b/src/main/java/neon/systems/physics/PhysicsSystem.java @@ -25,7 +25,7 @@ import net.phys2d.raw.strategies.QuadSpaceStrategy; public class PhysicsSystem { - private World world; + private final World world; public PhysicsSystem() { world = new World(new Vector2f(0, 0), 1, new QuadSpaceStrategy(50, 15)); diff --git a/src/main/java/neon/ui/GamePanel.java b/src/main/java/neon/ui/GamePanel.java index 7814630..9f4ce8e 100644 --- a/src/main/java/neon/ui/GamePanel.java +++ b/src/main/java/neon/ui/GamePanel.java @@ -163,7 +163,7 @@ public void repaint() { drawing.updateCamera(bounds.getLocation()); } Collection renderables = - context.getAtlas().getCurrentZone().getRenderables(getVisibleRectangle()); + context.getAtlasPosition().getCurrentZone().getRenderables(getVisibleRectangle()); renderables.add(context.getPlayer().getRenderComponent()); if (cursor != null) { renderables.add(cursor); @@ -355,7 +355,7 @@ public BufferedImage filter(BufferedImage src, BufferedImage dest) { (bounds.y - 8) * zoom - view.y * zoom, (int) (17 * zoom), (int) (17 * zoom)))); - for (Point p : context.getAtlas().getCurrentZone().getLightMap().keySet()) { + for (Point p : context.getAtlasPosition().getCurrentZone().getLightMap().keySet()) { // 4 en 9: cirkel met diameter 8, gecentreerd op licht area.subtract( new Area( @@ -376,7 +376,7 @@ public BufferedImage filter(BufferedImage src, BufferedImage dest) { g.clearRect(0, 0, src.getWidth(), src.getHeight()); g.drawImage(src, src.getMinX(), src.getMinY(), null); - if (context.getAtlas().getCurrentMap() instanceof World) { + if (context.getAtlasPosition().getCurrentMap() instanceof World) { int hour = (context.getTimer().getTime() / (60 * 1) + 12) % 24; g.setColor(new Color(0, 0, 0, (hour - 12) * (hour - 12) * 3 / 2)); g.fill(area); diff --git a/src/main/java/neon/ui/states/AimState.java b/src/main/java/neon/ui/states/AimState.java index 5aabdcf..6f5aa92 100644 --- a/src/main/java/neon/ui/states/AimState.java +++ b/src/main/java/neon/ui/states/AimState.java @@ -143,7 +143,7 @@ public void keyPressed(KeyEvent key) { private void shoot() { Rectangle bounds = player.getShapeComponent(); if (target.distance(bounds.x, bounds.y) < 5) { - Creature victim = context.getAtlas().getCurrentZone().getCreature(target); + Creature victim = context.getAtlasPosition().getCurrentZone().getCreature(target); if (victim != null) { Weapon ammo = (Weapon) context.getStore().getEntity(player.getInventoryComponent().get(Slot.AMMO)); @@ -186,7 +186,7 @@ private void shoot(Item projectile, Creature victim) { // shoot prBounds.setLocation(vBounds.x, vBounds.y); - context.getAtlas().getCurrentZone().addItem(projectile); + context.getAtlasPosition().getCurrentZone().addItem(projectile); new Thread( new Translation(projectile, plBounds.x, plBounds.y, vBounds.x, vBounds.y, 100, panel)) .start(); @@ -195,7 +195,7 @@ private void shoot(Item projectile, Creature victim) { private void talk() { Rectangle bounds = player.getShapeComponent(); if (target.distance(bounds.getLocation()) < 2) { - Creature creature = context.getAtlas().getCurrentZone().getCreature(target); + Creature creature = context.getAtlasPosition().getCurrentZone().getCreature(target); if (creature != null) { if (creature.hasDialog()) { // dialog module @@ -231,7 +231,7 @@ private void look() { // description of what is being looked at Rectangle bounds = player.getShapeComponent(); if (target.distance(bounds.getLocation()) < 20) { - Zone zone = context.getAtlas().getCurrentZone(); + Zone zone = context.getAtlasPosition().getCurrentZone(); String items = ""; String actors = ""; ArrayList things = new ArrayList(zone.getItems(target)); @@ -240,7 +240,7 @@ private void look() { } else if (things.size() > 1) { items = ", several items"; } - Creature creature = context.getAtlas().getCurrentZone().getCreature(target); + Creature creature = context.getAtlasPosition().getCurrentZone().getCreature(target); if (creature != null) { actors = ", " + creature.toString(); } @@ -251,7 +251,7 @@ private void look() { } private void act() { - for (long uid : context.getAtlas().getCurrentZone().getItems(target)) { + for (long uid : context.getAtlasPosition().getCurrentZone().getItems(target)) { if (context.getStore().getEntity(uid) instanceof Door) { bus.publishAsync(new TransitionEvent("door", "door", context.getStore().getEntity(uid))); break; diff --git a/src/main/java/neon/ui/states/BumpState.java b/src/main/java/neon/ui/states/BumpState.java index 7443bd2..b22c00b 100644 --- a/src/main/java/neon/ui/states/BumpState.java +++ b/src/main/java/neon/ui/states/BumpState.java @@ -109,7 +109,7 @@ public void keyPressed(KeyEvent ke) { Rectangle pBounds = player.getShapeComponent(); Rectangle cBounds = creature.getShapeComponent(); pBounds.setLocation(cBounds.x, cBounds.y); - context.getAtlas().getCurrentZone().removeCreature(creature.getUID()); + context.getAtlasPosition().getCurrentZone().removeCreature(creature.getUID()); panel.repaint(); bus.publishAsync(new TransitionEvent("return")); } diff --git a/src/main/java/neon/ui/states/ContainerState.java b/src/main/java/neon/ui/states/ContainerState.java index 1b486ec..e348d99 100644 --- a/src/main/java/neon/ui/states/ContainerState.java +++ b/src/main/java/neon/ui/states/ContainerState.java @@ -159,7 +159,7 @@ public void keyPressed(KeyEvent key) { Rectangle pBounds = player.getShapeComponent(); Rectangle iBounds = item.getShapeComponent(); iBounds.setLocation(pBounds.x, pBounds.y); - context.getAtlas().getCurrentZone().addItem(item); + context.getAtlasPosition().getCurrentZone().addItem(item); } else if (container instanceof Creature) { InventoryHandler.addItem(((Creature) container), item.getUID()); } @@ -177,7 +177,7 @@ public void keyPressed(KeyEvent key) { bus.publishAsync(new TransitionEvent("container", "holder", item)); } else { if (container instanceof Zone) { - context.getAtlas().getCurrentZone().removeItem((Item) item); + context.getAtlasPosition().getCurrentZone().removeItem((Item) item); } else if (container instanceof Creature) { InventoryHandler.removeItem(((Creature) container), item.getUID()); } else { diff --git a/src/main/java/neon/ui/states/GameState.java b/src/main/java/neon/ui/states/GameState.java index 9eda169..df21691 100644 --- a/src/main/java/neon/ui/states/GameState.java +++ b/src/main/java/neon/ui/states/GameState.java @@ -125,7 +125,8 @@ public void keyPressed(KeyEvent key) { break; default: if (code == keys.map) { - new MapDialog(ui.getWindow(), context.getAtlas().getCurrentZone(), context).show(); + new MapDialog(ui.getWindow(), context.getAtlasPosition().getCurrentZone(), context) + .show(); } else if (code == keys.sneak) { player.setSneaking(!player.isSneaking()); panel.repaint(); diff --git a/src/main/java/neon/ui/states/InventoryState.java b/src/main/java/neon/ui/states/InventoryState.java index 25bb846..ad8f22b 100644 --- a/src/main/java/neon/ui/states/InventoryState.java +++ b/src/main/java/neon/ui/states/InventoryState.java @@ -204,7 +204,7 @@ public void keyPressed(KeyEvent e) { Rectangle pBounds = player.getShapeComponent(); Rectangle iBounds = item.getShapeComponent(); iBounds.setLocation(pBounds.x, pBounds.y); - context.getAtlas().getCurrentZone().addItem(item); + context.getAtlasPosition().getCurrentZone().addItem(item); initList(); inventory.setSelectedIndex(0); inventory.repaint(); diff --git a/src/main/java/neon/ui/states/MoveState.java b/src/main/java/neon/ui/states/MoveState.java index a8dc8d7..825fa33 100644 --- a/src/main/java/neon/ui/states/MoveState.java +++ b/src/main/java/neon/ui/states/MoveState.java @@ -72,7 +72,7 @@ private void move(int x, int y) { Point p = new Point(bounds.x + x, bounds.y + y); // check if creature is in the way - Creature other = context.getAtlas().getCurrentZone().getCreature(p); + Creature other = context.getAtlasPosition().getCurrentZone().getCreature(p); if (other != null && !other.hasCondition(Condition.DEAD)) { if (other.brain.isHostile()) { bus.publishAsync(new CombatEvent(player, other)); @@ -82,7 +82,7 @@ private void move(int x, int y) { } } else { // no one in the way, so move if (MotionHandler.move(player, p) == MotionHandler.DOOR) { - for (long uid : context.getAtlas().getCurrentZone().getItems(p)) { + for (long uid : context.getAtlasPosition().getCurrentZone().getItems(p)) { if (context.getStore().getEntity(uid) instanceof Door) { bus.publishAsync( new TransitionEvent("door", "door", context.getStore().getEntity(uid))); @@ -100,8 +100,8 @@ private void act() { // clone the list here, otherwise concurrent modification exceptions when picking up items Rectangle bounds = player.getShapeComponent(); ArrayList items = - new ArrayList(context.getAtlas().getCurrentZone().getItems(bounds)); - Creature c = context.getAtlas().getCurrentZone().getCreature(bounds.getLocation()); + new ArrayList(context.getAtlasPosition().getCurrentZone().getItems(bounds)); + Creature c = context.getAtlasPosition().getCurrentZone().getCreature(bounds.getLocation()); if (c != null) { items.add(c.getUID()); } @@ -126,12 +126,12 @@ private void act() { } else if (entity instanceof Creature) { bus.publishAsync(new TransitionEvent("container", "holder", entity)); } else { - context.getAtlas().getCurrentZone().removeItem((Item) entity); + context.getAtlasPosition().getCurrentZone().removeItem((Item) entity); InventoryHandler.addItem(player, entity.getUID()); } } else if (items.size() > 1) { bus.publishAsync( - new TransitionEvent("container", "holder", context.getAtlas().getCurrentZone())); + new TransitionEvent("container", "holder", context.getAtlasPosition().getCurrentZone())); } } @@ -171,7 +171,7 @@ public void keyPressed(KeyEvent key) { if (player.isMounted()) { Creature mount = player.getMount(); player.unmount(); - context.getAtlas().getCurrentZone().addCreature(mount); + context.getAtlasPosition().getCurrentZone().addCreature(mount); Rectangle pBounds = player.getShapeComponent(); Rectangle mBounds = mount.getShapeComponent(); mBounds.setLocation(pBounds.x, pBounds.y); diff --git a/src/test/java/neon/maps/AtlasIntegrationTest.java b/src/test/java/neon/maps/AtlasIntegrationTest.java index 1c9bbb3..f492b78 100644 --- a/src/test/java/neon/maps/AtlasIntegrationTest.java +++ b/src/test/java/neon/maps/AtlasIntegrationTest.java @@ -1,13 +1,11 @@ package neon.maps; -import static neon.maps.Atlas.createDefaultZoneActivator; import static org.junit.jupiter.api.Assertions.*; import java.awt.Rectangle; import java.util.Collection; -import neon.maps.services.EngineEntityStore; -import neon.maps.services.EngineQuestProvider; -import neon.maps.services.EngineResourceProvider; +import neon.maps.services.*; +import neon.narrative.QuestTracker; import neon.test.MapDbTestHelper; import neon.test.TestEngineContext; import org.h2.mvstore.MVStore; @@ -24,19 +22,20 @@ class AtlasIntegrationTest { private MVStore testDb; private Atlas atlas; + AtlasPosition atlasPosition; @BeforeEach void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); - atlas = - new Atlas( - TestEngineContext.getStubFileSystem(), - testDb, - new EngineEntityStore(), - new EngineResourceProvider(), - new EngineQuestProvider(), - createDefaultZoneActivator()); + atlas = new Atlas(TestEngineContext.getStubFileSystem(), "test-atlas", new EngineEntityStore()); + atlasPosition = + new AtlasPosition( + atlas, + TestEngineContext.getTestZoneActivator(), + TestEngineContext.getTestResources(), + new QuestTracker(), + TestEngineContext.getTestEntityStore()); } @AfterEach @@ -51,9 +50,9 @@ void tearDown() { @Test void testZoneUsesAtlasDatabase() { World world = new World("DB Test World", 1000); - atlas.setMap(world); + atlasPosition.setMap(world); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); assertNotNull(zone); // Add regions to the zone @@ -75,12 +74,12 @@ void testMultipleZonesShareDatabase() { World world1 = new World("World 1", 1001); World world2 = new World("World 2", 1002); - atlas.setMap(world1); - Zone zone1 = atlas.getCurrentZone(); + atlasPosition.setMap(world1); + Zone zone1 = atlasPosition.getCurrentZone(); zone1.addRegion(MapTestFixtures.createTestRegion("zone1-region", 0, 0, 10, 10, 0)); - atlas.setMap(world2); - Zone zone2 = atlas.getCurrentZone(); + atlasPosition.setMap(world2); + Zone zone2 = atlasPosition.getCurrentZone(); zone2.addRegion(MapTestFixtures.createTestRegion("zone2-region", 20, 20, 10, 10, 0)); testDb.commit(); @@ -101,8 +100,8 @@ void testFullRoundTrip() { // Create a world with populated zone World world = new World("Round Trip World", 1003); - atlas.setMap(world); - Zone zone = atlas.getCurrentZone(); + atlasPosition.setMap(world); + Zone zone = atlasPosition.getCurrentZone(); // Add multiple regions for (int i = 0; i < 20; i++) { @@ -114,12 +113,12 @@ void testFullRoundTrip() { testDb.commit(); // Retrieve the map again - Map retrievedMap = atlas.getCurrentMap(); + Map retrievedMap = atlasPosition.getCurrentMap(); assertEquals(1003, retrievedMap.getUID()); assertEquals("Round Trip World", retrievedMap.getName()); // Verify zone data - Zone retrievedZone = atlas.getCurrentZone(); + Zone retrievedZone = atlasPosition.getCurrentZone(); assertEquals(20, retrievedZone.getRegions().size()); // Test spatial query on retrieved zone @@ -131,9 +130,9 @@ void testFullRoundTrip() { @Test void testZoneSpatialIndexPersistence() { World world = new World("Spatial Index World", 1004); - atlas.setMap(world); + atlasPosition.setMap(world); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); // Create a grid of regions for (int y = 0; y < 5; y++) { @@ -166,15 +165,15 @@ void testMapSwitchingPreservesData() { World world2 = new World("World B", 1006); // Populate world1 - atlas.setMap(world1); - Zone zone1 = atlas.getCurrentZone(); + atlasPosition.setMap(world1); + Zone zone1 = atlasPosition.getCurrentZone(); for (int i = 0; i < 5; i++) { zone1.addRegion(MapTestFixtures.createTestRegion(i * 10, 0, 10, 10)); } // Populate world2 - atlas.setMap(world2); - Zone zone2 = atlas.getCurrentZone(); + atlasPosition.setMap(world2); + Zone zone2 = atlasPosition.getCurrentZone(); for (int i = 0; i < 10; i++) { zone2.addRegion(MapTestFixtures.createTestRegion(0, i * 10, 10, 10)); } @@ -182,20 +181,20 @@ void testMapSwitchingPreservesData() { testDb.commit(); // Switch back to world1 and verify data - atlas.setMap(world1); - assertEquals(5, atlas.getCurrentZone().getRegions().size()); + atlasPosition.setMap(world1); + assertEquals(5, atlasPosition.getCurrentZone().getRegions().size()); // Switch to world2 and verify data - atlas.setMap(world2); - assertEquals(10, atlas.getCurrentZone().getRegions().size()); + atlasPosition.setMap(world2); + assertEquals(10, atlasPosition.getCurrentZone().getRegions().size()); } @Test void testRegionScriptsPersistThroughAtlas() { World world = new World("Script World", 1007); - atlas.setMap(world); + atlasPosition.setMap(world); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); Region region = MapTestFixtures.createTestRegion("scripted-region", 0, 0, 50, 50, 0); region.addScript("init.js", false); region.addScript("update.js", false); @@ -218,9 +217,9 @@ void testRegionScriptsPersistThroughAtlas() { @Test void testLargeWorldIntegration() { World world = new World("Large World", 1008); - atlas.setMap(world); + atlasPosition.setMap(world); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); // Add 100 regions in a 10x10 grid for (int y = 0; y < 10; y++) { @@ -245,9 +244,9 @@ void testLargeWorldIntegration() { @Test void testAtlasHandlesEmptyWorld() { World emptyWorld = new World("Empty World", 1009); - atlas.setMap(emptyWorld); + atlasPosition.setMap(emptyWorld); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); assertNotNull(zone); assertTrue(zone.getRegions().isEmpty()); @@ -262,9 +261,9 @@ void testMultipleAtlasInstancesShareTestDb() { // This tests that the testDb created in setUp is properly shared // through TestEngineContext World world = new World("Shared DB World", 1010); - atlas.setMap(world); + atlasPosition.setMap(world); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); zone.addRegion(MapTestFixtures.createTestRegion(0, 0, 10, 10)); testDb.commit(); diff --git a/src/test/java/neon/maps/AtlasTest.java b/src/test/java/neon/maps/AtlasTest.java index 6081c13..290ba48 100644 --- a/src/test/java/neon/maps/AtlasTest.java +++ b/src/test/java/neon/maps/AtlasTest.java @@ -1,12 +1,10 @@ package neon.maps; -import static neon.maps.Atlas.createDefaultZoneActivator; import static org.junit.jupiter.api.Assertions.*; import java.io.IOException; import neon.maps.services.EngineEntityStore; -import neon.maps.services.EngineQuestProvider; -import neon.maps.services.EngineResourceProvider; +import neon.narrative.QuestTracker; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; @@ -24,19 +22,20 @@ class AtlasTest { private MVStore testDb; private Atlas atlas; + private AtlasPosition atlasPosition; @BeforeEach void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); - atlas = - new Atlas( - TestEngineContext.getStubFileSystem(), - testDb, - new EngineEntityStore(), - new EngineResourceProvider(), - new EngineQuestProvider(), - createDefaultZoneActivator()); + atlas = new Atlas(TestEngineContext.getStubFileSystem(), "atlas-test", new EngineEntityStore()); + atlasPosition = + new AtlasPosition( + atlas, + TestEngineContext.getTestZoneActivator(), + TestEngineContext.getTestResources(), + new QuestTracker(), + TestEngineContext.getTestEntityStore()); } @AfterEach @@ -57,9 +56,9 @@ void testConstructorCreatesMapDb() { void testSetMapAddsToCache() { World world = new World("Test World", 100); - atlas.setMap(world); + atlasPosition.setMap(world); - Map retrievedMap = atlas.getCurrentMap(); + Map retrievedMap = atlasPosition.getCurrentMap(); assertNotNull(retrievedMap); assertEquals(100, retrievedMap.getUID()); assertEquals("Test World", retrievedMap.getName()); @@ -70,19 +69,19 @@ void testGetCurrentMapReturnsSetMap() { World world1 = new World("World 1", 101); World world2 = new World("World 2", 102); - atlas.setMap(world1); - assertEquals(101, atlas.getCurrentMap().getUID()); + atlasPosition.setMap(world1); + assertEquals(101, atlasPosition.getCurrentMap().getUID()); - atlas.setMap(world2); - assertEquals(102, atlas.getCurrentMap().getUID()); + atlasPosition.setMap(world2); + assertEquals(102, atlasPosition.getCurrentMap().getUID()); } @Test void testGetCurrentZoneReturnsCorrectZone() { World world = new World("Test World", 103); - atlas.setMap(world); + atlasPosition.setMap(world); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); assertNotNull(zone); // World creates a zone with hardcoded name "world" assertEquals("world", zone.getName()); @@ -91,9 +90,9 @@ void testGetCurrentZoneReturnsCorrectZone() { @Test void testGetCurrentZoneIndexDefaultsToZero() { World world = new World("Test World", 104); - atlas.setMap(world); + atlasPosition.setMap(world); - assertEquals(0, atlas.getCurrentZoneIndex()); + assertEquals(0, atlasPosition.getCurrentZoneIndex()); } @Test @@ -101,29 +100,29 @@ void testMultipleMapsDoNotInterfere() { World world1 = new World("World 1", 201); World world2 = new World("World 2", 202); - atlas.setMap(world1); - atlas.setMap(world2); + atlasPosition.setMap(world1); + atlasPosition.setMap(world2); // Set back to world1 - atlas.setMap(world1); - assertEquals(201, atlas.getCurrentMap().getUID()); - assertEquals("World 1", atlas.getCurrentMap().getName()); + atlasPosition.setMap(world1); + assertEquals(201, atlasPosition.getCurrentMap().getUID()); + assertEquals("World 1", atlasPosition.getCurrentMap().getName()); // Set to world2 - atlas.setMap(world2); - assertEquals(202, atlas.getCurrentMap().getUID()); - assertEquals("World 2", atlas.getCurrentMap().getName()); + atlasPosition.setMap(world2); + assertEquals(202, atlasPosition.getCurrentMap().getUID()); + assertEquals("World 2", atlasPosition.getCurrentMap().getName()); } @Test void testSetMapOnlyAddsToCacheOnce() { World world = new World("Test World", 300); - atlas.setMap(world); - atlas.setMap(world); // Second call should not duplicate + atlasPosition.setMap(world); + atlasPosition.setMap(world); // Second call should not duplicate // Verify map is still retrievable - assertEquals(300, atlas.getCurrentMap().getUID()); + assertEquals(300, atlasPosition.getCurrentMap().getUID()); } @Test @@ -131,27 +130,27 @@ void testCacheWithMultipleMaps() { // Add multiple maps to cache for (int i = 0; i < 10; i++) { World world = new World("World " + i, 400 + i); - atlas.setMap(world); + atlasPosition.setMap(world); } // Verify last map is current - assertEquals(409, atlas.getCurrentMap().getUID()); + assertEquals(409, atlasPosition.getCurrentMap().getUID()); // Switch between maps World world5 = new World("World 5", 405); - atlas.setMap(world5); - assertEquals(405, atlas.getCurrentMap().getUID()); + atlasPosition.setMap(world5); + assertEquals(405, atlasPosition.getCurrentMap().getUID()); } @Test void testWorldWithMultipleZones() { // Worlds only have one zone, but we can test zone access World world = new World("Single Zone World", 500); - atlas.setMap(world); + atlasPosition.setMap(world); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); assertNotNull(zone); - assertEquals(0, atlas.getCurrentZoneIndex()); + assertEquals(0, atlasPosition.getCurrentZoneIndex()); } // Note: Dungeon serialization through MapDb requires special handling @@ -167,7 +166,7 @@ void testCachePerformanceWithManyMaps() throws Exception { () -> { for (int i = 0; i < mapCount; i++) { World world = new World("World " + i, 700 + i); - atlas.setMap(world); + atlasPosition.setMap(world); } return null; }); @@ -186,12 +185,12 @@ void testCacheRetrievalPerformance() throws Exception { // Add maps to cache for (int i = 0; i < 20; i++) { World world = new World("World " + i, 800 + i); - atlas.setMap(world); + atlasPosition.setMap(world); } // Measure retrieval time PerformanceHarness.MeasuredResult result = - PerformanceHarness.measure(() -> atlas.getCurrentMap()); + PerformanceHarness.measure(() -> atlasPosition.getCurrentMap()); System.out.printf( "[PERF] Cache retrieval: %d ms (%d ns)%n", @@ -204,9 +203,22 @@ void testCacheRetrievalPerformance() throws Exception { @Test void testMapDbPersistsAcrossAtlasInstances() throws IOException { // Create first atlas and add map - Atlas atlas1 = new Atlas(TestEngineContext.getStubFileSystem(), "shared-cache"); + Atlas atlas1 = + new Atlas( + TestEngineContext.getStubFileSystem(), + "shared-cache", + TestEngineContext.getTestEntityStore()); + AtlasPosition atlasPosition = + new AtlasPosition( + atlas1, + TestEngineContext.getTestZoneActivator(), + TestEngineContext.getTestResources(), + new QuestTracker(), + TestEngineContext.getTestEntityStore()); + World world = new World("Persistent World", 900); - atlas1.setMap(world); + + atlasPosition.setMap(world); // Create second atlas with same cache name // Note: In the current implementation, Atlas always creates a new in-memory DB, diff --git a/src/test/java/neon/maps/MapPerformanceTest.java b/src/test/java/neon/maps/MapPerformanceTest.java index e38d357..dc8eaba 100644 --- a/src/test/java/neon/maps/MapPerformanceTest.java +++ b/src/test/java/neon/maps/MapPerformanceTest.java @@ -1,6 +1,5 @@ package neon.maps; -import static neon.maps.Atlas.createDefaultZoneActivator; import static org.junit.jupiter.api.Assertions.*; import java.awt.Rectangle; @@ -10,8 +9,7 @@ import neon.entities.Creature; import neon.entities.Item; import neon.maps.services.EngineEntityStore; -import neon.maps.services.EngineQuestProvider; -import neon.maps.services.EngineResourceProvider; +import neon.narrative.QuestTracker; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; @@ -408,13 +406,14 @@ void testZoneMultiLayerPerformance() throws Exception { @Test void testAtlasMapCachingPerformance() throws Exception { Atlas atlas = - new Atlas( - TestEngineContext.getStubFileSystem(), - testDb, - new EngineEntityStore(), - new EngineResourceProvider(), - new EngineQuestProvider(), - createDefaultZoneActivator()); + new Atlas(TestEngineContext.getStubFileSystem(), "test-atlas", new EngineEntityStore()); + AtlasPosition atlasPosition = + new AtlasPosition( + atlas, + TestEngineContext.getTestZoneActivator(), + TestEngineContext.getTestResources(), + new QuestTracker(), + TestEngineContext.getTestEntityStore()); int mapCount = 100; PerformanceHarness.MeasuredResult result = @@ -422,7 +421,7 @@ void testAtlasMapCachingPerformance() throws Exception { () -> { for (int i = 0; i < mapCount; i++) { World world = new World("World " + i, 2000 + i); - atlas.setMap(world); + atlasPosition.setMap(world); } return mapCount; }); @@ -438,14 +437,25 @@ void testAtlasMapCachingPerformance() throws Exception { @Test void testAtlasMapSwitchingPerformance() throws Exception { - Atlas atlas = new Atlas(TestEngineContext.getStubFileSystem(), "switch-perf-atlas"); + Atlas atlas = + new Atlas( + TestEngineContext.getStubFileSystem(), + "switch-perf-atlas", + TestEngineContext.getTestEntityStore()); + AtlasPosition atlasPosition = + new AtlasPosition( + atlas, + TestEngineContext.getTestZoneActivator(), + TestEngineContext.getTestResources(), + new QuestTracker(), + TestEngineContext.getTestEntityStore()); // Create and cache 50 maps List worlds = new ArrayList<>(); for (int i = 0; i < 50; i++) { World world = new World("World " + i, 3000 + i); worlds.add(world); - atlas.setMap(world); + atlasPosition.setMap(world); } int switchCount = 1000; @@ -455,8 +465,8 @@ void testAtlasMapSwitchingPerformance() throws Exception { () -> { for (int i = 0; i < switchCount; i++) { World world = worlds.get(i % worlds.size()); - atlas.setMap(world); - atlas.getCurrentMap(); + atlasPosition.setMap(world); + atlasPosition.getCurrentMap(); } return switchCount; }); @@ -474,12 +484,19 @@ void testAtlasMapSwitchingPerformance() throws Exception { @Test void testAtlasZoneAccessPerformance() throws Exception { - Atlas atlas = new Atlas(TestEngineContext.getStubFileSystem(), "zone-access-atlas"); + Atlas atlas = TestEngineContext.getTestAtlas(); + AtlasPosition atlasPosition = + new AtlasPosition( + atlas, + TestEngineContext.getTestZoneActivator(), + TestEngineContext.getTestResources(), + new QuestTracker(), + TestEngineContext.getTestEntityStore()); World world = new World("Zone Access World", 4000); - atlas.setMap(world); + atlasPosition.setMap(world); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); for (int i = 0; i < 100; i++) { Region region = MapTestFixtures.createTestRegion(i * 10, i * 10, 10, 10); zone.addRegion(region); @@ -494,7 +511,7 @@ void testAtlasZoneAccessPerformance() throws Exception { () -> { int sum = 0; for (int i = 0; i < accessCount; i++) { - Zone z = atlas.getCurrentZone(); + Zone z = atlasPosition.getCurrentZone(); sum += z.getRegions().size(); } return sum; @@ -516,15 +533,22 @@ void testAtlasZoneAccessPerformance() throws Exception { @Test void testFullMapLoadAndQueryPerformance() throws Exception { Atlas atlas = new Atlas(TestEngineContext.getStubFileSystem(), "full-perf-atlas"); + AtlasPosition atlasPosition = + new AtlasPosition( + atlas, + TestEngineContext.getTestZoneActivator(), + TestEngineContext.getTestResources(), + new QuestTracker(), + TestEngineContext.getTestEntityStore()); PerformanceHarness.MeasuredResult result = PerformanceHarness.measure( () -> { // Create a large world World world = new World("Large World", 5000); - atlas.setMap(world); + atlasPosition.setMap(world); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); // Add 500 regions with creatures and items long uidCounter = 70000; @@ -583,6 +607,13 @@ void testFullMapLoadAndQueryPerformance() throws Exception { @Test void testMemoryEfficiencyWithLargeMaps() throws Exception { Atlas atlas = new Atlas(TestEngineContext.getStubFileSystem(), "memory-test-atlas"); + AtlasPosition atlasPosition = + new AtlasPosition( + atlas, + TestEngineContext.getTestZoneActivator(), + TestEngineContext.getTestResources(), + new QuestTracker(), + TestEngineContext.getTestEntityStore()); Runtime runtime = Runtime.getRuntime(); runtime.gc(); @@ -591,9 +622,9 @@ void testMemoryEfficiencyWithLargeMaps() throws Exception { // Create 10 large worlds for (int w = 0; w < 10; w++) { World world = new World("World " + w, 6000 + w); - atlas.setMap(world); + atlasPosition.setMap(world); - Zone zone = atlas.getCurrentZone(); + Zone zone = atlasPosition.getCurrentZone(); for (int i = 0; i < 200; i++) { Region region = MapTestFixtures.createTestRegion(i * 5, i * 5, 10, 10); zone.addRegion(region); diff --git a/src/test/java/neon/maps/generators/DungeonGeneratorTest.java b/src/test/java/neon/maps/generators/DungeonGeneratorTest.java index 93a9d10..cfff904 100644 --- a/src/test/java/neon/maps/generators/DungeonGeneratorTest.java +++ b/src/test/java/neon/maps/generators/DungeonGeneratorTest.java @@ -9,12 +9,7 @@ import java.util.stream.Stream; import neon.entities.Door; import neon.entities.Entity; -import neon.maps.Atlas; -import neon.maps.Dungeon; -import neon.maps.MapTestFixtures; -import neon.maps.MapUtils; -import neon.maps.Zone; -import neon.maps.ZoneFactory; +import neon.maps.*; import neon.maps.services.EntityStore; import neon.maps.services.QuestProvider; import neon.maps.services.ResourceProvider; @@ -603,6 +598,7 @@ class GenerateWithContextTests { private Atlas testAtlas; private ZoneFactory zoneFactory; private EntityStore entityStore; + private AtlasPosition testAtlasPosition; @BeforeEach void setUp() throws Exception { @@ -738,7 +734,7 @@ void generate_createsZoneWithRegions() throws Exception { previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); // Add the dungeon to the atlas - testAtlas.setMap(dungeon); + testAtlasPosition.setMap(dungeon); // Create a door in the previous zone that leads to zone 1 Door entryDoor = @@ -797,7 +793,7 @@ void generate_linksDoorsCorrectly() throws Exception { // Add a region to the previous zone previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); - testAtlas.setMap(dungeon); + testAtlasPosition.setMap(dungeon); // Create entry door in previous zone Door entryDoor = @@ -863,7 +859,7 @@ void generate_handlesZoneConnections() throws Exception { dungeon.addConnection(1, 0); dungeon.addConnection(1, 2); - testAtlas.setMap(dungeon); + testAtlasPosition.setMap(dungeon); // Create entry door from zone 0 to zone 1 Door entryDoor = @@ -913,7 +909,7 @@ void generate_placesQuestItem() throws Exception { // Add a region to the previous zone previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); - testAtlas.setMap(dungeon); + testAtlasPosition.setMap(dungeon); Door entryDoor = MapTestFixtures.createTestPortalDoor(entityStore.createNewEntityUID(), 25, 25, 1, 0); @@ -988,7 +984,7 @@ void generate_placesQuestCreature() throws Exception { // Add a region to the previous zone previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); - testAtlas.setMap(dungeon); + testAtlasPosition.setMap(dungeon); Door entryDoor = MapTestFixtures.createTestPortalDoor(entityStore.createNewEntityUID(), 25, 25, 1, 0); @@ -1070,7 +1066,7 @@ void generate_isDeterministicWithFullContext() throws Exception { // Add a region to the previous zone previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); - testAtlas.setMap(dungeon); + testAtlasPosition.setMap(dungeon); Door entryDoor = MapTestFixtures.createTestPortalDoor(entityStore.createNewEntityUID(), 25, 25, 1, 0); diff --git a/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java b/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java index ad326c1..3956b9b 100644 --- a/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java +++ b/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java @@ -8,11 +8,7 @@ import java.util.stream.Stream; import neon.entities.Door; import neon.entities.Entity; -import neon.maps.Atlas; -import neon.maps.Dungeon; -import neon.maps.MapTestFixtures; -import neon.maps.MapUtils; -import neon.maps.Zone; +import neon.maps.*; import neon.maps.services.EntityStore; import neon.maps.services.QuestProvider; import neon.resources.RDungeonTheme; @@ -326,6 +322,7 @@ class GenerateWithFullContextTests { private MVStore testDb; private Atlas testAtlas; private EntityStore entityStore; + private AtlasPosition testAtlasPosition; @BeforeEach void setUp() throws Exception { @@ -340,6 +337,7 @@ void setUp() throws Exception { TestEngineContext.loadTestResourceViaConfig("src/test/resources/neon.ini.sampleMod1.xml"); // TestEngineContext.loadTestResources("src/test/resources/sampleMod1"); testAtlas = TestEngineContext.getTestAtlas(); + testAtlasPosition = TestEngineContext.getAtlasPosition(); entityStore = TestEngineContext.getTestEntityStore(); } @@ -374,7 +372,7 @@ void generate_withXmlZoneTheme_createsZoneWithRegions(ZoneThemeScenario scenario Zone targetZone = dungeon.getZone(1); previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); - testAtlas.setMap(dungeon); + testAtlasPosition.setMap(dungeon); // Create entry door in previous zone Door entryDoor = @@ -414,7 +412,7 @@ void generate_withXmlZoneTheme_linksDoorsCorrectly(ZoneThemeScenario scenario) Zone targetZone = dungeon.getZone(1); previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); - testAtlas.setMap(dungeon); + testAtlasPosition.setMap(dungeon); Door entryDoor = MapTestFixtures.createTestPortalDoor(entityStore.createNewEntityUID(), 10, 10, 1, 0); diff --git a/src/test/java/neon/test/TestEngineContext.java b/src/test/java/neon/test/TestEngineContext.java index d73b6b6..764c57b 100644 --- a/src/test/java/neon/test/TestEngineContext.java +++ b/src/test/java/neon/test/TestEngineContext.java @@ -15,9 +15,11 @@ import neon.entities.components.PhysicsComponent; import neon.entities.property.Gender; import neon.maps.Atlas; +import neon.maps.AtlasPosition; import neon.maps.ZoneActivator; import neon.maps.ZoneFactory; import neon.maps.services.*; +import neon.narrative.QuestTracker; import neon.resources.*; import neon.resources.builder.IniBuilder; import neon.systems.files.FileSystem; @@ -37,15 +39,30 @@ public class TestEngineContext { private static MVStore testDb; - private static Atlas testAtlas; + + /** -- GETTER -- Gets the test Atlas instance. */ + @Getter private static Atlas testAtlas; + private static StubResourceManager testResources; private static Game testGame; private static UIDStore testStore; - private static ZoneFactory testZoneFactory; - private static EntityStore testEntityStore; - private static ZoneActivator testZoneActivator; + @Getter private static PhysicsManager stubPhysicsManager; + + @Getter private static AtlasPosition atlasPosition; + + /** -- GETTER -- Gets the test ZoneFactory instance. */ + @Getter private static ZoneFactory testZoneFactory; + + /** -- GETTER -- Gets the test ResourceProvider instance. */ + @Getter private static EntityStore testEntityStore; + + @Getter private static ZoneActivator testZoneActivator; + @Getter private static PhysicsSystem physicsSystem; + @Getter private static StubFileSystem stubFileSystem; + @Getter private static QuestTracker questTracker; + static { try { stubFileSystem = new StubFileSystem(); @@ -81,30 +98,25 @@ public static void initialize(MVStore db) throws Exception { // Create test UIDStore testStore = new UIDStore("test-store.dat"); - + questTracker = new QuestTracker(); // Create test EntityStore testEntityStore = new StubEntityStore(testStore); // Create stub PhysicsManager and ZoneActivator - PhysicsManager stubPhysicsManager = new StubPhysicsManager(); + stubPhysicsManager = new StubPhysicsManager(); Player stubPlayer = new StubPlayer(); - testZoneActivator = new ZoneActivator(stubPhysicsManager, () -> stubPlayer); + testZoneActivator = new ZoneActivator(stubPhysicsManager); // Create ZoneFactory for tests testZoneFactory = new ZoneFactory(db); // Create test Atlas with dependency injection (doesn't need Engine.game) - testAtlas = - new Atlas( - getStubFileSystem(), - db, - testEntityStore, - new EngineResourceProvider(), - new EngineQuestProvider(), - testZoneActivator); - + testAtlas = new Atlas(getStubFileSystem(), "test-atlas", testEntityStore); + atlasPosition = + new AtlasPosition( + testAtlas, testZoneActivator, testResources, questTracker, testEntityStore); // Create test Game using new DI constructor - testGame = new Game(stubPlayer, testAtlas, testStore); + testGame = new Game(stubPlayer, testAtlas, testStore, atlasPosition); setStaticField(Engine.class, "game", testGame); // Create stub FileSystem @@ -124,6 +136,7 @@ public static void reset() { if (testStore != null) { testStore.getCache().close(); } + if (testAtlas != null) { testAtlas.close(); } @@ -144,31 +157,16 @@ public static void reset() { } } - /** Gets the test Atlas instance. */ - public static Atlas getTestAtlas() { - return testAtlas; - } - /** Gets the test ResourceManager instance. */ public static ResourceManager getTestResources() { return testResources; } - /** Gets the test ResourceProvider instance. */ - public static EntityStore getTestEntityStore() { - return testEntityStore; - } - /** Gets the test ResourceProvider instance. */ public static ResourceProvider getTestResourceProvider() { return testResources; } - /** Gets the test ZoneFactory instance. */ - public static ZoneFactory getTestZoneFactory() { - return testZoneFactory; - } - public static void loadTestResourceViaConfig(String configFilename) throws Exception { IniBuilder iniBuilder = new IniBuilder(configFilename, getStubFileSystem(), new TaskQueue()); iniBuilder.build(getTestResources()); From 05b3d8eeb5c2379baaded4c87c1d267678626bc3 Mon Sep 17 00:00:00 2001 From: Peter Riewe Date: Sat, 10 Jan 2026 21:58:50 -0500 Subject: [PATCH 02/12] Merge and replace MVStore with interface --- .../java/neon/core/DefaultGameContext.java | 7 ++ src/main/java/neon/core/Game.java | 4 +- src/main/java/neon/core/GameContext.java | 3 + src/main/java/neon/core/GameLoader.java | 35 ++++--- .../neon/core/handlers/MotionHandler.java | 13 ++- src/main/java/neon/entities/UIDStore.java | 8 +- src/main/java/neon/maps/Atlas.java | 96 ++++--------------- src/main/java/neon/maps/MapLoader.java | 24 +++-- src/main/java/neon/maps/Zone.java | 8 +- src/main/java/neon/maps/ZoneFactory.java | 6 +- .../java/neon/util/mapstorage/MapStore.java | 16 ++++ .../mapstorage/MapStoreMVStoreAdapter.java | 37 +++++++ src/main/java/neon/util/spatial/RTree.java | 4 +- src/test/java/neon/core/GameLoaderTest.java | 4 +- .../java/neon/maps/AtlasIntegrationTest.java | 11 ++- src/test/java/neon/maps/AtlasTest.java | 15 ++- .../java/neon/maps/MapPerformanceTest.java | 28 ++++-- .../java/neon/maps/MapSerializationTest.java | 4 +- .../java/neon/maps/RegionIntegrationTest.java | 4 +- .../neon/maps/RegionSerializationTest.java | 4 +- .../java/neon/maps/ZoneIntegrationTest.java | 4 +- .../java/neon/maps/ZoneSerializationTest.java | 4 +- .../maps/generators/DungeonGeneratorTest.java | 4 +- .../DungeonGeneratorXmlIntegrationTest.java | 4 +- .../TownGeneratorIntegrationTest.java | 4 +- .../WildernessGeneratorIntegrationTest.java | 4 +- src/test/java/neon/test/MapDbTestHelper.java | 26 ++--- .../java/neon/test/TestEngineContext.java | 17 ++-- .../util/spatial/RTreePersistenceTest.java | 4 +- 29 files changed, 224 insertions(+), 178 deletions(-) create mode 100644 src/main/java/neon/util/mapstorage/MapStore.java create mode 100644 src/main/java/neon/util/mapstorage/MapStoreMVStoreAdapter.java diff --git a/src/main/java/neon/core/DefaultGameContext.java b/src/main/java/neon/core/DefaultGameContext.java index 9ecf90b..d0a7fa8 100644 --- a/src/main/java/neon/core/DefaultGameContext.java +++ b/src/main/java/neon/core/DefaultGameContext.java @@ -25,6 +25,7 @@ import neon.entities.UIDStore; import neon.maps.Atlas; import neon.maps.AtlasPosition; +import neon.maps.services.PhysicsManager; import neon.narrative.QuestTracker; import neon.resources.ResourceManager; import neon.systems.files.FileSystem; @@ -49,6 +50,7 @@ public class DefaultGameContext implements GameContext { @Setter private ResourceManager resources; @Setter private QuestTracker questTracker; @Setter private PhysicsSystem physicsEngine; + @Setter private PhysicsManager physicsManager; @Setter private Context scriptEngine; @Setter private MBassador bus; @Setter private FileSystem fileSystem; @@ -98,6 +100,11 @@ public PhysicsSystem getPhysicsEngine() { return physicsEngine; } + @Override + public PhysicsManager getPhysicsManager() { + return physicsManager; + } + @Override public Context getScriptEngine() { return scriptEngine; diff --git a/src/main/java/neon/core/Game.java b/src/main/java/neon/core/Game.java index f49d6e1..8bf0ee9 100644 --- a/src/main/java/neon/core/Game.java +++ b/src/main/java/neon/core/Game.java @@ -25,6 +25,7 @@ import neon.entities.UIDStore; import neon.maps.Atlas; import neon.maps.AtlasPosition; +import neon.maps.MapLoader; import neon.maps.ZoneActivator; import neon.maps.services.PhysicsManager; import neon.narrative.QuestTracker; @@ -47,7 +48,8 @@ public Game( ResourceManager resourceManager, QuestTracker questTracker) { store = new UIDStore(files.getFullPath("uidstore")); - atlas = new Atlas(files, files.getFullPath("atlas"), store); + MapLoader mapLoader = new MapLoader(store, resourceManager, files); + atlas = new Atlas(files, files.getFullPath("atlas"), store, mapLoader); this.player = player; this.atlasPosition = new AtlasPosition( diff --git a/src/main/java/neon/core/GameContext.java b/src/main/java/neon/core/GameContext.java index c23614a..338c0ed 100644 --- a/src/main/java/neon/core/GameContext.java +++ b/src/main/java/neon/core/GameContext.java @@ -24,6 +24,7 @@ import neon.entities.UIDStore; import neon.maps.Atlas; import neon.maps.AtlasPosition; +import neon.maps.services.PhysicsManager; import neon.narrative.QuestTracker; import neon.resources.ResourceManager; import neon.systems.files.FileSystem; @@ -75,6 +76,8 @@ public interface GameContext { PhysicsSystem getPhysicsEngine(); + PhysicsManager getPhysicsManager(); + Context getScriptEngine(); Object execute(String script); diff --git a/src/main/java/neon/core/GameLoader.java b/src/main/java/neon/core/GameLoader.java index 68b16ae..7d69ef9 100644 --- a/src/main/java/neon/core/GameLoader.java +++ b/src/main/java/neon/core/GameLoader.java @@ -49,7 +49,6 @@ import neon.maps.Atlas; import neon.maps.Map; import neon.maps.MapLoader; -import neon.maps.MapUtils; import neon.maps.services.GameContextResourceProvider; import neon.resources.CGame; import neon.resources.RCreature; @@ -79,7 +78,7 @@ public GameLoader(GameContext context, Configuration config) { this.config = config; queue = context.getQueue(); resourceProvider = new GameContextResourceProvider(context); - mapLoader = new MapLoader(context.getStore(), resourceProvider, new MapUtils()); + mapLoader = new MapLoader(context.getStore(), resourceProvider, context.getFileSystem()); } @Handler @@ -131,14 +130,13 @@ public void initGame( RCreature species = ((RCreature) context.getResources().getResource(race)).clone(); Player player = new Player(species, name, gender, spec, profession); player.species.text = "@"; - context.startGame(new Game(player, context.getFileSystem())); - context.startGame( + context.startGame( new Game( player, - context.getFileSystem(), - context.getPhysicsManager(), - context.getResources(), - context.getQuestTracker())); + context.getFileSystem(), + context.getPhysicsManager(), + context.getResources(), + context.getQuestTracker())); setSign(player, sign); for (Skill skill : Skill.values()) { SkillHandler.checkFeat(skill, player); @@ -169,8 +167,8 @@ public void initGame( Map map = atlas.getMap(store.getMapUID(startMap)); context.getScriptEngine().getBindings("js").putMember("map", map); - context.getAtlas().setMap(map); - context.getAtlas().setCurrentZone(game.getStartZone()); + context.getAtlasPosition().setMap(map); + context.getAtlasPosition().setCurrentZone(game.getStartZone(), player); } catch (RuntimeException re) { log.error("Error during initGame", re); } @@ -291,22 +289,21 @@ private void loadPlayer(SaveGameModel.PlayerSaveData playerData) { Gender.valueOf(playerData.gender.toUpperCase()), Player.Specialisation.valueOf(playerData.specialisation), playerData.profession); - context.startGame(new Game(player, context.getFileSystem())); - context.startGame( + context.startGame( new Game( player, - context.getFileSystem(), - context.getPhysicsManager(), - context.getResources(), - context.getQuestTracker())); + context.getFileSystem(), + context.getPhysicsManager(), + context.getResources(), + context.getQuestTracker())); Rectangle bounds = player.getShapeComponent(); bounds.setLocation(playerData.x, playerData.y); player.setSign(playerData.sign); player.species.text = "@"; // start map - context.getAtlas().setMap(context.getAtlas().getMap(playerData.map)); - context.getAtlas().setCurrentZone(playerData.level); + context.getAtlasPosition().setMap(context.getAtlas().getMap(playerData.map)); + context.getAtlasPosition().setCurrentZone(playerData.level, player); // stats Stats stats = player.getStatsComponent(); @@ -388,7 +385,7 @@ private void initMaps() { Element map = context.getFileSystem().getFile(new XMLTranslator(), path).getRootElement(); short mapUID = Short.parseShort(map.getChild("header").getAttributeValue("uid")); int uid = UIDStore.getMapUID(context.getStore().getModUID(path[0]), mapUID); - mapLoader.load(path, mapUID, context.getFileSystem()); + mapLoader.load(path, mapUID); context.getStore().addMap(uid, path); } catch (Exception e) { log.info("Map error in mod {} : {}", path, e.toString()); diff --git a/src/main/java/neon/core/handlers/MotionHandler.java b/src/main/java/neon/core/handlers/MotionHandler.java index 71c6267..32a7f1e 100644 --- a/src/main/java/neon/core/handlers/MotionHandler.java +++ b/src/main/java/neon/core/handlers/MotionHandler.java @@ -20,8 +20,10 @@ import java.awt.Point; import java.awt.Rectangle; +import java.io.IOException; import java.util.Collection; import javax.swing.SwingConstants; +import lombok.extern.slf4j.Slf4j; import neon.core.Engine; import neon.core.event.MessageEvent; import neon.entities.Creature; @@ -40,6 +42,7 @@ * * @author mdriesen */ +@Slf4j public class MotionHandler { public static final byte OK = 0; public static final byte BLOCKED = 1; @@ -78,9 +81,13 @@ public static byte teleport(Player creature, Door door) { Engine.getScriptEngine().getBindings("js").putMember("map", map); door.portal.setDestMap(Engine.getAtlasPosition().getCurrentMap()); } else if (door.portal.getDestTheme() != null) { - Dungeon dungeon = MapLoader.loadDungeon(door.portal.getDestTheme()); - Engine.getAtlasPosition().setMap(dungeon); - door.portal.setDestMap(Engine.getAtlasPosition().getCurrentMap()); + try { + Dungeon dungeon = MapLoader.loadDungeon(door.portal.getDestTheme()); + Engine.getAtlasPosition().setMap(dungeon); + door.portal.setDestMap(Engine.getAtlasPosition().getCurrentMap()); + } catch (IOException ioe) { + log.error("Error loading dungeon for theme {}", door.portal.getDestTheme(), ioe); + } } Engine.getAtlasPosition().enterZone(door, previous, creature); diff --git a/src/main/java/neon/entities/UIDStore.java b/src/main/java/neon/entities/UIDStore.java index 8412ac2..6aecb7a 100644 --- a/src/main/java/neon/entities/UIDStore.java +++ b/src/main/java/neon/entities/UIDStore.java @@ -24,6 +24,8 @@ import java.util.Map; import lombok.extern.slf4j.Slf4j; import neon.maps.services.EntityStore; +import neon.util.mapstorage.MapStore; +import neon.util.mapstorage.MapStoreMVStoreAdapter; import org.h2.mvstore.MVStore; /** @@ -39,7 +41,7 @@ public class UIDStore implements EntityStore, Closeable { public static final long DUMMY = 0; // uid database - private final MVStore uidDb; + private final MapStore uidDb; // uids of all objects in the game private final Map objects; // uids of all loaded mods @@ -53,7 +55,7 @@ public class UIDStore implements EntityStore, Closeable { * @param file */ public UIDStore(String file) { - uidDb = MVStore.open(file); + uidDb = new MapStoreMVStoreAdapter(MVStore.open(file)); objects = uidDb.openMap("object"); mods = uidDb.openMap("mods"); } @@ -61,7 +63,7 @@ public UIDStore(String file) { /** * @return the jdbm3 cache used by this UIDStore */ - public MVStore getCache() { + public MapStore getCache() { return uidDb; } diff --git a/src/main/java/neon/maps/Atlas.java b/src/main/java/neon/maps/Atlas.java index c8f9886..5c9fcb8 100644 --- a/src/main/java/neon/maps/Atlas.java +++ b/src/main/java/neon/maps/Atlas.java @@ -20,12 +20,13 @@ import java.io.Closeable; import java.io.IOException; +import java.util.concurrent.ConcurrentMap; import lombok.extern.slf4j.Slf4j; -import neon.maps.services.EngineEntityStore; import neon.maps.services.EntityStore; import neon.maps.services.MapAtlas; import neon.systems.files.FileSystem; -import org.h2.mvstore.MVMap; +import neon.util.mapstorage.MapStore; +import neon.util.mapstorage.MapStoreMVStoreAdapter; import org.h2.mvstore.MVStore; /** @@ -35,53 +36,34 @@ */ @Slf4j public class Atlas implements Closeable, MapAtlas { - private final MVStore db; - private final MVMap maps; + private final MapStore db; + private final ConcurrentMap maps; private final EntityStore entityStore; private final FileSystem fileSystem; - private final MapLoader mapLoader; - /** - * Initializes this {@code Atlas} with the given {@code FileSystem} and cache path. The cache is - * lazy initialised. - * - * @param fileSystem a {@code FileSystem} - * @param path the path to the file used for caching - * @deprecated Use {@link #Atlas(FileSystem, String, EntityStore, ZoneActivator)} to avoid - * dependency on Engine singleton - */ - @Deprecated - public Atlas(FileSystem fileSystem, String path) { - this(fileSystem, path, new EngineEntityStore()); - } + private final MapLoader mapLoader; - /** - * Initializes this {@code Atlas} with dependency injection. - * - * @param fileSystem the file system - * @param atlasStore the MVStore for caching - * @param entityStore the entity store service - */ - public Atlas(FileSystem fileSystem, String path, EntityStore entityStore) { + /** Initializes this {@code Atlas} with dependency injection. */ + public Atlas(FileSystem fileSystem, String path, EntityStore entityStore, MapLoader mapLoader) { this.fileSystem = fileSystem; this.entityStore = entityStore; - this.db = getMVStore(fileSystem, path); + this.db = getMapStore(fileSystem, path); // files.delete(path); // String fileName = files.getFullPath(path); // log.warn("Creating new MVStore at {}", fileName); - this.mapLoader = new MapLoader(this.entityStore, this.resourceProvider); + this.mapLoader = mapLoader; // db = MVStore.open(fileName); maps = db.openMap("maps"); } - private static MVStore getMVStore(FileSystem files, String fileName) { + private MapStore getMapStore(FileSystem files, String fileName) { files.delete(fileName); log.warn("Creating new MVStore at {}", fileName); - return MVStore.open(fileName); + return new MapStoreMVStoreAdapter(MVStore.open(fileName)); } - public MVStore getCache() { + public MapStore getCache() { return db; } @@ -95,60 +77,20 @@ public Map getMap(int uid) { if (entityStore.getMapPath(uid) == null) { throw new RuntimeException(String.format("No existing mappath for uid %d", uid)); } - Map map = mapLoader.load(entityStore.getMapPath(uid), uid, files); + Map map = mapLoader.load(entityStore.getMapPath(uid), uid); System.out.println("Loaded map " + map.toString()); maps.put(uid, map); } return maps.get(uid); } - @Override - public Map getMap(int uid, String... path) { - Map map = mapLoader.load(path, uid, files); - return map; - } - - public void putMapIfNeeded(Map map) { - if (!maps.containsKey(map.getUID())) { - // could be a random map that's not in the database yet - maps.put(map.getUID(), map); - } - } - /** - * Sets the current zone. - * - * @param i the index of the current zone - */ - public void setCurrentZone(int i) { - currentZone = i; - zoneActivator.activateZone(getCurrentZone()); - } - - /** - * Enter a new zone through a door. - * - * @param door - * @param previousZone - */ - public void enterZone(Door door, Zone previousZone) { - if (door.portal.getDestZone() > -1) { - setCurrentZone(door.portal.getDestZone()); - } else { - setCurrentZone(0); - } - - if (getCurrentMap() instanceof Dungeon && getCurrentZone().isRandom()) { - new DungeonGenerator(getCurrentZone(), entityStore, resourceProvider, questProvider) - .generate(door, previousZone, this); - } + @Override + public Map getMap(int uid, String... path) { + Map map = mapLoader.load(path, uid); + return map; } - /** - * Set the current map. - * - * @param map the new current map - */ - public void setMap(Map map) { + public void putMapIfNeeded(Map map) { if (!maps.containsKey(map.getUID())) { // could be a random map that's not in the database yet maps.put(map.getUID(), map); diff --git a/src/main/java/neon/maps/MapLoader.java b/src/main/java/neon/maps/MapLoader.java index 399225f..b01dea1 100644 --- a/src/main/java/neon/maps/MapLoader.java +++ b/src/main/java/neon/maps/MapLoader.java @@ -21,6 +21,7 @@ import java.awt.Point; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import neon.core.*; import neon.entities.Container; import neon.entities.Creature; @@ -60,6 +61,7 @@ public class MapLoader { private final EntityStore entityStore; private final ResourceProvider resourceProvider; private final MapUtils mapUtils; + private final FileSystem fileSystem; /** * Creates a MapLoader with dependency injection. @@ -67,8 +69,9 @@ public class MapLoader { * @param entityStore the entity store service * @param resourceProvider the resource provider service */ - public MapLoader(EntityStore entityStore, ResourceProvider resourceProvider) { - this(entityStore, resourceProvider, new MapUtils()); + public MapLoader( + EntityStore entityStore, ResourceProvider resourceProvider, FileSystem fileSystem) { + this(entityStore, resourceProvider, new MapUtils(), fileSystem); } /** @@ -78,10 +81,15 @@ public MapLoader(EntityStore entityStore, ResourceProvider resourceProvider) { * @param resourceProvider the resource provider service * @param mapUtils the MapUtils instance for random operations */ - public MapLoader(EntityStore entityStore, ResourceProvider resourceProvider, MapUtils mapUtils) { + public MapLoader( + EntityStore entityStore, + ResourceProvider resourceProvider, + MapUtils mapUtils, + FileSystem fileSystem) { this.entityStore = entityStore; this.resourceProvider = resourceProvider; this.mapUtils = mapUtils; + this.fileSystem = fileSystem; } /** @@ -89,8 +97,8 @@ public MapLoader(EntityStore entityStore, ResourceProvider resourceProvider, Map * * @return a new MapLoader instance */ - private static MapLoader createDefault() { - return new MapLoader(new EngineEntityStore(), new EngineResourceProvider()); + private static MapLoader createDefault() throws IOException { + return new MapLoader(new EngineEntityStore(), new EngineResourceProvider(), new FileSystem()); } /** @@ -101,11 +109,11 @@ private static MapLoader createDefault() { * @param files the file system * @return the Map described by the map file */ - public Map load(@NotNull String[] path, int uid, FileSystem files) { + public Map load(@NotNull String[] path, int uid) { // For now, use JDOM to determine type, then build models // In the future, FileSystem can provide InputStream directly - Document doc = files.getFile(new XMLTranslator(), path); + Document doc = fileSystem.getFile(new XMLTranslator(), path); Element root = doc.getRootElement(); if (root.getName().equals("world")) { @@ -130,7 +138,7 @@ public Map load(@NotNull String[] path, int uid, FileSystem files) { * @deprecated Use instance method {@link #loadThemedDungeon(String, String, int)} instead */ @Deprecated - public static Dungeon loadDungeon(String theme) { + public static Dungeon loadDungeon(String theme) throws IOException { MapLoader loader = createDefault(); return loader.loadThemedDungeon(theme, theme, loader.entityStore.createNewMapUID()); } diff --git a/src/main/java/neon/maps/Zone.java b/src/main/java/neon/maps/Zone.java index 8516a0a..ae0ab98 100644 --- a/src/main/java/neon/maps/Zone.java +++ b/src/main/java/neon/maps/Zone.java @@ -30,8 +30,8 @@ import neon.entities.Item; import neon.resources.RZoneTheme; import neon.ui.graphics.*; +import neon.util.mapstorage.MapStore; import neon.util.spatial.*; -import org.h2.mvstore.MVStore; public class Zone implements Externalizable { private static final ZComparator comparator = new ZComparator(); @@ -89,7 +89,7 @@ public Zone(String name, int map, RZoneTheme theme, int index) { * @param index the zone index * @param cache the MapDB cache for spatial indices */ - private Zone(String name, int map, int index, MVStore cache) { + private Zone(String name, int map, int index, MapStore cache) { this.map = map; this.name = name; this.index = index; @@ -105,7 +105,7 @@ private Zone(String name, int map, int index, MVStore cache) { * @param cache the MapDB cache for spatial indices * @return a new Zone instance */ - static Zone create(String name, int mapUID, int index, MVStore cache) { + static Zone create(String name, int mapUID, int index, MapStore cache) { return new Zone(name, mapUID, index, cache); } @@ -119,7 +119,7 @@ static Zone create(String name, int mapUID, int index, MVStore cache) { * @param cache the MapDB cache for spatial indices * @return a new Zone instance with a theme */ - static Zone create(String name, int mapUID, RZoneTheme theme, int index, MVStore cache) { + static Zone create(String name, int mapUID, RZoneTheme theme, int index, MapStore cache) { Zone zone = new Zone(name, mapUID, index, cache); zone.theme = theme; return zone; diff --git a/src/main/java/neon/maps/ZoneFactory.java b/src/main/java/neon/maps/ZoneFactory.java index a846731..419c789 100644 --- a/src/main/java/neon/maps/ZoneFactory.java +++ b/src/main/java/neon/maps/ZoneFactory.java @@ -19,7 +19,7 @@ package neon.maps; import neon.resources.RZoneTheme; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; /** * Factory for creating Zone instances with proper dependency injection. Eliminates the constructor @@ -28,14 +28,14 @@ * @author mdriesen */ public class ZoneFactory { - private final MVStore cache; + private final MapStore cache; /** * Creates a new ZoneFactory with the given cache database. * * @param cache the MapDB cache database for spatial indices */ - public ZoneFactory(MVStore cache) { + public ZoneFactory(MapStore cache) { this.cache = cache; } diff --git a/src/main/java/neon/util/mapstorage/MapStore.java b/src/main/java/neon/util/mapstorage/MapStore.java new file mode 100644 index 0000000..46dc80e --- /dev/null +++ b/src/main/java/neon/util/mapstorage/MapStore.java @@ -0,0 +1,16 @@ +package neon.util.mapstorage; + +import java.util.Collection; +import java.util.concurrent.ConcurrentMap; + +public interface MapStore { + void close(); + + long commit(); + + ConcurrentMap openMap(String filename); + + boolean isClosed(); + + Collection getMapNames(); +} diff --git a/src/main/java/neon/util/mapstorage/MapStoreMVStoreAdapter.java b/src/main/java/neon/util/mapstorage/MapStoreMVStoreAdapter.java new file mode 100644 index 0000000..dc2dd4a --- /dev/null +++ b/src/main/java/neon/util/mapstorage/MapStoreMVStoreAdapter.java @@ -0,0 +1,37 @@ +package neon.util.mapstorage; + +import java.util.Collection; +import java.util.concurrent.ConcurrentMap; +import org.h2.mvstore.MVStore; + +public class MapStoreMVStoreAdapter implements MapStore { + private final MVStore mvStore; + + public MapStoreMVStoreAdapter(MVStore mvStore) { + this.mvStore = mvStore; + } + + @Override + public void close() { + mvStore.close(); + } + + @Override + public long commit() { + return mvStore.commit(); + } + + @Override + public ConcurrentMap openMap(String filename) { + return mvStore.openMap(filename); + } + + @Override + public boolean isClosed() { + return mvStore.isClosed(); + } + + public Collection getMapNames() { + return mvStore.getMapNames(); + } +} diff --git a/src/main/java/neon/util/spatial/RTree.java b/src/main/java/neon/util/spatial/RTree.java index 86cb88b..6d0572f 100644 --- a/src/main/java/neon/util/spatial/RTree.java +++ b/src/main/java/neon/util/spatial/RTree.java @@ -24,7 +24,7 @@ import java.util.*; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicInteger; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.jetbrains.annotations.NotNull; /** @@ -65,7 +65,7 @@ public RTree(int nodeSize, int fillFactor) throws IllegalArgumentException { * @param nodeSize the requested node size * @param fillFactor the requested fill factor */ - public RTree(int nodeSize, int fillFactor, MVStore db, String name) + public RTree(int nodeSize, int fillFactor, MapStore db, String name) throws IllegalArgumentException { if (fillFactor > nodeSize / 2) { throw new IllegalArgumentException("Fill factor too high."); diff --git a/src/test/java/neon/core/GameLoaderTest.java b/src/test/java/neon/core/GameLoaderTest.java index eea9309..5b35aa1 100644 --- a/src/test/java/neon/core/GameLoaderTest.java +++ b/src/test/java/neon/core/GameLoaderTest.java @@ -25,7 +25,7 @@ import neon.resources.RSign; import neon.test.MapDbTestHelper; import neon.test.TestEngineContext; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -38,7 +38,7 @@ */ public class GameLoaderTest { - private MVStore testDb; + private MapStore testDb; @BeforeEach public void setUp() throws Exception { diff --git a/src/test/java/neon/maps/AtlasIntegrationTest.java b/src/test/java/neon/maps/AtlasIntegrationTest.java index f492b78..503975a 100644 --- a/src/test/java/neon/maps/AtlasIntegrationTest.java +++ b/src/test/java/neon/maps/AtlasIntegrationTest.java @@ -8,7 +8,7 @@ import neon.narrative.QuestTracker; import neon.test.MapDbTestHelper; import neon.test.TestEngineContext; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -20,7 +20,7 @@ */ class AtlasIntegrationTest { - private MVStore testDb; + private MapStore testDb; private Atlas atlas; AtlasPosition atlasPosition; @@ -28,7 +28,12 @@ class AtlasIntegrationTest { void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); - atlas = new Atlas(TestEngineContext.getStubFileSystem(), "test-atlas", new EngineEntityStore()); + atlas = + new Atlas( + TestEngineContext.getStubFileSystem(), + "test-atlas", + TestEngineContext.getTestEntityStore(), + TestEngineContext.getMapLoader()); atlasPosition = new AtlasPosition( atlas, diff --git a/src/test/java/neon/maps/AtlasTest.java b/src/test/java/neon/maps/AtlasTest.java index 290ba48..471ae9c 100644 --- a/src/test/java/neon/maps/AtlasTest.java +++ b/src/test/java/neon/maps/AtlasTest.java @@ -3,12 +3,11 @@ import static org.junit.jupiter.api.Assertions.*; import java.io.IOException; -import neon.maps.services.EngineEntityStore; import neon.narrative.QuestTracker; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -20,7 +19,7 @@ */ class AtlasTest { - private MVStore testDb; + private MapStore testDb; private Atlas atlas; private AtlasPosition atlasPosition; @@ -28,7 +27,12 @@ class AtlasTest { void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); - atlas = new Atlas(TestEngineContext.getStubFileSystem(), "atlas-test", new EngineEntityStore()); + atlas = + new Atlas( + TestEngineContext.getStubFileSystem(), + "atlas-test", + TestEngineContext.getTestEntityStore(), + TestEngineContext.getMapLoader()); atlasPosition = new AtlasPosition( atlas, @@ -207,7 +211,8 @@ void testMapDbPersistsAcrossAtlasInstances() throws IOException { new Atlas( TestEngineContext.getStubFileSystem(), "shared-cache", - TestEngineContext.getTestEntityStore()); + TestEngineContext.getTestEntityStore(), + TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( atlas1, diff --git a/src/test/java/neon/maps/MapPerformanceTest.java b/src/test/java/neon/maps/MapPerformanceTest.java index dc8eaba..1b8a97c 100644 --- a/src/test/java/neon/maps/MapPerformanceTest.java +++ b/src/test/java/neon/maps/MapPerformanceTest.java @@ -8,12 +8,11 @@ import java.util.List; import neon.entities.Creature; import neon.entities.Item; -import neon.maps.services.EngineEntityStore; import neon.narrative.QuestTracker; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -25,7 +24,7 @@ */ class MapPerformanceTest { - private MVStore testDb; + private MapStore testDb; @BeforeEach void setUp() throws Exception { @@ -406,7 +405,11 @@ void testZoneMultiLayerPerformance() throws Exception { @Test void testAtlasMapCachingPerformance() throws Exception { Atlas atlas = - new Atlas(TestEngineContext.getStubFileSystem(), "test-atlas", new EngineEntityStore()); + new Atlas( + TestEngineContext.getStubFileSystem(), + "test-atlas", + TestEngineContext.getTestEntityStore(), + TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( atlas, @@ -441,7 +444,8 @@ void testAtlasMapSwitchingPerformance() throws Exception { new Atlas( TestEngineContext.getStubFileSystem(), "switch-perf-atlas", - TestEngineContext.getTestEntityStore()); + TestEngineContext.getTestEntityStore(), + TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( atlas, @@ -532,7 +536,12 @@ void testAtlasZoneAccessPerformance() throws Exception { @Test void testFullMapLoadAndQueryPerformance() throws Exception { - Atlas atlas = new Atlas(TestEngineContext.getStubFileSystem(), "full-perf-atlas"); + Atlas atlas = + new Atlas( + TestEngineContext.getStubFileSystem(), + "full-perf-atlas", + TestEngineContext.getTestEntityStore(), + TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( atlas, @@ -606,7 +615,12 @@ void testFullMapLoadAndQueryPerformance() throws Exception { @Test void testMemoryEfficiencyWithLargeMaps() throws Exception { - Atlas atlas = new Atlas(TestEngineContext.getStubFileSystem(), "memory-test-atlas"); + Atlas atlas = + new Atlas( + TestEngineContext.getStubFileSystem(), + "memory-test-atlas", + TestEngineContext.getTestEntityStore(), + TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( atlas, diff --git a/src/test/java/neon/maps/MapSerializationTest.java b/src/test/java/neon/maps/MapSerializationTest.java index 1ab9b73..e4dc0b0 100644 --- a/src/test/java/neon/maps/MapSerializationTest.java +++ b/src/test/java/neon/maps/MapSerializationTest.java @@ -7,7 +7,7 @@ import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -20,7 +20,7 @@ */ class MapSerializationTest { - private MVStore testDb; + private MapStore testDb; @BeforeEach void setUp() throws Exception { diff --git a/src/test/java/neon/maps/RegionIntegrationTest.java b/src/test/java/neon/maps/RegionIntegrationTest.java index 72519e5..e13d9bf 100644 --- a/src/test/java/neon/maps/RegionIntegrationTest.java +++ b/src/test/java/neon/maps/RegionIntegrationTest.java @@ -6,7 +6,7 @@ import neon.resources.RTerrain; import neon.test.MapDbTestHelper; import neon.test.TestEngineContext; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -18,7 +18,7 @@ */ class RegionIntegrationTest { - private MVStore testDb; + private MapStore testDb; @BeforeEach void setUp() throws Exception { diff --git a/src/test/java/neon/maps/RegionSerializationTest.java b/src/test/java/neon/maps/RegionSerializationTest.java index cf6517f..e474499 100644 --- a/src/test/java/neon/maps/RegionSerializationTest.java +++ b/src/test/java/neon/maps/RegionSerializationTest.java @@ -7,7 +7,7 @@ import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -20,7 +20,7 @@ */ class RegionSerializationTest { - private MVStore testDb; + private MapStore testDb; @BeforeEach void setUp() throws Exception { diff --git a/src/test/java/neon/maps/ZoneIntegrationTest.java b/src/test/java/neon/maps/ZoneIntegrationTest.java index a9fb4b3..b6c8151 100644 --- a/src/test/java/neon/maps/ZoneIntegrationTest.java +++ b/src/test/java/neon/maps/ZoneIntegrationTest.java @@ -6,7 +6,7 @@ import java.util.Collection; import neon.test.MapDbTestHelper; import neon.test.TestEngineContext; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -18,7 +18,7 @@ */ class ZoneIntegrationTest { - private MVStore testDb; + private MapStore testDb; @BeforeEach void setUp() throws Exception { diff --git a/src/test/java/neon/maps/ZoneSerializationTest.java b/src/test/java/neon/maps/ZoneSerializationTest.java index b249eb1..ad14579 100644 --- a/src/test/java/neon/maps/ZoneSerializationTest.java +++ b/src/test/java/neon/maps/ZoneSerializationTest.java @@ -8,7 +8,7 @@ import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -21,7 +21,7 @@ */ class ZoneSerializationTest { - private MVStore testDb; + private MapStore testDb; @BeforeEach void setUp() throws Exception { diff --git a/src/test/java/neon/maps/generators/DungeonGeneratorTest.java b/src/test/java/neon/maps/generators/DungeonGeneratorTest.java index cfff904..a846af7 100644 --- a/src/test/java/neon/maps/generators/DungeonGeneratorTest.java +++ b/src/test/java/neon/maps/generators/DungeonGeneratorTest.java @@ -20,7 +20,7 @@ import neon.test.MapDbTestHelper; import neon.test.TestEngineContext; import neon.util.Dice; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -594,7 +594,7 @@ private String visualizeTerrain(String[][] terrain) { @Nested class GenerateWithContextTests { - private MVStore testDb; + private MapStore testDb; private Atlas testAtlas; private ZoneFactory zoneFactory; private EntityStore entityStore; diff --git a/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java b/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java index 3956b9b..d85397b 100644 --- a/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java +++ b/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java @@ -16,7 +16,7 @@ import neon.test.MapDbTestHelper; import neon.test.TestEngineContext; import neon.util.Dice; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; @@ -319,7 +319,7 @@ private String visualizeTerrain(String[][] terrain) { @Nested class GenerateWithFullContextTests { - private MVStore testDb; + private MapStore testDb; private Atlas testAtlas; private EntityStore entityStore; private AtlasPosition testAtlasPosition; diff --git a/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java b/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java index d0a333b..696aefa 100644 --- a/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java +++ b/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java @@ -14,7 +14,7 @@ import neon.resources.RRegionTheme; import neon.test.MapDbTestHelper; import neon.test.TestEngineContext; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; @@ -109,7 +109,7 @@ static Stream townThemeProviderSingleSeed() { @Nested class GenerateWithFullContextTests { - private MVStore testDb; + private MapStore testDb; private Atlas testAtlas; private EntityStore entityStore; diff --git a/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java b/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java index b2a4ab7..a64b88d 100644 --- a/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java +++ b/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java @@ -15,7 +15,7 @@ import neon.test.MapDbTestHelper; import neon.test.TestEngineContext; import neon.util.Dice; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; @@ -154,7 +154,7 @@ void generateTerrain_isDeterministic(WildernessScenario scenario) { @Nested class GenerateWithFullContextTests { - private MVStore testDb; + private MapStore testDb; private Atlas testAtlas; private EntityStore entityStore; diff --git a/src/test/java/neon/test/MapDbTestHelper.java b/src/test/java/neon/test/MapDbTestHelper.java index 037bd84..3225f76 100644 --- a/src/test/java/neon/test/MapDbTestHelper.java +++ b/src/test/java/neon/test/MapDbTestHelper.java @@ -3,6 +3,8 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import neon.util.mapstorage.MapStore; +import neon.util.mapstorage.MapStoreMVStoreAdapter; import org.h2.mvstore.MVStore; /** @@ -15,15 +17,15 @@ public class MapDbTestHelper { /** Represents a test database with its associated file path (if file-backed). */ public static class TestDatabase { - private final MVStore db; + private final MapStore db; private final Path filePath; - public TestDatabase(MVStore db, Path filePath) { + public TestDatabase(MapStore db, Path filePath) { this.db = db; this.filePath = filePath; } - public MVStore getDb() { + public MapStore getDb() { return db; } @@ -43,8 +45,8 @@ public boolean isFileBacked() { * * @return an in-memory DB instance */ - public static MVStore createInMemoryDB() { - return MVStore.open(null); + public static MapStore createInMemoryDB() { + return new MapStoreMVStoreAdapter(MVStore.open(null)); } /** @@ -57,7 +59,7 @@ public static MVStore createInMemoryDB() { */ public static TestDatabase createTempFileDB() throws IOException { Path tempFile = Files.createTempFile("neon-test-db-", ".dat"); - MVStore db = MVStore.open(tempFile.toString()); + MapStore db = new MapStoreMVStoreAdapter(MVStore.open(tempFile.toString())); return new TestDatabase(db, tempFile); } @@ -71,7 +73,7 @@ public static TestDatabase createTempFileDB() throws IOException { */ public static TestDatabase createTempFileDB(String prefix) throws IOException { Path tempFile = Files.createTempFile(prefix, ".dat"); - MVStore db = MVStore.open(tempFile.toString()); + MapStore db = new MapStoreMVStoreAdapter(MVStore.open(tempFile.toString())); return new TestDatabase(db, tempFile); } @@ -82,7 +84,7 @@ public static TestDatabase createTempFileDB(String prefix) throws IOException { * * @param db the database to cleanup */ - public static void cleanup(MVStore db) { + public static void cleanup(MapStore db) { if (db != null && !db.isClosed()) { db.close(); } @@ -121,7 +123,7 @@ public static void cleanup(TestDatabase testDb) { * @param db the database to check * @throws IllegalStateException if the database is null or closed */ - public static void assertDbOpen(MVStore db) { + public static void assertDbOpen(MapStore db) { if (db == null) { throw new IllegalStateException("Database is null"); } @@ -137,7 +139,7 @@ public static void assertDbOpen(MVStore db) { * @param collectionName the name of the collection * @throws IllegalStateException if the collection doesn't exist */ - public static void assertCollectionExists(MVStore db, String collectionName) { + public static void assertCollectionExists(MapStore db, String collectionName) { assertDbOpen(db); if (!db.getMapNames().contains(collectionName)) { throw new IllegalStateException("Collection '" + collectionName + "' does not exist"); @@ -151,7 +153,7 @@ public static void assertCollectionExists(MVStore db, String collectionName) { * @param collectionName the name of the collection * @return the number of entries, or -1 if collection doesn't exist */ - public static int getCollectionSize(MVStore db, String collectionName) { + public static int getCollectionSize(MapStore db, String collectionName) { var map = db.openMap(collectionName); return map.size(); } @@ -161,7 +163,7 @@ public static int getCollectionSize(MVStore db, String collectionName) { * * @param db the database to commit */ - public static void commit(MVStore db) { + public static void commit(MapStore db) { if (db != null && !db.isClosed()) { db.commit(); } diff --git a/src/test/java/neon/test/TestEngineContext.java b/src/test/java/neon/test/TestEngineContext.java index 0e22d25..66ec314 100644 --- a/src/test/java/neon/test/TestEngineContext.java +++ b/src/test/java/neon/test/TestEngineContext.java @@ -14,16 +14,14 @@ import neon.entities.UIDStore; import neon.entities.components.PhysicsComponent; import neon.entities.property.Gender; -import neon.maps.Atlas; -import neon.maps.AtlasPosition; -import neon.maps.ZoneActivator; -import neon.maps.ZoneFactory; +import neon.maps.*; import neon.maps.services.*; import neon.narrative.QuestTracker; import neon.resources.*; import neon.resources.builder.IniBuilder; import neon.systems.files.FileSystem; import neon.systems.physics.PhysicsSystem; +import neon.util.mapstorage.MapStore; import org.h2.mvstore.MVStore; import org.jdom2.Document; import org.jdom2.Element; @@ -38,7 +36,7 @@ @Slf4j public class TestEngineContext { - private static MVStore testDb; + private static MapStore testDb; /** -- GETTER -- Gets the test Atlas instance. */ @Getter private static Atlas testAtlas; @@ -61,7 +59,7 @@ public class TestEngineContext { @Getter private static StubFileSystem stubFileSystem; @Getter private static neon.core.DefaultGameContext testContext; - + @Getter private static MapLoader mapLoader; @Getter private static QuestTracker questTracker; static { @@ -90,7 +88,7 @@ public class TestEngineContext { * @param db the MapDb database to use for Atlas * @throws RuntimeException if reflection fails */ - public static void initialize(MVStore db) throws Exception { + public static void initialize(MapStore db) throws Exception { testDb = db; // Create stub ResourceManager @@ -110,13 +108,14 @@ public static void initialize(MVStore db) throws Exception { // Create ZoneFactory for tests testZoneFactory = new ZoneFactory(db); - + mapLoader = new MapLoader(testEntityStore, testResources, getStubFileSystem()); // Create test Atlas with dependency injection (doesn't need Engine.game) - testAtlas = new Atlas(getStubFileSystem(), "test-atlas", testEntityStore); + testAtlas = new Atlas(getStubFileSystem(), "test-atlas", getTestEntityStore(), mapLoader); atlasPosition = new AtlasPosition( testAtlas, testZoneActivator, testResources, questTracker, testEntityStore); // Create test Game using new DI constructor + testGame = new Game(stubPlayer, testAtlas, testStore, atlasPosition); setStaticField(Engine.class, "game", testGame); diff --git a/src/test/java/neon/util/spatial/RTreePersistenceTest.java b/src/test/java/neon/util/spatial/RTreePersistenceTest.java index 5c9dc71..4dbb767 100644 --- a/src/test/java/neon/util/spatial/RTreePersistenceTest.java +++ b/src/test/java/neon/util/spatial/RTreePersistenceTest.java @@ -8,7 +8,7 @@ import java.util.ArrayList; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; -import org.h2.mvstore.MVStore; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -21,7 +21,7 @@ */ class RTreePersistenceTest { - private MVStore testDb; + private MapStore testDb; @BeforeEach void setUp() { From 4c239013aad88049f29e45ec07c37de9b36e76b2 Mon Sep 17 00:00:00 2001 From: Peter Riewe Date: Sat, 10 Jan 2026 22:16:34 -0500 Subject: [PATCH 03/12] Use more in-memory db for unit tests --- src/main/java/neon/entities/UIDStore.java | 6 + src/main/java/neon/maps/Atlas.java | 13 ++ src/test/java/neon/maps/AtlasTest.java | 7 +- src/test/java/neon/test/MapDbTestHelper.java | 130 +----------------- .../java/neon/test/TestEngineContext.java | 4 +- 5 files changed, 24 insertions(+), 136 deletions(-) diff --git a/src/main/java/neon/entities/UIDStore.java b/src/main/java/neon/entities/UIDStore.java index 6aecb7a..b30ff46 100644 --- a/src/main/java/neon/entities/UIDStore.java +++ b/src/main/java/neon/entities/UIDStore.java @@ -60,6 +60,12 @@ public UIDStore(String file) { mods = uidDb.openMap("mods"); } + public UIDStore(MapStore mapStore) { + uidDb = mapStore; + objects = uidDb.openMap("object"); + mods = uidDb.openMap("mods"); + } + /** * @return the jdbm3 cache used by this UIDStore */ diff --git a/src/main/java/neon/maps/Atlas.java b/src/main/java/neon/maps/Atlas.java index 5c9fcb8..785a83c 100644 --- a/src/main/java/neon/maps/Atlas.java +++ b/src/main/java/neon/maps/Atlas.java @@ -42,6 +42,19 @@ public class Atlas implements Closeable, MapAtlas { private final FileSystem fileSystem; private final MapLoader mapLoader; + public Atlas( + FileSystem fileSystem, MapStore mapStore, EntityStore entityStore, MapLoader mapLoader) { + this.fileSystem = fileSystem; + this.entityStore = entityStore; + this.db = mapStore; + // files.delete(path); + // String fileName = files.getFullPath(path); + // log.warn("Creating new MVStore at {}", fileName); + this.mapLoader = mapLoader; + // db = MVStore.open(fileName); + maps = db.openMap("maps"); + } + /** Initializes this {@code Atlas} with dependency injection. */ public Atlas(FileSystem fileSystem, String path, EntityStore entityStore, MapLoader mapLoader) { this.fileSystem = fileSystem; diff --git a/src/test/java/neon/maps/AtlasTest.java b/src/test/java/neon/maps/AtlasTest.java index 471ae9c..9972ec2 100644 --- a/src/test/java/neon/maps/AtlasTest.java +++ b/src/test/java/neon/maps/AtlasTest.java @@ -27,12 +27,7 @@ class AtlasTest { void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); - atlas = - new Atlas( - TestEngineContext.getStubFileSystem(), - "atlas-test", - TestEngineContext.getTestEntityStore(), - TestEngineContext.getMapLoader()); + atlas = TestEngineContext.getTestAtlas(); atlasPosition = new AtlasPosition( atlas, diff --git a/src/test/java/neon/test/MapDbTestHelper.java b/src/test/java/neon/test/MapDbTestHelper.java index 3225f76..d640df1 100644 --- a/src/test/java/neon/test/MapDbTestHelper.java +++ b/src/test/java/neon/test/MapDbTestHelper.java @@ -1,8 +1,5 @@ package neon.test; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import neon.util.mapstorage.MapStore; import neon.util.mapstorage.MapStoreMVStoreAdapter; import org.h2.mvstore.MVStore; @@ -17,25 +14,9 @@ public class MapDbTestHelper { /** Represents a test database with its associated file path (if file-backed). */ public static class TestDatabase { - private final MapStore db; - private final Path filePath; - public TestDatabase(MapStore db, Path filePath) { - this.db = db; - this.filePath = filePath; - } - - public MapStore getDb() { - return db; - } - - public Path getFilePath() { - return filePath; - } - - public boolean isFileBacked() { - return filePath != null; - } + private TestDatabase() {} + ; } /** @@ -49,34 +30,6 @@ public static MapStore createInMemoryDB() { return new MapStoreMVStoreAdapter(MVStore.open(null)); } - /** - * Creates a temporary file-backed MapDb database for testing. - * - *

Tests real persistence behavior. The file is created in the system temp directory. - * - * @return a TestDatabase instance with both DB and file path - * @throws IOException if temp file creation fails - */ - public static TestDatabase createTempFileDB() throws IOException { - Path tempFile = Files.createTempFile("neon-test-db-", ".dat"); - MapStore db = new MapStoreMVStoreAdapter(MVStore.open(tempFile.toString())); - - return new TestDatabase(db, tempFile); - } - - /** - * Creates a temporary file-backed MapDb database with a specific name prefix. - * - * @param prefix the prefix for the temp file name - * @return a TestDatabase instance with both DB and file path - * @throws IOException if temp file creation fails - */ - public static TestDatabase createTempFileDB(String prefix) throws IOException { - Path tempFile = Files.createTempFile(prefix, ".dat"); - MapStore db = new MapStoreMVStoreAdapter(MVStore.open(tempFile.toString())); - return new TestDatabase(db, tempFile); - } - /** * Cleans up an in-memory database. * @@ -89,83 +42,4 @@ public static void cleanup(MapStore db) { db.close(); } } - - /** - * Cleans up a test database and deletes its backing file if present. - * - *

Closes the database, deletes the file, and releases all resources. - * - * @param testDb the test database to cleanup - */ - public static void cleanup(TestDatabase testDb) { - if (testDb == null) { - return; - } - - // Close database - if (testDb.db != null && !testDb.db.isClosed()) { - testDb.db.close(); - } - - // Delete backing file if it exists - if (testDb.filePath != null) { - try { - Files.deleteIfExists(testDb.filePath); - } catch (IOException e) { - System.err.println("Warning: Failed to delete test database file: " + e.getMessage()); - } - } - } - - /** - * Asserts that a database is open and ready for use. - * - * @param db the database to check - * @throws IllegalStateException if the database is null or closed - */ - public static void assertDbOpen(MapStore db) { - if (db == null) { - throw new IllegalStateException("Database is null"); - } - if (db.isClosed()) { - throw new IllegalStateException("Database is closed"); - } - } - - /** - * Asserts that a named collection exists in the database. - * - * @param db the database to check - * @param collectionName the name of the collection - * @throws IllegalStateException if the collection doesn't exist - */ - public static void assertCollectionExists(MapStore db, String collectionName) { - assertDbOpen(db); - if (!db.getMapNames().contains(collectionName)) { - throw new IllegalStateException("Collection '" + collectionName + "' does not exist"); - } - } - - /** - * Gets the number of entries in a named collection. - * - * @param db the database - * @param collectionName the name of the collection - * @return the number of entries, or -1 if collection doesn't exist - */ - public static int getCollectionSize(MapStore db, String collectionName) { - var map = db.openMap(collectionName); - return map.size(); - } - - /** - * Commits all pending changes to the database. - * - * @param db the database to commit - */ - public static void commit(MapStore db) { - if (db != null && !db.isClosed()) { - db.commit(); - } - } } diff --git a/src/test/java/neon/test/TestEngineContext.java b/src/test/java/neon/test/TestEngineContext.java index 66ec314..f239b5b 100644 --- a/src/test/java/neon/test/TestEngineContext.java +++ b/src/test/java/neon/test/TestEngineContext.java @@ -96,7 +96,7 @@ public static void initialize(MapStore db) throws Exception { setStaticField(Engine.class, "resources", testResources); // Create test UIDStore - testStore = new UIDStore("test-store.dat"); + testStore = new UIDStore(testDb); questTracker = new QuestTracker(); // Create test EntityStore testEntityStore = new StubEntityStore(testStore); @@ -110,7 +110,7 @@ public static void initialize(MapStore db) throws Exception { testZoneFactory = new ZoneFactory(db); mapLoader = new MapLoader(testEntityStore, testResources, getStubFileSystem()); // Create test Atlas with dependency injection (doesn't need Engine.game) - testAtlas = new Atlas(getStubFileSystem(), "test-atlas", getTestEntityStore(), mapLoader); + testAtlas = new Atlas(getStubFileSystem(), testDb, getTestEntityStore(), mapLoader); atlasPosition = new AtlasPosition( testAtlas, testZoneActivator, testResources, questTracker, testEntityStore); From 5a20d614280e5a9930d28116ca067911ce700549 Mon Sep 17 00:00:00 2001 From: Peter Riewe Date: Mon, 12 Jan 2026 08:53:35 -0500 Subject: [PATCH 04/12] In progress refactoring - does not compile! --- src/main/java/neon/Main.java | 4 +- src/main/java/neon/ai/AI.java | 97 ++++--- src/main/java/neon/ai/GuardAI.java | 12 +- src/main/java/neon/ai/PathFinder.java | 42 +-- .../java/neon/core/DefaultGameContext.java | 27 +- .../java/neon/core/DefaultGameStores.java | 42 +++ src/main/java/neon/core/Engine.java | 63 +---- src/main/java/neon/core/Game.java | 33 +-- src/main/java/neon/core/GameContext.java | 17 -- src/main/java/neon/core/GameLoader.java | 84 +++--- src/main/java/neon/core/GameSaver.java | 8 +- src/main/java/neon/core/GameStores.java | 19 ++ src/main/java/neon/core/ScriptInterface.java | 22 +- .../neon/core/handlers/CombatHandler.java | 40 ++- .../java/neon/core/handlers/CombatUtils.java | 40 +-- .../java/neon/core/handlers/DeathHandler.java | 9 +- .../neon/core/handlers/InventoryHandler.java | 47 ++-- .../java/neon/core/handlers/MagicHandler.java | 74 ++--- .../neon/core/handlers/MotionHandler.java | 71 ++--- .../java/neon/core/handlers/TurnHandler.java | 33 ++- src/main/java/neon/editor/DataStore.java | 179 +++++------- src/main/java/neon/editor/Editor.java | 9 +- src/main/java/neon/editor/maps/MapEditor.java | 14 +- .../java/neon/editor/resources/Instance.java | 4 +- src/main/java/neon/editor/resources/RMap.java | 12 +- .../java/neon/entities/EntityFactory.java | 123 ++++----- src/main/java/neon/entities/Player.java | 17 +- .../java/neon/entities/components/Portal.java | 40 +-- .../serialization/CreatureSerializer.java | 43 ++- .../serialization/EntitySerializer.java | 26 +- .../serialization/ItemSerializer.java | 17 +- src/main/java/neon/magic/SpellFactory.java | 22 +- src/main/java/neon/maps/Atlas.java | 4 +- src/main/java/neon/maps/AtlasPosition.java | 17 +- src/main/java/neon/maps/Dungeon.java | 24 +- src/main/java/neon/maps/MapLoader.java | 211 +++++++------- src/main/java/neon/maps/Region.java | 35 ++- src/main/java/neon/maps/World.java | 17 +- src/main/java/neon/maps/Zone.java | 261 +++++++----------- src/main/java/neon/maps/ZoneFactory.java | 39 ++- .../maps/generators/DungeonGenerator.java | 49 ++-- .../neon/maps/generators/TownGenerator.java | 19 +- .../maps/generators/WildernessGenerator.java | 33 ++- .../neon/maps/services/EngineEntityStore.java | 55 ---- .../maps/services/EngineResourceProvider.java | 40 --- .../maps/services/GameContextEntityStore.java | 61 ---- .../services/GameContextResourceProvider.java | 46 --- .../java/neon/narrative/QuestTracker.java | 10 +- src/main/java/neon/narrative/Resolver.java | 155 +++++------ src/main/java/neon/ui/Client.java | 27 +- src/main/java/neon/ui/GamePanel.java | 10 +- .../java/neon/ui/dialog/ChargeDialog.java | 4 +- .../java/neon/ui/dialog/CrafterDialog.java | 22 +- .../java/neon/ui/dialog/EnchantDialog.java | 7 +- .../java/neon/ui/dialog/NewGameDialog.java | 14 +- .../java/neon/ui/dialog/OptionDialog.java | 9 +- .../java/neon/ui/dialog/PotionDialog.java | 27 +- .../java/neon/ui/dialog/RepairDialog.java | 10 +- .../java/neon/ui/dialog/TattooDialog.java | 10 +- src/main/java/neon/ui/dialog/TradeDialog.java | 17 +- .../java/neon/ui/dialog/TrainingDialog.java | 10 +- .../java/neon/ui/dialog/TravelDialog.java | 11 +- src/main/java/neon/ui/states/AimState.java | 30 +- src/main/java/neon/ui/states/BumpState.java | 13 +- .../java/neon/ui/states/ContainerState.java | 31 ++- src/main/java/neon/ui/states/DialogState.java | 30 +- src/main/java/neon/ui/states/DoorState.java | 12 +- src/main/java/neon/ui/states/GameState.java | 22 +- .../java/neon/ui/states/InventoryState.java | 40 ++- .../java/neon/ui/states/JournalState.java | 20 +- .../java/neon/ui/states/MainMenuState.java | 13 +- src/main/java/neon/ui/states/MoveState.java | 28 +- src/main/java/neon/util/Graph.java | 9 +- .../java/neon/maps/AtlasIntegrationTest.java | 7 +- .../TownGeneratorIntegrationTest.java | 7 +- .../java/neon/test/TestEngineContext.java | 117 ++------ 76 files changed, 1315 insertions(+), 1608 deletions(-) create mode 100644 src/main/java/neon/core/DefaultGameStores.java create mode 100644 src/main/java/neon/core/GameStores.java delete mode 100644 src/main/java/neon/maps/services/EngineEntityStore.java delete mode 100644 src/main/java/neon/maps/services/EngineResourceProvider.java delete mode 100644 src/main/java/neon/maps/services/GameContextEntityStore.java delete mode 100644 src/main/java/neon/maps/services/GameContextResourceProvider.java diff --git a/src/main/java/neon/Main.java b/src/main/java/neon/Main.java index a00e1ea..7c25678 100644 --- a/src/main/java/neon/Main.java +++ b/src/main/java/neon/Main.java @@ -21,6 +21,7 @@ import java.io.IOException; import neon.core.Engine; import neon.core.GameContext; +import neon.core.GameStores; import neon.systems.io.LocalPort; import neon.ui.Client; @@ -48,7 +49,8 @@ public static void main(String[] args) throws IOException { // create engine and ui Engine engine = new Engine(sPort); GameContext context = engine.getContext(); - Client client = new Client(cPort, version, context); + GameStores gameStores = engine.getGameStores(); + Client client = new Client(cPort, version, context, gameStores); // custom look and feels are sometimes stricter than normal ones, apparently // the main problem is that parts of the ui are created outside the swing thread. diff --git a/src/main/java/neon/ai/AI.java b/src/main/java/neon/ai/AI.java index 8af6c75..2ded80f 100644 --- a/src/main/java/neon/ai/AI.java +++ b/src/main/java/neon/ai/AI.java @@ -22,7 +22,10 @@ import java.awt.Rectangle; import java.io.Serializable; import java.util.HashMap; +import lombok.Getter; import neon.core.Engine; +import neon.core.GameContext; +import neon.core.GameStores; import neon.core.event.CombatEvent; import neon.core.event.MagicEvent; import neon.core.handlers.*; @@ -46,11 +49,28 @@ * @author mdriesen */ public abstract class AI implements Serializable { - protected byte aggression; - protected byte confidence; + /** + * -- GETTER -- + * + * @return the aggression of the creature with this AI + */ + @Getter protected byte aggression; + + /** + * -- GETTER -- + * + * @return the confidence of the creature with this AI + */ + @Getter protected byte confidence; + protected Creature creature; protected HashMap dispositions = new HashMap(); - + protected final GameStores gameStores; + protected final InventoryHandler inventoryHandler; + protected final MotionHandler motionHandler; + protected final PathFinder pathFinder; + protected final CombatUtils combatUtils; + protected final GameContext gameContext; /** * Initializes a new AI. * @@ -58,10 +78,17 @@ public abstract class AI implements Serializable { * @param aggression * @param confidence */ - public AI(Creature creature, byte aggression, byte confidence) { + public AI(Creature creature, byte aggression, byte confidence, GameStores gameStores, GameContext gameContext) { this.aggression = aggression; this.confidence = confidence; this.creature = creature; + this.gameStores = gameStores; + this.gameContext = gameContext; + + inventoryHandler = new InventoryHandler(gameStores.getStore()); + motionHandler = new MotionHandler(gameContext,gameStores); + pathFinder = new PathFinder(gameStores); + combatUtils = new CombatUtils(gameStores.getStore()); } /** Lets the creature with this AI act. */ @@ -121,20 +148,6 @@ public void makeHostile(Creature other) { aggression = (byte) (getDisposition(other) + 10); } - /** - * @return the aggression of the creature with this AI - */ - public byte getAggression() { - return aggression; - } - - /** - * @return the confidence of the creature with this AI - */ - public byte getConfidence() { - return confidence; - } - /** * Checks if this creature can see another one. * @@ -173,13 +186,13 @@ public boolean sees(Point p) { protected boolean heal() { // first check potions and scrolls? for (long uid : creature.getInventoryComponent()) { - Item item = (Item) Engine.getStore().getEntity(uid); + Item item = (Item) gameStores.getStore().getEntity(uid); if (item instanceof Item.Scroll || item instanceof Item.Potion) { RSpell formula = item.getMagicComponent().getSpell(); if (formula.effect.equals(Effect.RESTORE_HEALTH) && formula.range == 0) { Engine.post(new MagicEvent.ItemOnSelf(this, creature, item)); - InventoryHandler.removeItem(creature, item.getUID()); + inventoryHandler.removeItem(creature, item.getUID()); return true; } } @@ -226,12 +239,12 @@ protected boolean cure() { private boolean cure(Effect effect) { // first check potions and scrolls? for (long uid : creature.getInventoryComponent()) { - Item item = (Item) Engine.getStore().getEntity(uid); + Item item = (Item) gameStores.getStore().getEntity(uid); if (item instanceof Item.Scroll || item instanceof Item.Potion) { RSpell formula = item.getMagicComponent().getSpell(); if (formula.effect.equals(effect) && formula.range == 0) { Engine.post(new MagicEvent.ItemOnSelf(this, creature, item)); - InventoryHandler.removeItem(creature, item.getUID()); + inventoryHandler.removeItem(creature, item.getUID()); return true; } } @@ -259,26 +272,26 @@ private boolean cure(Effect effect) { */ private boolean equip(Slot slot) { for (long uid : creature.getInventoryComponent()) { - Item item = (Item) Engine.getStore().getEntity(uid); + Item item = (Item) gameStores.getStore().getEntity(uid); if (item instanceof Weapon && slot.equals(((Weapon) item).getSlot())) { WeaponType type = ((Weapon) item).getWeaponType(); - InventoryHandler.equip(item, creature); + inventoryHandler.equip(item, creature); if ((type.equals(WeaponType.BOW) || type.equals(WeaponType.CROSSBOW)) && !equip(Slot.AMMO)) { continue; } else if (type.equals(WeaponType.ARROW) - && !CombatUtils.getWeaponType(creature).equals(WeaponType.BOW)) { + && !combatUtils.getWeaponType(creature).equals(WeaponType.BOW)) { continue; } else if (type.equals(WeaponType.BOLT) - && !CombatUtils.getWeaponType(creature).equals(WeaponType.CROSSBOW)) { + && !combatUtils.getWeaponType(creature).equals(WeaponType.CROSSBOW)) { continue; } return true; } else if (item instanceof Clothing && slot.equals(((Clothing) item).getSlot())) { - InventoryHandler.equip(item, creature); + inventoryHandler.equip(item, creature); return true; } else if (item instanceof Item.Scroll && slot.equals(Slot.MAGIC)) { - InventoryHandler.equip(item, creature); + inventoryHandler.equip(item, creature); return true; } } @@ -307,7 +320,7 @@ protected void flee(Creature hunter) { Point p = new Point(cBounds.x + dx, cBounds.y + dy); if (Engine.getAtlasPosition().getCurrentZone().getCreature(p) == null) { - byte result = MotionHandler.move(creature, p); + byte result = motionHandler.move(creature, p); if (result == MotionHandler.BLOCKED) { // try a random direction once (or multiple times?) wander(); @@ -323,8 +336,8 @@ protected void flee(Creature hunter) { private boolean open(Point p) { Door door = null; for (long uid : Engine.getAtlasPosition().getCurrentZone().getItems(p)) { - if (Engine.getStore().getEntity(uid) instanceof Door) { - door = (Door) Engine.getStore().getEntity(uid); + if (gameStores.getStore().getEntity(uid) instanceof Door) { + door = (Door) gameStores.getStore().getEntity(uid); } } if (door != null) { @@ -351,7 +364,7 @@ protected void hunt(int range, Point home, Creature prey) { hunt(prey); // if too far from home, return if (home.distance(bounds.getLocation()) > range) { - MotionHandler.move(creature, bounds.getLocation()); + motionHandler.move(creature, bounds.getLocation()); } } @@ -367,7 +380,7 @@ protected void wander(int range, Point home) { // if too far from home, return double newDistance = home.distance(bounds.getLocation()); if (newDistance > range && newDistance > oldDistance) { - MotionHandler.move(creature, bounds.getLocation()); + motionHandler.move(creature, bounds.getLocation()); } } @@ -384,7 +397,7 @@ protected void wander() { Point player = pBounds.getLocation(); if (Engine.getAtlasPosition().getCurrentZone().getCreature(p) == null && !player.equals(p)) { - MotionHandler.move(creature, p); + motionHandler.move(creature, p); } } @@ -396,10 +409,10 @@ protected void wander(Point destination) { Rectangle cBounds = creature.getShapeComponent(); Point player = pBounds.getLocation(); - Point next = PathFinder.findPath(creature, cBounds.getLocation(), destination)[0]; + Point next = pathFinder.findPath(creature, cBounds.getLocation(), destination)[0]; if (Engine.getAtlasPosition().getCurrentZone().getCreature(next) == null && !player.equals(next)) { - MotionHandler.move(creature, next); + motionHandler.move(creature, next); } } @@ -453,22 +466,22 @@ protected void hunt(Creature prey) { } else { // if creature is smarter, try A* Rectangle cBounds = creature.getShapeComponent(); Rectangle pBounds = prey.getShapeComponent(); - p = PathFinder.findPath(creature, cBounds.getLocation(), pBounds.getLocation())[0]; + p = pathFinder.findPath(creature, cBounds.getLocation(), pBounds.getLocation())[0]; } if (p.distance(preyPos.x, preyPos.y) < 1) { long uid = creature.getInventoryComponent().get(Slot.WEAPON); - Weapon weapon = (Weapon) Engine.getStore().getEntity(uid); + Weapon weapon = (Weapon) gameStores.getStore().getEntity(uid); if (creature.getInventoryComponent().hasEquiped(Slot.WEAPON) && weapon.isRanged()) { - if (!(CombatUtils.getWeaponType(creature).equals(WeaponType.THROWN) || equip(Slot.AMMO))) { - InventoryHandler.unequip(weapon.getUID(), creature); + if (!(combatUtils.getWeaponType(creature).equals(WeaponType.THROWN) || equip(Slot.AMMO))) { + inventoryHandler.unequip(weapon.getUID(), creature); } } else if (!creature.getInventoryComponent().hasEquiped(Slot.WEAPON)) { equip(Slot.WEAPON); } Engine.post(new CombatEvent(creature, prey)); } else if (Engine.getAtlasPosition().getCurrentZone().getCreature(p) == null) { - if (MotionHandler.move(creature, p) == MotionHandler.DOOR) { + if (motionHandler.move(creature, p) == MotionHandler.DOOR) { open(p); // open door if necessary } } else { // if another creature is in the way @@ -478,7 +491,7 @@ protected void hunt(Creature prey) { private boolean hasItem(Creature creature, RItem item) { for (long uid : creature.getInventoryComponent()) { - if (Engine.getStore().getEntity(uid).getID().equals(item.id)) { + if (gameStores.getStore().getEntity(uid).getID().equals(item.id)) { return true; } } diff --git a/src/main/java/neon/ai/GuardAI.java b/src/main/java/neon/ai/GuardAI.java index 6186d3b..0ec849a 100644 --- a/src/main/java/neon/ai/GuardAI.java +++ b/src/main/java/neon/ai/GuardAI.java @@ -20,6 +20,8 @@ import java.awt.Point; import neon.core.Engine; +import neon.core.GameContext; +import neon.core.GameStores; import neon.entities.Creature; import neon.entities.components.HealthComponent; import neon.entities.components.ShapeComponent; @@ -28,8 +30,8 @@ public class GuardAI extends AI { private int range; private Point home; - public GuardAI(Creature creature, byte aggression, byte confidence, int range) { - super(creature, aggression, confidence); + public GuardAI(Creature creature, byte aggression, byte confidence, int range, GameStores gameStores, GameContext gameContext) { + super(creature, aggression, confidence,gameStores,gameContext); this.range = range; ShapeComponent bounds = creature.getShapeComponent(); home = new Point(bounds.x, bounds.y); @@ -38,16 +40,16 @@ public GuardAI(Creature creature, byte aggression, byte confidence, int range) { public void act() { // TODO: not only pay attention to player, but also to other creatures in sight ShapeComponent cBounds = creature.getShapeComponent(); - ShapeComponent pBounds = Engine.getPlayer().getShapeComponent(); + ShapeComponent pBounds = gameContext.getPlayer().getShapeComponent(); if (isHostile() && cBounds.getLocation().distance(pBounds.getLocation()) < range) { HealthComponent health = creature.getHealthComponent(); if (100 * health.getHealth() / health.getBaseHealth() < confidence / 100) { // 80% chance to just flee, 20% chance to heal; if no heal spell, flee anyway if (Math.random() > 0.2 || !(cure() || heal())) { - flee(Engine.getPlayer()); + flee(gameContext.getPlayer()); } } else { - hunt(range, home, Engine.getPlayer()); + hunt(range, home, gameContext.getPlayer()); } } else { wander(range, home); diff --git a/src/main/java/neon/ai/PathFinder.java b/src/main/java/neon/ai/PathFinder.java index ce9bc2d..b61d387 100644 --- a/src/main/java/neon/ai/PathFinder.java +++ b/src/main/java/neon/ai/PathFinder.java @@ -26,6 +26,7 @@ import java.util.PriorityQueue; import java.util.Queue; import neon.core.Engine; +import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Door; import neon.entities.property.Skill; @@ -37,7 +38,13 @@ public class PathFinder { private static Point to; private static Creature mover; - public static Point[] findPath(Creature creature, Point origin, Point destination) { + private final GameStores gameStores; + + public PathFinder(GameStores gameStores) { + this.gameStores = gameStores; + } + + public Point[] findPath(Creature creature, Point origin, Point destination) { // points Point from = origin; to = destination; @@ -97,10 +104,10 @@ public static Point[] findPath(Creature creature, Point origin, Point destinatio to = todo.poll(); // if path was interrupted, continue with current estimate } // this can sometimes give strange behavior while (!from.equals(to)) { - path.add(0, to); + path.addFirst(to); to = links.get(to); } - return path.toArray(new Point[path.size()]); + return path.toArray(new Point[0]); } private static Point[] neighbours(Point current) { @@ -119,26 +126,23 @@ private static Point[] neighbours(Point current) { /* * manhattan distance between points */ - private static int manhattan(Point one, Point two) { + private int manhattan(Point one, Point two) { return Math.abs(one.x - two.x) + Math.abs(one.y - two.y); } - private static int terrainPenalty(Point neighbour) { + private int terrainPenalty(Point neighbour) { // better modifiers? - switch (Engine.getAtlasPosition().getCurrentZone().getRegion(neighbour).getMovMod()) { - case SWIM: - return (100 - mover.getSkill(Skill.SWIMMING)) / 5; - case CLIMB: - return (100 - mover.getSkill(Skill.CLIMBING)) / 5; - default: - return 0; - } + return switch (Engine.getAtlasPosition().getCurrentZone().getRegion(neighbour).getMovMod()) { + case SWIM -> (100 - mover.getSkill(Skill.SWIMMING)) / 5; + case CLIMB -> (100 - mover.getSkill(Skill.CLIMBING)) / 5; + default -> 0; + }; } - private static int doorPenalty(Point neighbour) { + private int doorPenalty(Point neighbour) { for (long uid : Engine.getAtlasPosition().getCurrentZone().getItems(neighbour)) { - if (Engine.getStore().getEntity(uid) instanceof Door) { - Door door = (Door) Engine.getStore().getEntity(uid); + if (gameStores.getStore().getEntity(uid) instanceof Door) { + Door door = (Door) gameStores.getStore().getEntity(uid); if (door.lock.isLocked()) { RItem key = door.lock.getKey(); if (key != null && hasItem(mover, key)) { @@ -155,15 +159,15 @@ private static int doorPenalty(Point neighbour) { } @SuppressWarnings("serial") - private static class NodeComparator implements Comparator, Serializable { + private class NodeComparator implements Comparator, Serializable { public int compare(Point one, Point two) { return (evaluated.get(one) + manhattan(one, to)) - (evaluated.get(two) + manhattan(two, to)); } } - private static boolean hasItem(Creature creature, RItem item) { + private boolean hasItem(Creature creature, RItem item) { for (long uid : creature.getInventoryComponent()) { - if (Engine.getStore().getEntity(uid).getID().equals(item.id)) { + if (gameStores.getStore().getEntity(uid).getID().equals(item.id)) { return true; } } diff --git a/src/main/java/neon/core/DefaultGameContext.java b/src/main/java/neon/core/DefaultGameContext.java index d0a7fa8..64d387a 100644 --- a/src/main/java/neon/core/DefaultGameContext.java +++ b/src/main/java/neon/core/DefaultGameContext.java @@ -22,13 +22,9 @@ import lombok.Setter; import neon.core.event.TaskQueue; import neon.entities.Player; -import neon.entities.UIDStore; -import neon.maps.Atlas; import neon.maps.AtlasPosition; import neon.maps.services.PhysicsManager; import neon.narrative.QuestTracker; -import neon.resources.ResourceManager; -import neon.systems.files.FileSystem; import neon.systems.physics.PhysicsSystem; import neon.systems.timing.Timer; import net.engio.mbassy.bus.MBassador; @@ -47,13 +43,12 @@ public class DefaultGameContext implements GameContext { // Engine-level systems (set during engine initialization) - @Setter private ResourceManager resources; @Setter private QuestTracker questTracker; @Setter private PhysicsSystem physicsEngine; @Setter private PhysicsManager physicsManager; @Setter private Context scriptEngine; @Setter private MBassador bus; - @Setter private FileSystem fileSystem; + @Setter private GameStores gamesStores; @Setter private TaskQueue queue; @Setter private Engine engine; @@ -65,31 +60,16 @@ public Player getPlayer() { return game != null ? game.getPlayer() : null; } - @Override - public Atlas getAtlas() { - return game != null ? game.getAtlas() : null; - } - @Override public AtlasPosition getAtlasPosition() { return game != null ? game.getAtlasPosition() : null; } - @Override - public UIDStore getStore() { - return game != null ? game.getStore() : null; - } - @Override public Timer getTimer() { return game != null ? game.getTimer() : null; } - @Override - public ResourceManager getResources() { - return resources; - } - @Override public QuestTracker getQuestTracker() { return questTracker; @@ -130,11 +110,6 @@ public void post(EventObject event) { bus.publishAsync(event); } - @Override - public FileSystem getFileSystem() { - return fileSystem; - } - @Override public TaskQueue getQueue() { return queue; diff --git a/src/main/java/neon/core/DefaultGameStores.java b/src/main/java/neon/core/DefaultGameStores.java new file mode 100644 index 0000000..072ff73 --- /dev/null +++ b/src/main/java/neon/core/DefaultGameStores.java @@ -0,0 +1,42 @@ +package neon.core; + +import lombok.Getter; +import neon.entities.UIDStore; +import neon.maps.Atlas; +import neon.maps.MapLoader; +import neon.maps.ZoneFactory; +import neon.resources.ResourceManager; +import neon.systems.files.FileSystem; +import neon.util.mapstorage.MapStore; +import org.h2.mvstore.MVStore; + +@Getter +public class DefaultGameStores implements GameStores { + + private final ResourceManager resources; + private final FileSystem fileSystem; + private final UIDStore store; + private final Atlas atlas; + private final ZoneFactory zoneFactory; + + public DefaultGameStores(ResourceManager resources, FileSystem fileSystem) { + this.resources = resources; + this.fileSystem = fileSystem; + this.store = new UIDStore(fileSystem.getFullPath("uidstore")); + MapStore mapStore = Atlas.getMapStore(fileSystem,"zones"); + this.zoneFactory = new ZoneFactory(mapStore,store,resources); + MapLoader mapLoader = new MapLoader(fileSystem, store, resources,zoneFactory); + this.atlas = new Atlas(fileSystem, fileSystem.getFullPath("atlas"), store, mapLoader); + } + + public DefaultGameStores( + ResourceManager resources, FileSystem fileSystem, UIDStore store, Atlas atlas) { + this.resources = resources; + this.fileSystem = fileSystem; + this.store = store; + this.atlas = atlas; + MapStore mapStore = Atlas.getMapStore(fileSystem,"zones"); + this.zoneFactory = new ZoneFactory(mapStore,store,resources); + + } +} diff --git a/src/main/java/neon/core/Engine.java b/src/main/java/neon/core/Engine.java index c1cc5fc..c481b7b 100644 --- a/src/main/java/neon/core/Engine.java +++ b/src/main/java/neon/core/Engine.java @@ -29,8 +29,6 @@ import neon.core.handlers.InventoryHandler; import neon.core.handlers.MagicHandler; import neon.entities.Player; -import neon.entities.UIDStore; -import neon.maps.Atlas; import neon.maps.AtlasPosition; import neon.maps.services.EnginePhysicsManager; import neon.maps.services.PhysicsManager; @@ -72,7 +70,7 @@ public class Engine implements Runnable { private static TaskQueue queue; private final Configuration config; - + private static GameStores gameStores; // set externally private static Game game; @@ -102,26 +100,28 @@ public Engine(Port port) throws IOException { .build(); files = new FileSystem(); + resources = new ResourceManager(); + gameStores = new DefaultGameStores(resources, files); physics = new PhysicsSystem(); physicsManager = new EnginePhysicsManager(physics); queue = new TaskQueue(); // create a resourcemanager to keep track of all the resources - resources = new ResourceManager(); + // we use an IniBuilder to add all resources to the manager new IniBuilder("neon.ini.xml", files, queue).build(resources); // set up remaining engine components - quests = new QuestTracker(); + quests = new QuestTracker(gameStores); config = new Configuration(resources); // Initialize the GameContext with all engine systems - context.setResources(resources); + context.setQuestTracker(quests); context.setPhysicsEngine(physics); context.setScriptEngine(engine); context.setBus(bus); - context.setFileSystem(files); + context.setQueue(queue); context.setEngine(this); } @@ -130,13 +130,13 @@ public Engine(Port port) throws IOException { public void run() { EventAdapter adapter = new EventAdapter(quests); bus.subscribe(queue); - bus.subscribe(new CombatHandler()); - bus.subscribe(new DeathHandler()); - bus.subscribe(new InventoryHandler()); + bus.subscribe(new CombatHandler(gameStores)); + bus.subscribe(new DeathHandler(gameStores.getResources())); + bus.subscribe(new InventoryHandler(gameStores.getStore())); bus.subscribe(adapter); bus.subscribe(quests); - bus.subscribe(new GameLoader(context, config)); - bus.subscribe(new GameSaver(queue)); + bus.subscribe(new GameLoader(context, gameStores, config)); + bus.subscribe(new GameSaver(queue,gameStores)); } /** @@ -237,33 +237,6 @@ public static Context getScriptEngine() { return engine; } - /** - * @return the entity store - * @deprecated Use {@link GameContext#getStore()} instead - */ - @Deprecated - public static UIDStore getStore() { - return game.getStore(); - } - - /** - * @return the resource manager - * @deprecated Use {@link GameContext#getResources()} instead - */ - @Deprecated - public static ResourceManager getResources() { - return resources; - } - - /** - * @return the atlas - * @deprecated Use {@link GameContext#getAtlas()} instead - */ - @Deprecated - public static Atlas getAtlas() { - return game.getAtlas(); - } - @Deprecated public static AtlasPosition getAtlasPosition() { return game.getAtlasPosition(); @@ -283,14 +256,8 @@ public GameContext getContext() { return context; } - /** - * Returns the static GameContext instance. This is a transitional method to allow gradual - * migration from static accessors. - * - * @return the game context - */ - public static GameContext getStaticContext() { - return context; + public GameStores getGameStores() { + return gameStores; } /** Starts a new game. */ @@ -300,7 +267,7 @@ public void startGame(Game game) { context.setGame(game); // set up missing systems - bus.subscribe(new MagicHandler(queue, game)); + bus.subscribe(new MagicHandler(queue, gameStores, context)); // register player Player player = game.getPlayer(); diff --git a/src/main/java/neon/core/Game.java b/src/main/java/neon/core/Game.java index 8bf0ee9..806a144 100644 --- a/src/main/java/neon/core/Game.java +++ b/src/main/java/neon/core/Game.java @@ -22,57 +22,50 @@ import java.io.IOException; import lombok.Getter; import neon.entities.Player; -import neon.entities.UIDStore; -import neon.maps.Atlas; import neon.maps.AtlasPosition; -import neon.maps.MapLoader; import neon.maps.ZoneActivator; import neon.maps.services.PhysicsManager; import neon.narrative.QuestTracker; -import neon.resources.ResourceManager; -import neon.systems.files.FileSystem; import neon.systems.timing.Timer; @Getter public class Game implements Closeable { - private final UIDStore store; + private final Player player; private final Timer timer = new Timer(); - private final Atlas atlas; private final AtlasPosition atlasPosition; + @Getter private final GameStores gameStores; public Game( Player player, - FileSystem files, + GameStores gameStores, PhysicsManager physicsManager, - ResourceManager resourceManager, QuestTracker questTracker) { - store = new UIDStore(files.getFullPath("uidstore")); - MapLoader mapLoader = new MapLoader(store, resourceManager, files); - atlas = new Atlas(files, files.getFullPath("atlas"), store, mapLoader); this.player = player; + this.gameStores = gameStores; this.atlasPosition = new AtlasPosition( - atlas, new ZoneActivator(physicsManager), resourceManager, questTracker, store); + gameStores.getAtlas(), + new ZoneActivator(physicsManager), + gameStores.getResources(), + questTracker, + gameStores.getStore()); } /** * Constructor with dependency injection for testing. * * @param player the player - * @param atlas the atlas - * @param store the UID store */ - public Game(Player player, Atlas atlas, UIDStore store, AtlasPosition atlasPosition) { + public Game(Player player, GameStores gameStores, AtlasPosition atlasPosition) { this.player = player; - this.atlas = atlas; - this.store = store; + this.gameStores = gameStores; this.atlasPosition = atlasPosition; } @Override public void close() throws IOException { - store.close(); - atlas.close(); + this.gameStores.getStore().close(); + this.gameStores.getAtlas().close(); } } diff --git a/src/main/java/neon/core/GameContext.java b/src/main/java/neon/core/GameContext.java index 338c0ed..f9f20bf 100644 --- a/src/main/java/neon/core/GameContext.java +++ b/src/main/java/neon/core/GameContext.java @@ -21,13 +21,9 @@ import java.util.EventObject; import neon.core.event.TaskQueue; import neon.entities.Player; -import neon.entities.UIDStore; -import neon.maps.Atlas; import neon.maps.AtlasPosition; import neon.maps.services.PhysicsManager; import neon.narrative.QuestTracker; -import neon.resources.ResourceManager; -import neon.systems.files.FileSystem; import neon.systems.physics.PhysicsSystem; import neon.systems.timing.Timer; import org.graalvm.polyglot.Context; @@ -43,23 +39,10 @@ public interface GameContext { Player getPlayer(); - Atlas getAtlas(); - AtlasPosition getAtlasPosition(); - UIDStore getStore(); - Timer getTimer(); - ResourceManager getResources(); - - /** - * Returns the file system. - * - * @return the file system for accessing game data files - */ - FileSystem getFileSystem(); - /** * Returns the task queue. * diff --git a/src/main/java/neon/core/GameLoader.java b/src/main/java/neon/core/GameLoader.java index 7d69ef9..ed9ad1d 100644 --- a/src/main/java/neon/core/GameLoader.java +++ b/src/main/java/neon/core/GameLoader.java @@ -49,7 +49,6 @@ import neon.maps.Atlas; import neon.maps.Map; import neon.maps.MapLoader; -import neon.maps.services.GameContextResourceProvider; import neon.resources.CGame; import neon.resources.RCreature; import neon.resources.RMod; @@ -66,19 +65,22 @@ @Listener(references = References.Strong) @Slf4j public class GameLoader { - private GameContext context; - private TaskQueue queue; - private Configuration config; - private GameContextResourceProvider resourceProvider; - private MapLoader mapLoader; + private final GameContext context; + private final GameStores gameStores; + private final TaskQueue queue; + private final Configuration config; + private final SpellFactory spellFactory; + private final MapLoader mapLoader; @Getter @Setter private int worldMapUID; - public GameLoader(GameContext context, Configuration config) { + public GameLoader(GameContext context, GameStores gameStores, Configuration config) { this.context = context; + this.gameStores = gameStores; this.config = config; queue = context.getQueue(); - resourceProvider = new GameContextResourceProvider(context); - mapLoader = new MapLoader(context.getStore(), resourceProvider, context.getFileSystem()); + mapLoader = + new MapLoader(gameStores.getFileSystem(), gameStores.getStore(), gameStores.getResources(),gameStores.getZoneFactory()); + spellFactory = new SpellFactory(gameStores.getResources()); } @Handler @@ -127,16 +129,13 @@ public void initGame( log.debug("Engine.initGame() start"); // initialize player - RCreature species = ((RCreature) context.getResources().getResource(race)).clone(); - Player player = new Player(species, name, gender, spec, profession); + RCreature species = ((RCreature) gameStores.getResources().getResource(race)).clone(); + EntityFactory entityFactory = + new EntityFactory(gameStores.getStore(), gameStores.getResources()); + Player player = new Player(species, name, gender, spec, profession, gameStores); player.species.text = "@"; context.startGame( - new Game( - player, - context.getFileSystem(), - context.getPhysicsManager(), - context.getResources(), - context.getQuestTracker())); + new Game(player, gameStores, context.getPhysicsManager(), context.getQuestTracker())); setSign(player, sign); for (Skill skill : Skill.values()) { SkillHandler.checkFeat(skill, player); @@ -145,24 +144,24 @@ public void initGame( // initialize maps initMaps(); - CGame game = (CGame) context.getResources().getResource("game", "config"); - + CGame game = (CGame) gameStores.getResources().getResource("game", "config"); + InventoryHandler inventoryHandler = new InventoryHandler(gameStores.getStore()); // starting items for (String i : game.getStartingItems()) { - Item item = EntityFactory.getItem(i, context.getStore().createNewEntityUID()); - context.getStore().addEntity(item); - InventoryHandler.addItem(player, item.getUID()); + Item item = entityFactory.getItem(i, gameStores.getStore().createNewEntityUID()); + gameStores.getStore().addEntity(item); + inventoryHandler.addItem(player, item.getUID()); } // starting spells for (String i : game.getStartingSpells()) { - player.getMagicComponent().addSpell(SpellFactory.getSpell(i)); + player.getMagicComponent().addSpell(spellFactory.getSpell(i)); } // position player Rectangle bounds = player.getShapeComponent(); bounds.setLocation(game.getStartPosition().x, game.getStartPosition().y); - Atlas atlas = context.getAtlas(); - UIDStore store = context.getStore(); + Atlas atlas = gameStores.getAtlas(); + UIDStore store = gameStores.getStore(); String[] startMap = game.getStartMap(); Map map = atlas.getMap(store.getMapUID(startMap)); @@ -178,7 +177,7 @@ public void initGame( private void setSign(Player player, RSign sign) { player.setSign(sign.id); for (String power : sign.powers) { - player.getMagicComponent().addSpell(SpellFactory.getSpell(power)); + player.getMagicComponent().addSpell(spellFactory.getSpell(power)); } for (Ability ability : sign.abilities.keySet()) { player.getCharacteristicsComponent().addAbility(ability, sign.abilities.get(ability)); @@ -266,11 +265,11 @@ private void loadEvents(SaveGameModel.EventsData events) { SpellType type = SpellType.valueOf(event.spellType.toUpperCase()); Entity caster = null; if (event.caster != null) { - caster = context.getStore().getEntity(event.caster); + caster = gameStores.getStore().getEntity(event.caster); } Entity target = null; if (event.target != null) { - target = context.getStore().getEntity(event.target); + target = gameStores.getStore().getEntity(event.target); } Spell spell = new Spell(target, caster, effect, magnitude, script, type); queue.add(new MagicTask(spell, stop), start, stop, period); @@ -281,28 +280,24 @@ private void loadEvents(SaveGameModel.EventsData events) { private void loadPlayer(SaveGameModel.PlayerSaveData playerData) { // create player - RCreature species = (RCreature) context.getResources().getResource(playerData.race); + RCreature species = (RCreature) gameStores.getResources().getResource(playerData.race); Player player = new Player( species.clone(), playerData.name, Gender.valueOf(playerData.gender.toUpperCase()), Player.Specialisation.valueOf(playerData.specialisation), - playerData.profession); + playerData.profession, + gameStores); context.startGame( - new Game( - player, - context.getFileSystem(), - context.getPhysicsManager(), - context.getResources(), - context.getQuestTracker())); + new Game(player, gameStores, context.getPhysicsManager(), context.getQuestTracker())); Rectangle bounds = player.getShapeComponent(); bounds.setLocation(playerData.x, playerData.y); player.setSign(playerData.sign); player.species.text = "@"; // start map - context.getAtlasPosition().setMap(context.getAtlas().getMap(playerData.map)); + context.getAtlasPosition().setMap(gameStores.getAtlas().getMap(playerData.map)); context.getAtlasPosition().setCurrentZone(playerData.level, player); // stats @@ -324,7 +319,7 @@ private void loadPlayer(SaveGameModel.PlayerSaveData playerData) { // spells for (SaveGameModel.SpellReference spellRef : playerData.spells) { - player.getMagicComponent().addSpell(SpellFactory.getSpell(spellRef.id)); + player.getMagicComponent().addSpell(spellFactory.getSpell(spellRef.id)); } // feats @@ -376,17 +371,18 @@ private void loadSkills(Player player, SaveGameModel.SkillsData skills) { private void initMaps() { // put mods and maps in uidstore - for (RMod mod : context.getResources().getResources(RMod.class)) { - if (!context.getStore().isModUIDLoaded(mod.id)) { - context.getStore().addMod(mod.id); + for (RMod mod : gameStores.getResources().getResources(RMod.class)) { + if (!gameStores.getStore().isModUIDLoaded(mod.id)) { + gameStores.getStore().addMod(mod.id); } for (String[] path : mod.getMaps()) try { // maps are in twowaymap, and are therefore not stored in cache - Element map = context.getFileSystem().getFile(new XMLTranslator(), path).getRootElement(); + Element map = + gameStores.getFileSystem().getFile(new XMLTranslator(), path).getRootElement(); short mapUID = Short.parseShort(map.getChild("header").getAttributeValue("uid")); - int uid = UIDStore.getMapUID(context.getStore().getModUID(path[0]), mapUID); + int uid = UIDStore.getMapUID(gameStores.getStore().getModUID(path[0]), mapUID); mapLoader.load(path, mapUID); - context.getStore().addMap(uid, path); + gameStores.getStore().addMap(uid, path); } catch (Exception e) { log.info("Map error in mod {} : {}", path, e.toString()); } diff --git a/src/main/java/neon/core/GameSaver.java b/src/main/java/neon/core/GameSaver.java index 0c90dde..ca38fc3 100644 --- a/src/main/java/neon/core/GameSaver.java +++ b/src/main/java/neon/core/GameSaver.java @@ -43,9 +43,11 @@ @Listener(references = References.Strong) public class GameSaver { private TaskQueue queue; + private final GameStores gameStores; - public GameSaver(TaskQueue queue) { + public GameSaver(TaskQueue queue, GameStores gameStores) { this.queue = queue; + this.gameStores = gameStores; } /** Saves the current game. */ @@ -75,8 +77,8 @@ public void saveGame(SaveEvent se) { } // first copy everything from temp to save, to ensure savedoc is not overwritten - Engine.getAtlas().getCache().commit(); - Engine.getStore().getCache().commit(); + gameStores.getAtlas().getCache().commit(); + gameStores.getStore().getCache().commit(); Engine.getFileSystem().storeTemp(dir); // Serialize with Jackson diff --git a/src/main/java/neon/core/GameStores.java b/src/main/java/neon/core/GameStores.java new file mode 100644 index 0000000..dbfbe96 --- /dev/null +++ b/src/main/java/neon/core/GameStores.java @@ -0,0 +1,19 @@ +package neon.core; + +import neon.entities.UIDStore; +import neon.maps.Atlas; +import neon.maps.ZoneFactory; +import neon.resources.ResourceManager; +import neon.systems.files.FileSystem; + +public interface GameStores { + Atlas getAtlas(); + + UIDStore getStore(); + + ResourceManager getResources(); + + FileSystem getFileSystem(); + + ZoneFactory getZoneFactory(); +} diff --git a/src/main/java/neon/core/ScriptInterface.java b/src/main/java/neon/core/ScriptInterface.java index 6974520..5ce70d0 100644 --- a/src/main/java/neon/core/ScriptInterface.java +++ b/src/main/java/neon/core/ScriptInterface.java @@ -19,18 +19,24 @@ package neon.core; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Scanner; import neon.entities.Entity; +import neon.entities.UIDStore; import neon.ui.GamePanel; public class ScriptInterface { - private GamePanel panel; - - public ScriptInterface(GamePanel panel) { + private final GamePanel panel; + private final UIDStore uidStore; + private final GameContext gameContext; + public ScriptInterface(GamePanel panel, UIDStore uidStore, GameContext gameContext) { this.panel = panel; - InputStream input = Engine.class.getResourceAsStream("scripts.js"); - Scanner scanner = new Scanner(input, "UTF-8"); - Engine.execute(scanner.useDelimiter("\\A").next()); + this.uidStore = uidStore; + this.gameContext = gameContext; + InputStream input = Engine.class.getResourceAsStream("scripts.js"); + assert input != null; + Scanner scanner = new Scanner(input, StandardCharsets.UTF_8); + gameContext.execute(scanner.useDelimiter("\\A").next()); scanner.close(); } @@ -39,10 +45,10 @@ public void show(String text) { } public Entity get(long uid) { - return Engine.getStore().getEntity(uid); + return uidStore.getEntity(uid); } public Entity getPlayer() { - return Engine.getPlayer(); + return gameContext.getPlayer(); } } diff --git a/src/main/java/neon/core/handlers/CombatHandler.java b/src/main/java/neon/core/handlers/CombatHandler.java index 53ed8c1..7bb4a63 100644 --- a/src/main/java/neon/core/handlers/CombatHandler.java +++ b/src/main/java/neon/core/handlers/CombatHandler.java @@ -21,6 +21,7 @@ import java.awt.Rectangle; import lombok.extern.slf4j.Slf4j; import neon.core.Engine; +import neon.core.GameStores; import neon.core.event.CombatEvent; import neon.core.event.MagicEvent; import neon.entities.Creature; @@ -47,6 +48,15 @@ @Listener(references = References.Strong) // strong, to avoid gc @Slf4j public class CombatHandler { + private final GameStores gameStores; + private final InventoryHandler inventoryHandler; + private final CombatUtils combatUtils; + public CombatHandler(GameStores gameStores) { + this.gameStores = gameStores; + inventoryHandler = new InventoryHandler(gameStores.getStore()); + combatUtils = new CombatUtils(gameStores.getStore()); + } + @Handler public void handleCombat(CombatEvent ce) { log.trace("handleCombat {}", ce); @@ -76,7 +86,7 @@ public void handleCombat(CombatEvent ce) { */ private int fight(Creature attacker, Creature defender) { long uid = attacker.getInventoryComponent().get(Slot.WEAPON); - Weapon weapon = (Weapon) Engine.getStore().getEntity(uid); + Weapon weapon = (Weapon) gameStores.getStore().getEntity(uid); return fight(attacker, defender, weapon); } @@ -91,18 +101,18 @@ private int fight(Creature attacker, Creature defender) { private int shoot(Creature shooter, Creature target) { // damage is average of arrow and bow (Creature.getAV) Weapon ammo = - (Weapon) Engine.getStore().getEntity(shooter.getInventoryComponent().get(Slot.AMMO)); - InventoryHandler.removeItem(shooter, ammo.getUID()); + (Weapon) gameStores.getStore().getEntity(shooter.getInventoryComponent().get(Slot.AMMO)); + inventoryHandler.removeItem(shooter, ammo.getUID()); for (long uid : shooter.getInventoryComponent()) { - Item item = (Item) Engine.getStore().getEntity(uid); + Item item = (Item) gameStores.getStore().getEntity(uid); if (item.getID().equals(ammo.getID())) { - InventoryHandler.equip(item, shooter); + inventoryHandler.equip(item, shooter); break; } } long uid = shooter.getInventoryComponent().get(Slot.WEAPON); - Weapon weapon = (Weapon) Engine.getStore().getEntity(uid); + Weapon weapon = (Weapon) gameStores.getStore().getEntity(uid); return fight(shooter, target, weapon); } @@ -116,12 +126,12 @@ private int shoot(Creature shooter, Creature target) { */ private int fling(Creature thrower, Creature target) { Weapon weapon = - (Weapon) Engine.getStore().getEntity(thrower.getInventoryComponent().get(Slot.AMMO)); - InventoryHandler.removeItem(thrower, weapon.getUID()); + (Weapon) gameStores.getStore().getEntity(thrower.getInventoryComponent().get(Slot.AMMO)); + inventoryHandler.removeItem(thrower, weapon.getUID()); for (long uid : thrower.getInventoryComponent()) { - Item item = (Item) Engine.getStore().getEntity(uid); + Item item = (Item) gameStores.getStore().getEntity(uid); if (item.getID().equals(weapon.getID())) { - InventoryHandler.equip(item, thrower); + inventoryHandler.equip(item, thrower); break; } } @@ -130,21 +140,21 @@ private int fling(Creature thrower, Creature target) { private int fight(Creature attacker, Creature defender, Weapon weapon) { // attacker determines an attack value (depends on dex) - int attack = CombatUtils.attack(attacker); + int attack = combatUtils.attack(attacker); int result; // defender checks if they can dodge or block - if (CombatUtils.dodge(defender) < attack) { - if (CombatUtils.block(defender) < attack) { + if (combatUtils.dodge(defender) < attack) { + if (combatUtils.block(defender) < attack) { if (weapon != null) { weapon.setState(weapon.getState() - 1); } // Attack Value, dependent on weapon, skill and str - int AV = CombatUtils.getAV(attacker); + int AV = combatUtils.getAV(attacker); // defense value, dependent on armor, skill - int DV = CombatUtils.getDV(defender); + int DV = combatUtils.getDV(defender); // always minimum 1 damage HealthComponent health = defender.getHealthComponent(); diff --git a/src/main/java/neon/core/handlers/CombatUtils.java b/src/main/java/neon/core/handlers/CombatUtils.java index bcedb45..7e523af 100644 --- a/src/main/java/neon/core/handlers/CombatUtils.java +++ b/src/main/java/neon/core/handlers/CombatUtils.java @@ -18,11 +18,7 @@ package neon.core.handlers; -import neon.core.Engine; -import neon.entities.Armor; -import neon.entities.Creature; -import neon.entities.Entity; -import neon.entities.Weapon; +import neon.entities.*; import neon.entities.components.Inventory; import neon.entities.property.Skill; import neon.entities.property.Slot; @@ -31,13 +27,20 @@ import neon.util.Dice; public class CombatUtils { + + private final UIDStore uidStore; + + public CombatUtils(UIDStore uidStore) { + this.uidStore = uidStore; + } + /** * Does an attack roll. This is used to determine if this creature is able to hit anything with an * attack. * * @return an attack roll */ - protected static int attack(Creature creature) { + protected int attack(Creature creature) { switch (getWeaponType(creature)) { case BLADE_ONE: case BLADE_TWO: @@ -64,20 +67,20 @@ protected static int attack(Creature creature) { * * @return the attack value */ - protected static int getAV(Creature creature) { + protected int getAV(Creature creature) { Inventory inventory = creature.getInventoryComponent(); int damage; if (inventory.hasEquiped(Slot.WEAPON)) { - Weapon weapon = (Weapon) Engine.getStore().getEntity(inventory.get(Slot.WEAPON)); + Weapon weapon = (Weapon) uidStore.getEntity(inventory.get(Slot.WEAPON)); damage = Dice.roll(weapon.getDamage()); if (weapon.getWeaponType().equals(WeaponType.BOW) || weapon.getWeaponType().equals(WeaponType.CROSSBOW)) { - Weapon ammo = (Weapon) Engine.getStore().getEntity(inventory.get(Slot.AMMO)); + Weapon ammo = (Weapon) uidStore.getEntity(inventory.get(Slot.AMMO)); damage = (damage + Dice.roll(ammo.getDamage())) / 2; } } else if (inventory.hasEquiped(Slot.AMMO)) { - Weapon ammo = (Weapon) Engine.getStore().getEntity(inventory.get(Slot.AMMO)); + Weapon ammo = (Weapon) uidStore.getEntity(inventory.get(Slot.AMMO)); damage = Dice.roll(ammo.getDamage()); } else { damage = Dice.roll(creature.species.av); @@ -111,11 +114,10 @@ protected static int getAV(Creature creature) { * * @return a block skill check */ - protected static int block(Creature creature) { + protected int block(Creature creature) { if (creature.getInventoryComponent().hasEquiped(Slot.SHIELD)) { float mod = 1f; - Armor armor = - (Armor) Engine.getStore().getEntity(creature.getInventoryComponent().get(Slot.SHIELD)); + Armor armor = (Armor) uidStore.getEntity(creature.getInventoryComponent().get(Slot.SHIELD)); switch (((RClothing) (armor.resource)).kind) { case LIGHT: mod = creature.getSkill(Skill.LIGHT_ARMOR) / 20f; @@ -141,7 +143,7 @@ protected static int block(Creature creature) { * * @return a dodge skill check */ - protected static int dodge(Creature creature) { + protected int dodge(Creature creature) { return SkillHandler.check(creature, Skill.DODGING); } @@ -150,10 +152,10 @@ protected static int dodge(Creature creature) { * * @return the defense value */ - public static int getDV(Creature creature) { + public int getDV(Creature creature) { float AR = creature.species.dv; for (Slot s : creature.getInventoryComponent().slots()) { - Entity item = Engine.getStore().getEntity(creature.getInventoryComponent().get(s)); + Entity item = uidStore.getEntity(creature.getInventoryComponent().get(s)); if (item instanceof Armor) { Armor c = (Armor) item; int mod = 0; @@ -180,13 +182,13 @@ public static int getDV(Creature creature) { * @param creature * @return the type of the currently equiped weapon */ - public static WeaponType getWeaponType(Creature creature) { + public WeaponType getWeaponType(Creature creature) { Inventory inventory = creature.getInventoryComponent(); if (inventory.hasEquiped(Slot.WEAPON)) { - Weapon weapon = (Weapon) Engine.getStore().getEntity(inventory.get(Slot.WEAPON)); + Weapon weapon = (Weapon) uidStore.getEntity(inventory.get(Slot.WEAPON)); return (weapon.getWeaponType()); } else if (inventory.hasEquiped(Slot.AMMO) - && ((Weapon) Engine.getStore().getEntity(inventory.get(Slot.AMMO))).getWeaponType() + && ((Weapon) uidStore.getEntity(inventory.get(Slot.AMMO))).getWeaponType() == WeaponType.THROWN) { return WeaponType.THROWN; } else { diff --git a/src/main/java/neon/core/handlers/DeathHandler.java b/src/main/java/neon/core/handlers/DeathHandler.java index d09936a..b141a25 100644 --- a/src/main/java/neon/core/handlers/DeathHandler.java +++ b/src/main/java/neon/core/handlers/DeathHandler.java @@ -24,6 +24,7 @@ import neon.entities.Creature; import neon.entities.components.ScriptComponent; import neon.resources.RScript; +import neon.resources.ResourceManager; import net.engio.mbassy.listener.Handler; import net.engio.mbassy.listener.Listener; import net.engio.mbassy.listener.References; @@ -36,7 +37,11 @@ @Listener(references = References.Strong) // strong, om gc te vermijden @Slf4j public class DeathHandler { - public DeathHandler() {} + private final ResourceManager resourceManager; + + public DeathHandler(ResourceManager resourceManager) { + this.resourceManager = resourceManager; + } @Handler public void handle(DeathEvent de) { @@ -50,7 +55,7 @@ public void handle(DeathEvent de) { ScriptComponent sc = creature.getScriptComponent(); for (String s : sc.getScripts()) { - RScript rs = (RScript) Engine.getResources().getResource(s, "script"); + RScript rs = (RScript) resourceManager.getResource(s, "script"); Context se = Engine.getScriptEngine(); se.eval("js", rs.script); diff --git a/src/main/java/neon/core/handlers/InventoryHandler.java b/src/main/java/neon/core/handlers/InventoryHandler.java index 0a0aa7a..f67b399 100644 --- a/src/main/java/neon/core/handlers/InventoryHandler.java +++ b/src/main/java/neon/core/handlers/InventoryHandler.java @@ -21,12 +21,8 @@ import java.util.ArrayList; import java.util.Collection; import lombok.extern.slf4j.Slf4j; -import neon.core.Engine; import neon.core.event.StoreEvent; -import neon.entities.Clothing; -import neon.entities.Creature; -import neon.entities.Item; -import neon.entities.Weapon; +import neon.entities.*; import neon.entities.components.Inventory; import neon.entities.property.Slot; import neon.magic.Effect; @@ -40,6 +36,13 @@ @Listener(references = References.Strong) @Slf4j public class InventoryHandler { + + private final UIDStore uidStore; + + public InventoryHandler(UIDStore gameStores) { + this.uidStore = gameStores; + } + /** * Adds or removes an {@code Entity} from the {@code UIDStore}. * @@ -50,10 +53,10 @@ public void handle(StoreEvent event) { log.trace("handle {}", event); switch (event.getMode()) { case ADD: - Engine.getStore().addEntity(event.getEntity()); + uidStore.addEntity(event.getEntity()); break; case REMOVE: - Engine.getStore().removeEntity(event.getUID()); + uidStore.removeEntity(event.getUID()); break; } } @@ -64,8 +67,8 @@ public void handle(StoreEvent event) { * @param creature a creature * @param uid the uid of the item to add */ - public static void addItem(Creature creature, long uid) { - Item item = (Item) Engine.getStore().getEntity(uid); + public void addItem(Creature creature, long uid) { + Item item = (Item) uidStore.getEntity(uid); if (item instanceof Item.Coin) { creature.getInventoryComponent().addMoney(item.resource.cost); } else { @@ -78,7 +81,7 @@ public static void addItem(Creature creature, long uid) { * * @param uid the uid of the the item to remove */ - public static void removeItem(Creature creature, long uid) { + public void removeItem(Creature creature, long uid) { if (creature.getInventoryComponent().hasEquiped(uid)) { unequip(uid, creature); // first unequip if you still have this equipped } @@ -91,12 +94,12 @@ public static void removeItem(Creature creature, long uid) { * @param id the name of the item to remove * @param amount the number of items to remove */ - public static Collection removeItems(Creature creature, String id, int amount) { + public Collection removeItems(Creature creature, String id, int amount) { ArrayList removal = new ArrayList(); for (Long uid : creature.getInventoryComponent()) { - Item item = (Item) Engine.getStore().getEntity(uid); + Item item = (Item) uidStore.getEntity(uid); if (item.getID().equals(id)) { - InventoryHandler.removeItem(creature, item.getUID()); + removeItem(creature, item.getUID()); removal.add(uid); amount--; } @@ -107,7 +110,7 @@ public static Collection removeItems(Creature creature, String id, int amo return removal; } - public static void equip(Item item, Creature creature) { + public void equip(Item item, Creature creature) { Inventory inventory = creature.getInventoryComponent(); if (item instanceof Clothing) { Clothing c = (Clothing) item; @@ -142,8 +145,8 @@ public static void equip(Item item, Creature creature) { MagicUtils.equip(creature, (Clothing) item); } } else if (item instanceof Weapon) { - Weapon weapon = (Weapon) Engine.getStore().getEntity((inventory.get(Slot.WEAPON))); - Weapon ammo = (Weapon) Engine.getStore().getEntity((inventory.get(Slot.AMMO))); + Weapon weapon = (Weapon) uidStore.getEntity((inventory.get(Slot.WEAPON))); + Weapon ammo = (Weapon) uidStore.getEntity((inventory.get(Slot.AMMO))); switch (((Weapon) item).getWeaponType()) { case THROWN: @@ -183,9 +186,9 @@ public static void equip(Item item, Creature creature) { } } - public static void unequip(long uid, Creature creature) { + public void unequip(long uid, Creature creature) { Inventory inventory = creature.getInventoryComponent(); - Item item = (Item) Engine.getStore().getEntity(uid); + Item item = (Item) uidStore.getEntity(uid); if (item instanceof Clothing) { Clothing c = (Clothing) item; if (c.getSlot().equals(Slot.RING)) { @@ -218,10 +221,10 @@ public static void unequip(long uid, Creature creature) { * @param id * @return the number of items with the given id the given creature owns */ - public static int getAmount(Creature creature, String id) { + public int getAmount(Creature creature, String id) { int count = 0; for (long uid : creature.getInventoryComponent()) { - Item item = (Item) Engine.getStore().getEntity(uid); + Item item = (Item) uidStore.getEntity(uid); if (item.getID().equals(id)) { count++; } @@ -232,10 +235,10 @@ public static int getAmount(Creature creature, String id) { /** * @return a creature's weight */ - public static int getWeight(Creature creature) { + public int getWeight(Creature creature) { float sum = 0; for (long uid : creature.getInventoryComponent()) { - sum += ((Item) Engine.getStore().getEntity(uid)).resource.weight; + sum += ((Item) uidStore.getEntity(uid)).resource.weight; } // in case of 'burden' spell for (Spell s : creature.getActiveSpells()) { diff --git a/src/main/java/neon/core/handlers/MagicHandler.java b/src/main/java/neon/core/handlers/MagicHandler.java index 59d26ea..1e1da34 100644 --- a/src/main/java/neon/core/handlers/MagicHandler.java +++ b/src/main/java/neon/core/handlers/MagicHandler.java @@ -23,7 +23,8 @@ import java.util.Collection; import lombok.extern.slf4j.Slf4j; import neon.core.Engine; -import neon.core.Game; +import neon.core.GameContext; +import neon.core.GameStores; import neon.core.event.MagicEvent; import neon.core.event.MagicTask; import neon.core.event.TaskQueue; @@ -56,12 +57,18 @@ public class MagicHandler { public static final int SILENCED = 8; // caster silenced public static final int INTERVAL = 9; // power interval niet gedaan - private static TaskQueue queue; - private static Game game; - - public MagicHandler(TaskQueue queue, Game game) { - MagicHandler.queue = queue; - MagicHandler.game = game; + private TaskQueue queue; + private final GameStores gameStores; + private final GameContext gameContext; + private final InventoryHandler inventoryHandler; + private final CombatUtils combatUtils; + + public MagicHandler(TaskQueue queue, GameStores gameStores, GameContext gameContext) { + this.queue = queue; + this.gameStores = gameStores; + this.inventoryHandler = new InventoryHandler(gameStores.getStore()); + this.gameContext = gameContext; + this.combatUtils = new CombatUtils(gameStores.getStore()); } /** @@ -93,17 +100,18 @@ public void cast(MagicEvent.OnPoint me) { if (spell.effect == Effect.SCRIPTED) { Engine.execute(spell.script); } else if (spell.effect.getHandler().onItem()) { - Collection items = game.getAtlasPosition().getCurrentZone().getItems(box); + Collection items = gameContext.getAtlasPosition().getCurrentZone().getItems(box); for (long uid : items) { - castSpell((Item) game.getStore().getEntity(uid), spell); + castSpell((Item) gameStores.getStore().getEntity(uid), spell); } } else { - Collection creatures = game.getAtlasPosition().getCurrentZone().getCreatures(box); + Collection creatures = + gameContext.getAtlasPosition().getCurrentZone().getCreatures(box); for (Creature creature : creatures) { castSpell(creature, null, spell); } - if (box.contains(game.getPlayer().getShapeComponent())) { - castSpell(game.getPlayer(), null, spell); + if (box.contains(gameContext.getPlayer().getShapeComponent())) { + castSpell(gameContext.getPlayer(), null, spell); } } } @@ -132,7 +140,7 @@ public void cast(MagicEvent.CreatureOnPoint me) { Engine.post(new MagicEvent.Result(this, caster, RANGE)); } else { if (formula instanceof RSpell.Power) { - int time = game.getTimer().getTime(); + int time = gameContext.getTimer().getTime(); if (caster.getMagicComponent().canUse((RSpell.Power) formula, time)) { caster.getMagicComponent().usePower((RSpell.Power) formula, time); } else { // te kort geleden power gecast @@ -164,14 +172,15 @@ public void cast(MagicEvent.CreatureOnPoint me) { if (formula.effect == Effect.SCRIPTED) { Engine.execute(formula.script); } else if (formula.effect.getHandler().onItem()) { - Collection items = game.getAtlasPosition().getCurrentZone().getItems(box); + Collection items = gameContext.getAtlasPosition().getCurrentZone().getItems(box); for (long uid : items) { - castSpell((Item) game.getStore().getEntity(uid), formula); + castSpell((Item) gameStores.getStore().getEntity(uid), formula); } } else { - Collection creatures = game.getAtlasPosition().getCurrentZone().getCreatures(box); - if (box.contains(game.getPlayer().getShapeComponent())) { - creatures.add(game.getPlayer()); + Collection creatures = + gameContext.getAtlasPosition().getCurrentZone().getCreatures(box); + if (box.contains(gameContext.getPlayer().getShapeComponent())) { + creatures.add(gameContext.getPlayer()); } for (Creature creature : creatures) { castSpell(creature, caster, formula); @@ -213,7 +222,7 @@ public void cast(MagicEvent.ItemOnPoint me) { Engine.post(new MagicEvent.Result(this, caster, RANGE)); } else { if (item instanceof Item.Scroll) { - InventoryHandler.removeItem(caster, item.getUID()); + inventoryHandler.removeItem(caster, item.getUID()); } else { enchantment.addMana(-MagicUtils.getMana(formula)); } @@ -224,14 +233,15 @@ public void cast(MagicEvent.ItemOnPoint me) { if (formula.effect == Effect.SCRIPTED) { Engine.execute(formula.script); } else if (formula.effect.getHandler().onItem()) { - Collection items = game.getAtlasPosition().getCurrentZone().getItems(box); + Collection items = gameContext.getAtlasPosition().getCurrentZone().getItems(box); for (long uid : items) { - castSpell((Item) game.getStore().getEntity(uid), formula); + castSpell((Item) gameStores.getStore().getEntity(uid), formula); } } else { - Collection creatures = game.getAtlasPosition().getCurrentZone().getCreatures(box); - if (box.contains(game.getPlayer().getShapeComponent())) { - creatures.add(game.getPlayer()); + Collection creatures = + gameContext.getAtlasPosition().getCurrentZone().getCreatures(box); + if (box.contains(gameContext.getPlayer().getShapeComponent())) { + creatures.add(gameContext.getPlayer()); } for (Creature creature : creatures) { castSpell(creature, caster, formula); @@ -246,8 +256,6 @@ public void cast(MagicEvent.ItemOnPoint me) { /** * This methods lets a creature using a magic item cast a spell on itself. * - * @param caster the spell caster - * @param item the spell caster's magic item * @return the result of the cast */ @Handler @@ -273,7 +281,7 @@ public void cast(MagicEvent.ItemOnSelf me) { } else { enchantment.addMana(-MagicUtils.getMana(formula)); if (item instanceof Item.Scroll) { - InventoryHandler.removeItem(caster, item.getUID()); + inventoryHandler.removeItem(caster, item.getUID()); } Engine.post(new MagicEvent.Result(this, caster, castSpell(caster, caster, formula))); } @@ -299,7 +307,7 @@ public void cast(MagicEvent.OnSelf me) { Engine.post(new MagicEvent.Result(this, caster, RANGE)); } else { if (spell instanceof RSpell.Power) { - int time = game.getTimer().getTime(); + int time = gameContext.getTimer().getTime(); if (caster.getMagicComponent().canUse((RSpell.Power) spell, time)) { caster.getMagicComponent().usePower((RSpell.Power) spell, time); castSpell(caster, caster, spell); @@ -335,7 +343,7 @@ private int castSpell(Item target, RSpell formula) { } } - private static int castSpell(Creature target, Creature caster, RSpell formula) { + private int castSpell(Creature target, Creature caster, RSpell formula) { Characteristics chars = target.getCharacteristicsComponent(); int penalty = 0; @@ -362,7 +370,7 @@ private static int castSpell(Creature target, Creature caster, RSpell formula) { if (formula.duration > 0) { target.addActiveSpell(spell); - int time = game.getTimer().getTime(); + int time = gameContext.getTimer().getTime(); MagicTask task = new MagicTask(spell, time + formula.duration); queue.add(task, time, 1, time + formula.duration); } @@ -377,7 +385,7 @@ private int checkPenalty(Creature caster) { int penalty = 0; // wearing armor - if (CombatUtils.getDV(caster) > caster.species.dv) { + if (combatUtils.getDV(caster) > caster.species.dv) { penalty += 10; } @@ -391,7 +399,7 @@ private int checkPenalty(Creature caster) { * @param food * @return */ - public static void eat(Creature eater, Item.Food food) { + public void eat(Creature eater, Item.Food food) { Enchantment enchantment = food.getMagicComponent(); int check = Math.max(1, SkillHandler.check(eater, Skill.ALCHEMY) / 10); RSpell spell = @@ -413,7 +421,7 @@ public static void eat(Creature eater, Item.Food food) { * @param potion * @return */ - public static void drink(Creature drinker, Item.Potion potion) { + public void drink(Creature drinker, Item.Potion potion) { Enchantment enchantment = potion.getMagicComponent(); RSpell spell = enchantment.getSpell(); castSpell(drinker, drinker, spell); diff --git a/src/main/java/neon/core/handlers/MotionHandler.java b/src/main/java/neon/core/handlers/MotionHandler.java index 32a7f1e..24af393 100644 --- a/src/main/java/neon/core/handlers/MotionHandler.java +++ b/src/main/java/neon/core/handlers/MotionHandler.java @@ -25,6 +25,8 @@ import javax.swing.SwingConstants; import lombok.extern.slf4j.Slf4j; import neon.core.Engine; +import neon.core.GameContext; +import neon.core.GameStores; import neon.core.event.MessageEvent; import neon.entities.Creature; import neon.entities.Door; @@ -51,6 +53,15 @@ public class MotionHandler { public static final byte DOOR = 4; public static final byte NULL = 5; public static final byte HABITAT = 6; + public final GameContext context; + public final GameStores gameStores; + public final MapLoader mapLoader; + + public MotionHandler(GameContext context, GameStores gameStores) { + this.context = context; + this.gameStores = gameStores; + mapLoader = new MapLoader(gameStores.getFileSystem(),gameStores.getStore(),gameStores.getResources(),gameStores.getZoneFactory()); + } /** * Teleports a creature. Two results are possible: @@ -64,39 +75,35 @@ public class MotionHandler { * @param door the portal that the creature used * @return the result */ - public static byte teleport(Player creature, Door door) { + public byte teleport(Player creature, Door door) { if (door.portal.isPortal()) { - Zone previous = Engine.getAtlasPosition().getCurrentZone(); // briefly buffer current zone + Zone previous = context.getAtlasPosition().getCurrentZone(); // briefly buffer current zone if (door.portal.getDestMap() != 0) { // load map and have door refer back - Map map = Engine.getAtlas().getMap(door.portal.getDestMap()); + Map map = gameStores.getAtlas().getMap(door.portal.getDestMap()); Zone zone = map.getZone(door.portal.getDestZone()); for (long uid : zone.getItems(door.portal.getDestPos())) { - Entity i = Engine.getStore().getEntity(uid); + Entity i = gameStores.getStore().getEntity(uid); if (i instanceof Door) { - ((Door) i).portal.setDestMap(Engine.getAtlasPosition().getCurrentMap()); + ((Door) i).portal.setDestMap(context.getAtlasPosition().getCurrentMap()); } } - Engine.getAtlasPosition().setMap(map); - Engine.getScriptEngine().getBindings("js").putMember("map", map); - door.portal.setDestMap(Engine.getAtlasPosition().getCurrentMap()); + context.getAtlasPosition().setMap(map); + context.getScriptEngine().getBindings("js").putMember("map", map); + door.portal.setDestMap(context.getAtlasPosition().getCurrentMap()); } else if (door.portal.getDestTheme() != null) { - try { - Dungeon dungeon = MapLoader.loadDungeon(door.portal.getDestTheme()); - Engine.getAtlasPosition().setMap(dungeon); - door.portal.setDestMap(Engine.getAtlasPosition().getCurrentMap()); - } catch (IOException ioe) { - log.error("Error loading dungeon for theme {}", door.portal.getDestTheme(), ioe); - } + Dungeon dungeon = mapLoader.loadThemedDungeon(door.portal.getDestTheme(), door.portal.getDestTheme(),door.portal.getDestZone()); + context.getAtlasPosition().setMap(dungeon); + door.portal.setDestMap(context.getAtlasPosition().getCurrentMap()); } - Engine.getAtlasPosition().enterZone(door, previous, creature); + context.getAtlasPosition().enterZone(door, previous, creature); walk(creature, door.portal.getDestPos()); // check if there is a door at the destination, if so, unlock and open this door Rectangle bounds = creature.getShapeComponent(); - for (long uid : Engine.getAtlasPosition().getCurrentZone().getItems(bounds)) { - Entity i = Engine.getStore().getEntity(uid); + for (long uid : context.getAtlasPosition().getCurrentZone().getItems(bounds)) { + Entity i = gameStores.getStore().getEntity(uid); if (i instanceof Door) { ((Door) i).lock.open(); } @@ -128,16 +135,16 @@ public static byte teleport(Player creature, Door door) { * @param p the point the creature wants to move to * @return the result of the movement */ - public static byte move(Creature actor, Point p) { - Region region = Engine.getAtlasPosition().getCurrentZone().getRegion(p); + public byte move(Creature actor, Point p) { + Region region = context.getAtlasPosition().getCurrentZone().getRegion(p); if (p == null || region == null) { return NULL; } // check if there is no closed door present - Collection items = Engine.getAtlasPosition().getCurrentZone().getItems(p); + Collection items = context.getAtlasPosition().getCurrentZone().getItems(p); for (long uid : items) { - Entity i = Engine.getStore().getEntity(uid); + Entity i = gameStores.getStore().getEntity(uid); if (i instanceof Door) { if (((Door) i).lock.getState() != Lock.OPEN) { return DOOR; @@ -155,16 +162,12 @@ public static byte move(Creature actor, Point p) { } } - switch (mov) { - case NONE: - return walk(actor, p); - case SWIM: - return swim(actor, p); - case CLIMB: - return climb(actor, p); - default: - return BLOCKED; - } + return switch (mov) { + case NONE -> walk(actor, p); + case SWIM -> swim(actor, p); + case CLIMB -> climb(actor, p); + default -> BLOCKED; + }; } /** @@ -175,11 +178,11 @@ public static byte move(Creature actor, Point p) { * @param y * @return the result of the movement */ - public static byte move(Creature creature, int x, int y) { + public byte move(Creature creature, int x, int y) { return move(creature, new Point(x, y)); } - private static byte swim(Creature swimmer, Point p) { + private byte swim(Creature swimmer, Point p) { if (swimmer.species.habitat == Habitat.WATER) { return OK; } else if (SkillHandler.check(swimmer, Skill.SWIMMING) > 20) { diff --git a/src/main/java/neon/core/handlers/TurnHandler.java b/src/main/java/neon/core/handlers/TurnHandler.java index a2f91f4..21555eb 100644 --- a/src/main/java/neon/core/handlers/TurnHandler.java +++ b/src/main/java/neon/core/handlers/TurnHandler.java @@ -22,6 +22,7 @@ import java.util.Collection; import lombok.extern.slf4j.Slf4j; import neon.core.Configuration; +import neon.core.GameStores; import neon.core.event.TurnEvent; import neon.core.event.UpdateEvent; import neon.entities.Creature; @@ -33,10 +34,6 @@ import neon.maps.Region.Modifier; import neon.maps.generators.TownGenerator; import neon.maps.generators.WildernessGenerator; -import neon.maps.services.EntityStore; -import neon.maps.services.GameContextEntityStore; -import neon.maps.services.GameContextResourceProvider; -import neon.maps.services.ResourceProvider; import neon.resources.CServer; import neon.resources.RRegionTheme; import neon.ui.GamePanel; @@ -50,15 +47,16 @@ public class TurnHandler { private GamePanel panel; private Generator generator; private int range; - private final EntityStore entityStore; - private final ResourceProvider resourceProvider; - public TurnHandler(GamePanel panel) { + private final GameStores gameStores; + private final InventoryHandler inventoryHandler; + + public TurnHandler(GamePanel panel, GameStores gameStores) { this.panel = panel; - this.entityStore = new GameContextEntityStore(panel.getContext()); - this.resourceProvider = new GameContextResourceProvider(panel.getContext()); - CServer ini = (CServer) panel.getContext().getResources().getResource("ini", "config"); + this.gameStores = gameStores; + inventoryHandler = new InventoryHandler(gameStores.getStore()); + CServer ini = (CServer) gameStores.getResources().getResource("ini", "config"); range = ini.getAIRange(); } @@ -83,7 +81,7 @@ public void tick(TurnEvent te) { // monsters controleren Player player = panel.getContext().getPlayer(); for (long uid : panel.getContext().getAtlasPosition().getCurrentZone().getCreatures()) { - Creature creature = (Creature) panel.getContext().getStore().getEntity(uid); + Creature creature = (Creature) gameStores.getStore().getEntity(uid); if (!creature.hasCondition(Condition.DEAD)) { HealthComponent health = creature.getHealthComponent(); health.heal(creature.getStatsComponent().getCon() / 100f); @@ -152,10 +150,11 @@ private boolean checkRegions() { // die boolean is eigenlijk maar louche RRegionTheme theme = r.getTheme(); r.fix(); // vanaf hier wordt theme null if (theme.id.startsWith("town")) { - new TownGenerator(zone, entityStore, resourceProvider) + new TownGenerator(zone, gameStores.getStore(), gameStores.getResources()) .generate(r.getX(), r.getY(), r.getWidth(), r.getHeight(), theme, r.getZ()); } else { - new WildernessGenerator(zone, entityStore, resourceProvider).generate(r, theme); + new WildernessGenerator(zone, gameStores) + .generate(r, theme); } } } @@ -167,13 +166,13 @@ private boolean checkRegions() { // die boolean is eigenlijk maar louche /* * @return a creature's speed */ - private static int getSpeed(Creature creature) { + private int getSpeed(Creature creature) { int penalty = 3; - if (InventoryHandler.getWeight(creature) > 9 * creature.species.str) { + if (inventoryHandler.getWeight(creature) > 9 * creature.species.str) { return 0; - } else if (InventoryHandler.getWeight(creature) > 6 * creature.species.str) { + } else if (inventoryHandler.getWeight(creature) > 6 * creature.species.str) { penalty = 1; - } else if (InventoryHandler.getWeight(creature) > 3 * creature.species.str) { + } else if (inventoryHandler.getWeight(creature) > 3 * creature.species.str) { penalty = 2; } return (creature.getStatsComponent().getSpd()) * penalty / 3; diff --git a/src/main/java/neon/editor/DataStore.java b/src/main/java/neon/editor/DataStore.java index 85e92de..dc227a0 100644 --- a/src/main/java/neon/editor/DataStore.java +++ b/src/main/java/neon/editor/DataStore.java @@ -22,38 +22,38 @@ import com.google.common.collect.Multimap; import java.io.File; import java.util.*; + +import lombok.Getter; import neon.editor.resources.RFaction; import neon.editor.resources.RMap; import neon.resources.*; import neon.resources.quest.RQuest; +import neon.systems.files.FileSystem; import neon.systems.files.StringTranslator; import neon.systems.files.XMLTranslator; import org.jdom2.Document; import org.jdom2.Element; public class DataStore { - private HashMap scripts = new HashMap(); - private Multimap events = ArrayListMultimap.create(); - private HashMap mods = new HashMap(); + @Getter + private final HashMap scripts = new HashMap(); + @Getter + private final Multimap events = ArrayListMultimap.create(); + private final HashMap mods = new HashMap(); + private final ResourceManager resourceManager; + private final FileSystem fileSystem; + @Getter private RMod active; - public RMod getActive() { - return active; + public DataStore(ResourceManager resourceManager, FileSystem fileSystem) { + this.resourceManager = resourceManager; + this.fileSystem = fileSystem; } - - public RMod getMod(String id) { + public RMod getMod(String id) { return mods.get(id); } - public HashMap getScripts() { - return scripts; - } - - public Multimap getEvents() { - return events; - } - - /** + /** * Loads all data from a mod. * *

NOTE (Phase 6 - Minimal Migration): Currently uses JDOM constructors for resource loading. @@ -95,7 +95,7 @@ public void loadData(String root, boolean active, boolean extension) { private void loadEvents(RMod mod, String... file) { try { for (Element event : - Editor.files.getFile(new XMLTranslator(), file).getRootElement().getChildren()) { + fileSystem.getFile(new XMLTranslator(), file).getRootElement().getChildren()) { events.put(event.getAttributeValue("script"), event.getAttributeValue("tick")); } } catch (NullPointerException e) { @@ -105,12 +105,12 @@ private void loadEvents(RMod mod, String... file) { private void loadScripts(RMod mod, String... file) { String[] path = new String[file.length + 1]; try { - for (String id : Editor.files.listFiles(file)) { + for (String id : fileSystem.listFiles(file)) { System.arraycopy(file, 0, path, 0, file.length); id = id.substring(id.lastIndexOf("/") + 1); id = id.substring(id.lastIndexOf(File.separator) + 1); path[file.length] = id; - String script = Editor.files.getFile(new StringTranslator(), path); + String script = fileSystem.getFile(new StringTranslator(), path); id = id.replace(".js", ""); scripts.put(id, new RScript(id, script, mod.get("id"))); } @@ -121,7 +121,7 @@ private void loadScripts(RMod mod, String... file) { private Element loadInfo(String... file) { Element info; try { - info = Editor.files.getFile(new XMLTranslator(), file).getRootElement(); + info = fileSystem.getFile(new XMLTranslator(), file).getRootElement(); info.detach(); } catch (NullPointerException e) { // file does not exist info = new Element("master"); @@ -135,7 +135,7 @@ private Element loadInfo(String... file) { private Element loadCC(String... file) { Element cc; try { - cc = Editor.files.getFile(new XMLTranslator(), file).getRootElement(); + cc = fileSystem.getFile(new XMLTranslator(), file).getRootElement(); cc.detach(); } catch (NullPointerException e) { // file does not exist cc = new Element("root"); @@ -150,14 +150,14 @@ private Element loadCC(String... file) { private void loadMaps(RMod mod, String... file) { String[] path = new String[file.length + 1]; try { - for (String s : Editor.files.listFiles(file)) { + for (String s : fileSystem.listFiles(file)) { System.arraycopy(file, 0, path, 0, file.length); // both substrings must be included for jars s = s.substring(s.lastIndexOf("/") + 1); s = s.substring(s.lastIndexOf(File.separator) + 1); path[file.length] = s; - Element map = Editor.files.getFile(new XMLTranslator(), path).getRootElement(); - Editor.resources.addResource(new RMap(s.replace(".xml", ""), map, mod.get("id")), "maps"); + Element map = fileSystem.getFile(new XMLTranslator(), path).getRootElement(); + resourceManager.addResource(new RMap(s.replace(".xml", ""), map,resourceManager, mod.get("id")), "maps"); } } catch (NullPointerException e) { } @@ -166,15 +166,15 @@ private void loadMaps(RMod mod, String... file) { private void loadQuests(RMod mod, String... file) { String[] path = new String[file.length + 1]; try { - Collection files = Editor.files.listFiles(file); + Collection files = fileSystem.listFiles(file); for (String quest : files) { System.arraycopy(file, 0, path, 0, file.length); quest = quest.substring(quest.lastIndexOf("/") + 1); quest = quest.substring(quest.lastIndexOf(File.separator) + 1); path[file.length] = quest; - Element root = Editor.files.getFile(new XMLTranslator(), path).getRootElement(); + Element root = fileSystem.getFile(new XMLTranslator(), path).getRootElement(); String id = quest.replace(".xml", ""); - Editor.resources.addResource(new RQuest(id, root, mod.get("id")), "quest"); + resourceManager.addResource(new RQuest(id, root, mod.get("id")), "quest"); } } catch (NullPointerException e) { } @@ -182,31 +182,17 @@ private void loadQuests(RMod mod, String... file) { private void loadMagic(RMod mod, String... path) { try { - Document doc = Editor.files.getFile(new XMLTranslator(), path); + Document doc = fileSystem.getFile(new XMLTranslator(), path); for (Element e : doc.getRootElement().getChildren()) { - switch (e.getName()) { - case "sign": - Editor.resources.addResource(new RSign(e, mod.get("id")), "magic"); - break; - case "tattoo": - Editor.resources.addResource(new RTattoo(e, mod.get("id")), "magic"); - break; - case "recipe": - Editor.resources.addResource(new RRecipe(e, mod.get("id")), "magic"); - break; - case "list": - Editor.resources.addResource(new LSpell(e, mod.get("id")), "magic"); - break; - case "power": - Editor.resources.addResource(new RSpell.Power(e, mod.get("id")), "magic"); - break; - case "enchant": - Editor.resources.addResource(new RSpell.Enchantment(e, mod.get("id")), "magic"); - break; - default: - Editor.resources.addResource(new RSpell(e, mod.get("id")), "magic"); - break; - } + switch (e.getName()) { + case "sign" -> resourceManager.addResource(new RSign(e, mod.get("id")), "magic"); + case "tattoo" -> resourceManager.addResource(new RTattoo(e, mod.get("id")), "magic"); + case "recipe" -> resourceManager.addResource(new RRecipe(e, mod.get("id")), "magic"); + case "list" -> resourceManager.addResource(new LSpell(e, mod.get("id")), "magic"); + case "power" -> resourceManager.addResource(new RSpell.Power(e, mod.get("id")), "magic"); + case "enchant" -> resourceManager.addResource(new RSpell.Enchantment(e, mod.get("id")), "magic"); + default -> resourceManager.addResource(new RSpell(e, mod.get("id")), "magic"); + } } } catch (NullPointerException e) { } @@ -214,21 +200,14 @@ private void loadMagic(RMod mod, String... path) { private void loadCreatures(RMod mod, String... path) { try { - Document doc = Editor.files.getFile(new XMLTranslator(), path); + Document doc = fileSystem.getFile(new XMLTranslator(), path); for (Element e : doc.getRootElement().getChildren()) { - switch (e.getName()) { - case "list": - Editor.resources.addResource(new LCreature(e, mod.get("id"))); - break; - case "npc": - Editor.resources.addResource(new RPerson(e, mod.get("id"))); - break; - case "group": - break; - default: - Editor.resources.addResource(new RCreature(e, mod.get("id"))); - break; - } + switch (e.getName()) { + case "list" -> resourceManager.addResource(new LCreature(e, mod.get("id"))); + case "npc" -> resourceManager.addResource(new RPerson(e, mod.get("id"))); + case "group" -> {} + default -> resourceManager.addResource(new RCreature(e, mod.get("id"))); + } } } catch (NullPointerException e) { e.printStackTrace(); @@ -237,9 +216,9 @@ private void loadCreatures(RMod mod, String... path) { private void loadFactions(RMod mod, String... path) { try { - Document doc = Editor.files.getFile(new XMLTranslator(), path); + Document doc = fileSystem.getFile(new XMLTranslator(), path); for (Element e : doc.getRootElement().getChildren()) { - Editor.resources.addResource(new RFaction(e, mod.get("id")), "faction"); + resourceManager.addResource(new RFaction(e, mod.get("id")), "faction"); } } catch (NullPointerException e) { } @@ -247,9 +226,9 @@ private void loadFactions(RMod mod, String... path) { private void loadTerrain(RMod mod, String... path) { try { - Document doc = Editor.files.getFile(new XMLTranslator(), path); + Document doc = fileSystem.getFile(new XMLTranslator(), path); for (Element e : doc.getRootElement().getChildren()) { - Editor.resources.addResource(new RTerrain(e, mod.get("id")), "terrain"); + resourceManager.addResource(new RTerrain(e, mod.get("id")), "terrain"); } } catch (NullPointerException e) { } @@ -257,39 +236,19 @@ private void loadTerrain(RMod mod, String... path) { private void loadItems(RMod mod, String... path) { try { - Document doc = Editor.files.getFile(new XMLTranslator(), path); + Document doc = fileSystem.getFile(new XMLTranslator(), path); for (Element e : doc.getRootElement().getChildren()) { - switch (e.getName()) { - case "list": - Editor.resources.addResource(new LItem(e, mod.get("id"))); - break; - case "book": - case "scroll": - Editor.resources.addResource(new RItem.Text(e, mod.get("id"))); - break; - case "armor": - case "clothing": - Editor.resources.addResource(new RClothing(e, mod.get("id"))); - break; - case "weapon": - Editor.resources.addResource(new RWeapon(e, mod.get("id"))); - break; - case "craft": - Editor.resources.addResource(new RCraft(e, mod.get("id"))); - break; - case "door": - Editor.resources.addResource(new RItem.Door(e, mod.get("id"))); - break; - case "potion": - Editor.resources.addResource(new RItem.Potion(e, mod.get("id"))); - break; - case "container": - Editor.resources.addResource(new RItem.Container(e, mod.get("id"))); - break; - default: - Editor.resources.addResource(new RItem(e, mod.get("id"))); - break; - } + switch (e.getName()) { + case "list" -> resourceManager.addResource(new LItem(e, mod.get("id"))); + case "book", "scroll" -> resourceManager.addResource(new RItem.Text(e, mod.get("id"))); + case "armor", "clothing" -> resourceManager.addResource(new RClothing(e, mod.get("id"))); + case "weapon" -> resourceManager.addResource(new RWeapon(e, mod.get("id"))); + case "craft" -> resourceManager.addResource(new RCraft(e, mod.get("id"))); + case "door" -> resourceManager.addResource(new RItem.Door(e, mod.get("id"))); + case "potion" -> resourceManager.addResource(new RItem.Potion(e, mod.get("id"))); + case "container" -> resourceManager.addResource(new RItem.Container(e, mod.get("id"))); + default -> resourceManager.addResource(new RItem(e, mod.get("id"))); + } } } catch (NullPointerException e) { } @@ -297,19 +256,13 @@ private void loadItems(RMod mod, String... path) { private void loadThemes(RMod mod, String... path) { try { - Document doc = Editor.files.getFile(new XMLTranslator(), path); + Document doc = fileSystem.getFile(new XMLTranslator(), path); for (Element e : doc.getRootElement().getChildren()) { - switch (e.getName()) { - case "dungeon": - Editor.resources.addResource(new RDungeonTheme(e, mod.get("id")), "theme"); - break; - case "region": - Editor.resources.addResource(new RRegionTheme(e, mod.get("id")), "theme"); - break; - case "zone": - Editor.resources.addResource(new RZoneTheme(e, mod.get("id")), "theme"); - break; - } + switch (e.getName()) { + case "dungeon" -> resourceManager.addResource(new RDungeonTheme(e, mod.get("id")), "theme"); + case "region" -> resourceManager.addResource(new RRegionTheme(e, mod.get("id")), "theme"); + case "zone" -> resourceManager.addResource(new RZoneTheme(e, mod.get("id")), "theme"); + } } } catch (NullPointerException e) { } diff --git a/src/main/java/neon/editor/Editor.java b/src/main/java/neon/editor/Editor.java index f791b7f..fdf66db 100644 --- a/src/main/java/neon/editor/Editor.java +++ b/src/main/java/neon/editor/Editor.java @@ -39,8 +39,8 @@ // TODO: use mbassador for events public class Editor implements Runnable, ActionListener { public static JCheckBoxMenuItem tShow, tEdit, oShow, oEdit; - public static FileSystem files; - public static final ResourceManager resources = new ResourceManager(); + private final FileSystem files; + private final ResourceManager resources; private static JFrame frame; private static DataStore store; private static JPanel toolPanel; @@ -83,7 +83,8 @@ public Editor() throws IOException { // stuff files = new FileSystem(); - store = new DataStore(); + resources = new ResourceManager(); + store = new DataStore(resources,files); // menu bar menuBar = new JMenuBar(); @@ -203,7 +204,7 @@ public Editor() throws IOException { // panels with maps mapTabbedPane = new JTabbedPane(); JPanel mapPanel = new JPanel(new BorderLayout()); - mapEditor = new MapEditor(mapTabbedPane, mapPanel); + mapEditor = new MapEditor(mapTabbedPane, mapPanel,resources); // panel with objects and terrain JTabbedPane editPanel = new JTabbedPane(); diff --git a/src/main/java/neon/editor/maps/MapEditor.java b/src/main/java/neon/editor/maps/MapEditor.java index 8af7259..1792b91 100644 --- a/src/main/java/neon/editor/maps/MapEditor.java +++ b/src/main/java/neon/editor/maps/MapEditor.java @@ -33,6 +33,7 @@ import neon.editor.resources.Instance; import neon.editor.resources.RMap; import neon.editor.resources.RZone; +import neon.resources.ResourceManager; public class MapEditor { private static String terrain; @@ -47,9 +48,10 @@ public class MapEditor { private JTabbedPane tabs; private JCheckBox levelBox; private JSpinner levelSpinner; - - public MapEditor(JTabbedPane tabs, JPanel panel) { - activeMaps = new HashSet(); + private final ResourceManager resourceManager; + public MapEditor(JTabbedPane tabs, JPanel panel, ResourceManager resourceManager) { + this.resourceManager = resourceManager; + activeMaps = new HashSet(); mapUIDs = new HashMap(); this.tabs = tabs; @@ -135,14 +137,14 @@ public static boolean drawMode() { public void deleteMap(String id) { // TODO: activeMaps is , not ! activeMaps.remove(id); - Editor.resources.removeResource(id); + resourceManager.removeResource(id); } public void makeMap(MapDialog.Properties props) { if (!props.cancelled()) { // editableMap maken short uid = createNewUID(); - RMap map = new RMap(uid, Editor.getStore().getActive().get("id"), props); + RMap map = new RMap(uid, Editor.getStore().getActive().get("id"), props,resourceManager); activeMaps.add(map); // en node maken DefaultTreeModel model = (DefaultTreeModel) mapTree.getModel(); @@ -153,7 +155,7 @@ public void makeMap(MapDialog.Properties props) { } model.insertNodeInto(node, root, root.getChildCount()); mapTree.expandPath(new TreePath(root)); - Editor.resources.addResource(map, "maps"); + resourceManager.addResource(map, "maps"); } } diff --git a/src/main/java/neon/editor/resources/Instance.java b/src/main/java/neon/editor/resources/Instance.java index 532176f..60963ec 100644 --- a/src/main/java/neon/editor/resources/Instance.java +++ b/src/main/java/neon/editor/resources/Instance.java @@ -31,9 +31,9 @@ import org.jdom2.Element; public abstract class Instance implements Renderable { - private static AlphaComposite alphaOn = + private static final AlphaComposite alphaOn = AlphaComposite.getInstance(AlphaComposite.SRC_OVER).derive(0.5f); - private static AlphaComposite alphaOff = AlphaComposite.getInstance(AlphaComposite.SRC); + private static final AlphaComposite alphaOff = AlphaComposite.getInstance(AlphaComposite.SRC); public int x, y, z, width, height; public RData resource; diff --git a/src/main/java/neon/editor/resources/RMap.java b/src/main/java/neon/editor/resources/RMap.java index d4f893a..5fb3618 100644 --- a/src/main/java/neon/editor/resources/RMap.java +++ b/src/main/java/neon/editor/resources/RMap.java @@ -26,6 +26,7 @@ import neon.resources.RData; import neon.resources.RDungeonTheme; import neon.resources.RScript; +import neon.resources.ResourceManager; import neon.systems.files.XMLTranslator; import neon.ui.graphics.Renderable; import org.jdom2.*; @@ -48,12 +49,14 @@ public class RMap extends RData { public short uid; private boolean type; private ArrayList uids; + private final ResourceManager resourceManager; // for already existing maps during loadMod - public RMap(String id, Element properties, String... path) { + public RMap(String id, Element properties, ResourceManager resourceManager, String... path) { super(id, path); uid = Short.parseShort(properties.getChild("header").getAttributeValue("uid")); - name = properties.getChild("header").getChildText("name"); + this.resourceManager = resourceManager; + name = properties.getChild("header").getChildText("name"); type = properties.getName().equals("dungeon"); if (type == DUNGEON) { @@ -73,11 +76,12 @@ public RMap(String id, Element properties, String... path) { } // for new maps to be created - public RMap(short uid, String mod, MapDialog.Properties props) { + public RMap(short uid, String mod, MapDialog.Properties props, ResourceManager resourceManager) { super(props.getID(), mod); this.uid = uid; type = props.isDungeon(); - name = props.getName(); + this.resourceManager = resourceManager; + name = props.getName(); if (!props.isDungeon()) { // always set zone and base region for outdoor Element region = new Element("region"); diff --git a/src/main/java/neon/entities/EntityFactory.java b/src/main/java/neon/entities/EntityFactory.java index 227cede..01594ee 100644 --- a/src/main/java/neon/entities/EntityFactory.java +++ b/src/main/java/neon/entities/EntityFactory.java @@ -21,7 +21,6 @@ import java.awt.Rectangle; import java.util.*; import neon.ai.*; -import neon.core.Engine; import neon.core.handlers.InventoryHandler; import neon.entities.components.Enchantment; import neon.entities.components.FactionComponent; @@ -35,23 +34,34 @@ import neon.util.Dice; public class EntityFactory { - private static AIFactory aiFactory = new AIFactory(); + private final AIFactory aiFactory = new AIFactory(); - public static Item getItem(String id, long uid) { + private final InventoryHandler inventoryHandler; + private final UIDStore uidStore; + private final ResourceManager resourceManager; + private final SpellFactory spellFactory; + + public EntityFactory(UIDStore uidStore, ResourceManager resourceManager) { + this.uidStore = uidStore; + this.resourceManager = resourceManager; + inventoryHandler = new InventoryHandler(uidStore); + spellFactory = new SpellFactory(resourceManager); + } + + public Item getItem(String id, long uid) { Item item = getItem(id, -1, -1, uid); return item; } - public static Item getItem(String id, int x, int y, long uid) { + public Item getItem(String id, int x, int y, long uid) { // item aanmaken RItem resource; - if (Engine.getResources().getResource(id) instanceof LItem) { - LItem li = (LItem) Engine.getResources().getResource(id); + if (resourceManager.getResource(id) instanceof LItem) { + LItem li = (LItem) resourceManager.getResource(id); ArrayList items = new ArrayList(li.items.keySet()); - resource = - (RItem) Engine.getResources().getResource(items.get(Dice.roll(1, items.size(), -1))); + resource = (RItem) resourceManager.getResource(items.get(Dice.roll(1, items.size(), -1))); } else { - resource = (RItem) Engine.getResources().getResource(id); + resource = (RItem) resourceManager.getResource(id); } Item item = getItem(resource, uid); @@ -77,7 +87,7 @@ public static Item getItem(String id, int x, int y, long uid) { mana = ((RWeapon) resource).mana; } item.setMagicComponent( - new Enchantment(SpellFactory.getSpell(resource.spell), mana, item.getUID())); + new Enchantment(spellFactory.getSpell(resource.spell), mana, item.getUID())); } return item; @@ -85,42 +95,29 @@ public static Item getItem(String id, int x, int y, long uid) { private static Item getItem(RItem resource, long uid) { // item aanmaken - switch (resource.type) { - case container: - return new Container(uid, (RItem.Container) resource); - case food: - return new Item.Food(uid, resource); - case aid: - return new Item.Aid(uid, resource); - case book: - return new Item.Book(uid, (RItem.Text) resource); - case clothing: - return new Clothing(uid, (RClothing) resource); - case armor: - return new Armor(uid, (RClothing) resource); - case coin: - return new Item.Coin(uid, resource); - case door: - return new Door(uid, resource); - case light: - return new Item.Light(uid, resource); - case potion: - return new Item.Potion(uid, resource); - case scroll: - return new Item.Scroll(uid, (RItem.Text) resource); - case weapon: - return new Weapon(uid, (RWeapon) resource); - default: - return new Item(uid, resource); - } + return switch (resource.type) { + case container -> new Container(uid, (RItem.Container) resource); + case food -> new Item.Food(uid, resource); + case aid -> new Item.Aid(uid, resource); + case book -> new Item.Book(uid, (RItem.Text) resource); + case clothing -> new Clothing(uid, (RClothing) resource); + case armor -> new Armor(uid, (RClothing) resource); + case coin -> new Item.Coin(uid, resource); + case door -> new Door(uid, resource); + case light -> new Item.Light(uid, resource); + case potion -> new Item.Potion(uid, resource); + case scroll -> new Item.Scroll(uid, (RItem.Text) resource); + case weapon -> new Weapon(uid, (RWeapon) resource); + default -> new Item(uid, resource); + }; } /* * Returns a person with the given uid, position and properties. */ - private static Creature getPerson(String id, int x, int y, long uid, RCreature species) { + private Creature getPerson(String id, int x, int y, long uid, RCreature species) { String name = id; - RPerson person = (RPerson) Engine.getResources().getResource(id); + RPerson person = (RPerson) resourceManager.getResource(id); if (person.name != null) { name = person.name; } @@ -128,13 +125,13 @@ private static Creature getPerson(String id, int x, int y, long uid, RCreature s Rectangle bounds = creature.getShapeComponent(); bounds.setLocation(x, y); for (String i : person.items) { - long itemUID = Engine.getStore().createNewEntityUID(); - Item item = EntityFactory.getItem(i, itemUID); - Engine.getStore().addEntity(item); - InventoryHandler.addItem(creature, itemUID); + long itemUID = uidStore.createNewEntityUID(); + Item item = getItem(i, itemUID); + uidStore.addEntity(item); + inventoryHandler.addItem(creature, itemUID); } for (String s : person.spells) { - creature.getMagicComponent().addSpell(neon.magic.SpellFactory.getSpell(s)); + creature.getMagicComponent().addSpell(spellFactory.getSpell(s)); } FactionComponent factions = creature.getFactionComponent(); for (String f : person.factions.keySet()) { @@ -146,12 +143,12 @@ private static Creature getPerson(String id, int x, int y, long uid, RCreature s return creature; } - public static Creature getCreature(String id, int x, int y, long uid) { + public Creature getCreature(String id, int x, int y, long uid) { Creature creature; - Resource resource = Engine.getResources().getResource(id); + Resource resource = resourceManager.getResource(id); if (resource instanceof RPerson) { RPerson rp = (RPerson) resource; - RCreature species = (RCreature) Engine.getResources().getResource(rp.species); + RCreature species = (RCreature) resourceManager.getResource(rp.species); creature = getPerson(id, x, y, uid, species); creature.brain = aiFactory.getAI(creature, rp); } else if (resource instanceof LCreature) { @@ -159,27 +156,15 @@ public static Creature getCreature(String id, int x, int y, long uid) { ArrayList creatures = new ArrayList(lc.creatures.keySet()); return getCreature(creatures.get(Dice.roll(1, creatures.size(), -1)), x, y, uid); } else { - RCreature rc = (RCreature) Engine.getResources().getResource(id); - switch (rc.type) { - case construct: - creature = new Construct(id, uid, rc); - break; - case humanoid: - creature = new Hominid(id, uid, rc); - break; - case daemon: - creature = new Daemon(id, uid, rc); - break; - case dragon: - creature = new Dragon(id, uid, rc); - break; - case goblin: - creature = new Hominid(id, uid, rc); - break; - default: - creature = new Creature(id, uid, rc); - break; - } + RCreature rc = (RCreature) resourceManager.getResource(id); + creature = + switch (rc.type) { + case construct -> new Construct(id, uid, rc); + case humanoid, goblin -> new Hominid(id, uid, rc); + case daemon -> new Daemon(id, uid, rc); + case dragon -> new Dragon(id, uid, rc); + default -> new Creature(id, uid, rc); + }; // positie Rectangle bounds = creature.getShapeComponent(); diff --git a/src/main/java/neon/entities/Player.java b/src/main/java/neon/entities/Player.java index 6d8c67d..f508cc5 100644 --- a/src/main/java/neon/entities/Player.java +++ b/src/main/java/neon/entities/Player.java @@ -19,7 +19,7 @@ package neon.entities; import java.util.EnumMap; -import neon.core.Engine; +import neon.core.GameStores; import neon.core.handlers.SkillHandler; import neon.entities.components.Inventory; import neon.entities.components.Lock; @@ -41,10 +41,17 @@ public class Player extends Hominid { private String sign; private boolean sneak = false; private Creature mount; + private final GameStores gameStores; public Player( - RCreature species, String name, Gender gender, Specialisation spec, String profession) { + RCreature species, + String name, + Gender gender, + Specialisation spec, + String profession, + GameStores gameStores) { super(species.id, 0, species); + this.gameStores = gameStores; components.putInstance(RenderComponent.class, new PlayerRenderComponent(this)); this.name = name; this.gender = gender; @@ -86,15 +93,15 @@ public String getAVString() { String damage; if (inventory.hasEquiped(Slot.WEAPON)) { - Weapon weapon = (Weapon) Engine.getStore().getEntity(inventory.get(Slot.WEAPON)); + Weapon weapon = (Weapon) gameStores.getStore().getEntity(inventory.get(Slot.WEAPON)); damage = weapon.getDamage(); if (weapon.getWeaponType().equals(WeaponType.BOW) || weapon.getWeaponType().equals(WeaponType.CROSSBOW)) { - Weapon ammo = (Weapon) Engine.getStore().getEntity(inventory.get(Slot.AMMO)); + Weapon ammo = (Weapon) gameStores.getStore().getEntity(inventory.get(Slot.AMMO)); damage += " : " + ammo.getDamage(); } } else if (inventory.hasEquiped(Slot.AMMO)) { - Weapon ammo = (Weapon) Engine.getStore().getEntity(inventory.get(Slot.AMMO)); + Weapon ammo = (Weapon) gameStores.getStore().getEntity(inventory.get(Slot.AMMO)); damage = ammo.getDamage(); } else { damage = species.av; diff --git a/src/main/java/neon/entities/components/Portal.java b/src/main/java/neon/entities/components/Portal.java index 4a503b0..20a36be 100644 --- a/src/main/java/neon/entities/components/Portal.java +++ b/src/main/java/neon/entities/components/Portal.java @@ -19,12 +19,19 @@ package neon.entities.components; import java.awt.Point; + +import lombok.Getter; +import lombok.Setter; import neon.maps.Map; public class Portal implements Component { private int destMapUID = -1; // -1 is zelfde map - private Point destPos; - private int destZone = -1; // -1 is zelfde zone + @Setter + @Getter + private Point destPos; + + @Setter + private int destZone = -1; // -1 is zelfde zone private String theme; private long uid; @@ -70,39 +77,14 @@ public void setDestMap(int map) { destMapUID = map; } - /** - * @return the destination position - */ - public Point getDestPos() { - return destPos; - } - - /** + /** * @return the dungeon level this portal leads to */ public Integer getDestZone() { return destZone; } - /** - * Sets the destination zone of this door. - * - * @param zone the index of the destination zone - */ - public void setDestZone(int zone) { - destZone = zone; - } - - /** - * Sets the destination position of this door. - * - * @param p the destination position - */ - public void setDestPos(Point p) { - destPos = p; - } - - /** + /** * @return the theme of the dungeon this door leads to */ public String getDestTheme() { diff --git a/src/main/java/neon/entities/serialization/CreatureSerializer.java b/src/main/java/neon/entities/serialization/CreatureSerializer.java index 2a71dd3..4038449 100644 --- a/src/main/java/neon/entities/serialization/CreatureSerializer.java +++ b/src/main/java/neon/entities/serialization/CreatureSerializer.java @@ -24,6 +24,7 @@ import java.io.IOException; import neon.ai.AIFactory; import neon.core.Engine; +import neon.core.GameStores; import neon.entities.Construct; import neon.entities.Creature; import neon.entities.Daemon; @@ -33,12 +34,18 @@ import neon.entities.property.Slot; import neon.magic.SpellFactory; import neon.resources.RCreature; +import neon.resources.ResourceManager; // TODO: factions public class CreatureSerializer { private static final long serialVersionUID = -2452444993764883434L; - private static AIFactory aiFactory = new AIFactory(); - + private final AIFactory aiFactory = new AIFactory(); + private final SpellFactory spellFactory; + private final ResourceManager resourceManager; + public CreatureSerializer(GameStores gameStores) { + spellFactory = new SpellFactory(gameStores.getResources()); + resourceManager = gameStores.getResources(); + } public Creature deserialize(DataInput in) throws IOException { String id = in.readUTF(); String species = in.readUTF(); @@ -59,7 +66,7 @@ public Creature deserialize(DataInput in) throws IOException { creature.getMagicComponent().setModifier(in.readFloat()); String spell = in.readUTF(); if (!spell.isEmpty()) { - creature.getMagicComponent().equipSpell(SpellFactory.getSpell(spell)); + creature.getMagicComponent().equipSpell(spellFactory.getSpell(spell)); } int date = in.readInt(); @@ -127,27 +134,15 @@ public void serialize(DataOutput out, Creature creature) throws IOException { private Creature getCreature(String id, int x, int y, long uid, String species) { Creature creature; - RCreature rc = (RCreature) Engine.getResources().getResource(species); - switch (rc.type) { - case construct: - creature = new Construct(id, uid, rc); - break; - case humanoid: - creature = new Hominid(id, uid, rc); - break; - case daemon: - creature = new Daemon(id, uid, rc); - break; - case dragon: - creature = new Dragon(id, uid, rc); - break; - case goblin: - creature = new Hominid(id, uid, rc); - break; - default: - creature = new Creature(id, uid, rc); - break; - } + RCreature rc = (RCreature) resourceManager.getResource(species); + creature = switch (rc.type) { + case construct -> new Construct(id, uid, rc); + case humanoid -> new Hominid(id, uid, rc); + case daemon -> new Daemon(id, uid, rc); + case dragon -> new Dragon(id, uid, rc); + case goblin -> new Hominid(id, uid, rc); + default -> new Creature(id, uid, rc); + }; return creature; } diff --git a/src/main/java/neon/entities/serialization/EntitySerializer.java b/src/main/java/neon/entities/serialization/EntitySerializer.java index 8860ad7..63df1e4 100644 --- a/src/main/java/neon/entities/serialization/EntitySerializer.java +++ b/src/main/java/neon/entities/serialization/EntitySerializer.java @@ -21,24 +21,28 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; + +import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Entity; import neon.entities.Item; public class EntitySerializer { - private static final long serialVersionUID = 4682346337753485512L; - private ItemSerializer itemSerializer = new ItemSerializer(); - private CreatureSerializer creatureSerializer = new CreatureSerializer(); + + private final ItemSerializer itemSerializer; + private final CreatureSerializer creatureSerializer; + + EntitySerializer(GameStores gameStores) { + itemSerializer = new ItemSerializer(gameStores); + creatureSerializer = new CreatureSerializer(gameStores); + } public Entity deserialize(DataInput input) throws IOException { - switch (input.readUTF()) { - case "item": - return itemSerializer.deserialize(input); - case "creature": - return creatureSerializer.deserialize(input); - default: - return null; - } + return switch (input.readUTF()) { + case "item" -> itemSerializer.deserialize(input); + case "creature" -> creatureSerializer.deserialize(input); + default -> null; + }; } public void serialize(DataOutput output, Entity entity) throws IOException { diff --git a/src/main/java/neon/entities/serialization/ItemSerializer.java b/src/main/java/neon/entities/serialization/ItemSerializer.java index cdacbd7..4493f2e 100644 --- a/src/main/java/neon/entities/serialization/ItemSerializer.java +++ b/src/main/java/neon/entities/serialization/ItemSerializer.java @@ -24,6 +24,7 @@ import java.io.DataOutput; import java.io.IOException; import neon.core.Engine; +import neon.core.GameStores; import neon.entities.Armor; import neon.entities.Container; import neon.entities.Door; @@ -44,14 +45,22 @@ */ public class ItemSerializer { private static final long serialVersionUID = 2138679015831709732L; + private final GameStores gameStores; + private final EntityFactory entityFactory; + private final SpellFactory spellFactory; + public ItemSerializer(GameStores gameStores) { + this.gameStores = gameStores; + entityFactory = new EntityFactory(gameStores.getStore(),gameStores.getResources()); + spellFactory= new SpellFactory(gameStores.getResources()); + } - public Item deserialize(DataInput input) throws IOException { + public Item deserialize(DataInput input) throws IOException { // item aanmaken String id = input.readUTF(); long uid = input.readLong(); int x = input.readInt(); int y = input.readInt(); - Item item = EntityFactory.getItem(id, x, y, uid); + Item item = entityFactory.getItem(id, x, y, uid); item.setOwner(input.readLong()); if (input.readBoolean()) { @@ -116,7 +125,7 @@ private void readEnchantment(DataInput input, Item item, long uid) throws IOExce String id = input.readUTF(); int mana = input.readInt(); float modifier = input.readFloat(); - Enchantment enchantment = new Enchantment(SpellFactory.getSpell(id), mana, uid); + Enchantment enchantment = new Enchantment(spellFactory.getSpell(id), mana, uid); enchantment.setModifier(modifier); item.setMagicComponent(enchantment); } @@ -183,7 +192,7 @@ private void readLock(DataInput input, Lock lock) throws IOException { lock.setState(input.readInt()); String id = input.readUTF(); if (!id.isEmpty()) { - lock.setKey((RItem) Engine.getResources().getResource(id)); + lock.setKey((RItem) gameStores.getResources().getResource(id)); } } diff --git a/src/main/java/neon/magic/SpellFactory.java b/src/main/java/neon/magic/SpellFactory.java index e362fbd..37bafe6 100644 --- a/src/main/java/neon/magic/SpellFactory.java +++ b/src/main/java/neon/magic/SpellFactory.java @@ -18,9 +18,9 @@ package neon.magic; -import neon.core.Engine; import neon.resources.LSpell; import neon.resources.RSpell; +import neon.resources.ResourceManager; import neon.util.Dice; /** @@ -29,18 +29,24 @@ * @author mdriesen */ public class SpellFactory { + private final ResourceManager resourceManager; + + public SpellFactory(ResourceManager resourceManager) { + this.resourceManager = resourceManager; + } + /** * Returns the spell with the given id. * * @param id the id of the requested spell * @return the spell with the given id */ - public static RSpell getSpell(String id) { - if (Engine.getResources().getResource(id, "magic") instanceof LSpell) { - LSpell ls = (LSpell) Engine.getResources().getResource(id, "magic"); + public RSpell getSpell(String id) { + if (resourceManager.getResource(id, "magic") instanceof LSpell) { + LSpell ls = (LSpell) resourceManager.getResource(id, "magic"); return getSpell(ls.spells.keySet().toArray()[Dice.roll(1, ls.spells.size(), -1)].toString()); } else { - return (RSpell) Engine.getResources().getResource(id, "magic"); + return (RSpell) resourceManager.getResource(id, "magic"); } } @@ -50,9 +56,9 @@ public static RSpell getSpell(String id) { * @param id the id of the requested enchantment * @return the enchantment with the given id */ - public static RSpell.Enchantment getEnchantment(String id) { - if (Engine.getResources().getResource(id, "magic") instanceof RSpell.Enchantment) { - return (RSpell.Enchantment) Engine.getResources().getResource(id, "magic"); + public RSpell.Enchantment getEnchantment(String id) { + if (resourceManager.getResource(id, "magic") instanceof RSpell.Enchantment) { + return (RSpell.Enchantment) resourceManager.getResource(id, "magic"); } else { throw new IllegalArgumentException("The given id (" + id + ") is not an enchantment."); } diff --git a/src/main/java/neon/maps/Atlas.java b/src/main/java/neon/maps/Atlas.java index 785a83c..8bda30d 100644 --- a/src/main/java/neon/maps/Atlas.java +++ b/src/main/java/neon/maps/Atlas.java @@ -43,7 +43,7 @@ public class Atlas implements Closeable, MapAtlas { private final MapLoader mapLoader; public Atlas( - FileSystem fileSystem, MapStore mapStore, EntityStore entityStore, MapLoader mapLoader) { + FileSystem fileSystem, MapStore mapStore, EntityStore entityStore, MapLoader mapLoader) { this.fileSystem = fileSystem; this.entityStore = entityStore; this.db = mapStore; @@ -68,7 +68,7 @@ public Atlas(FileSystem fileSystem, String path, EntityStore entityStore, MapLoa maps = db.openMap("maps"); } - private MapStore getMapStore(FileSystem files, String fileName) { + public static MapStore getMapStore(FileSystem files, String fileName) { files.delete(fileName); log.warn("Creating new MVStore at {}", fileName); diff --git a/src/main/java/neon/maps/AtlasPosition.java b/src/main/java/neon/maps/AtlasPosition.java index fb42e20..5287f76 100644 --- a/src/main/java/neon/maps/AtlasPosition.java +++ b/src/main/java/neon/maps/AtlasPosition.java @@ -2,13 +2,15 @@ import neon.entities.Door; import neon.entities.Player; +import neon.entities.UIDStore; import neon.maps.generators.DungeonGenerator; import neon.maps.services.EntityStore; -import neon.maps.services.PhysicsManager; import neon.maps.services.QuestProvider; import neon.narrative.QuestTracker; import neon.resources.ResourceManager; +import java.rmi.server.UID; + public class AtlasPosition { private int currentZone = 0; private int currentMap = 0; @@ -16,14 +18,14 @@ public class AtlasPosition { private final ZoneActivator zoneActivator; private final ResourceManager resourceProvider; private final QuestTracker questProvider; - private final EntityStore entityStore; + private final UIDStore entityStore; public AtlasPosition( Atlas atlas, ZoneActivator zoneActivator, ResourceManager resourceProvider, QuestTracker questProvider, - EntityStore entityStore) { + UIDStore entityStore) { this.atlas = atlas; this.zoneActivator = zoneActivator; this.resourceProvider = resourceProvider; @@ -31,15 +33,6 @@ public AtlasPosition( this.entityStore = entityStore; } - /** - * Creates a default zone activator using Engine singleton (for backward compatibility). - * - * @return a zone activator - */ - static ZoneActivator createDefaultZoneActivator(PhysicsManager physicsManager) { - return new ZoneActivator(physicsManager); - } - /** * @return the current map */ diff --git a/src/main/java/neon/maps/Dungeon.java b/src/main/java/neon/maps/Dungeon.java index 6f39974..62f1595 100644 --- a/src/main/java/neon/maps/Dungeon.java +++ b/src/main/java/neon/maps/Dungeon.java @@ -22,6 +22,9 @@ import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Collection; + +import lombok.Getter; +import lombok.Setter; import neon.resources.RZoneTheme; import neon.util.Graph; @@ -31,19 +34,22 @@ * @author mdriesen */ public class Dungeon implements Map { + @Setter + @Getter private String name; private int uid; private Graph zones = new Graph(); - + private ZoneFactory zoneFactory; /** * Initialize a dungeon. * * @param name the name of this dungeon * @param uid the unique identifier of this dungeon */ - public Dungeon(String name, int uid) { + public Dungeon(String name, int uid,ZoneFactory zoneFactory) { this.name = name; this.uid = uid; + this.zoneFactory = zoneFactory; } public Dungeon() {} @@ -56,22 +62,14 @@ public int getUID() { return uid; } - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - /** Adds an empty zone to this dungeon. */ + /** Adds an empty zone to this dungeon. */ public void addZone(int zone, String name) { - zones.addNode(zone, new Zone(name, uid, zone)); + zones.addNode(zone, zoneFactory.createZone(name, uid, zone)); } /** Adds an empty zone to this dungeon. */ public void addZone(int zone, String name, RZoneTheme theme) { - zones.addNode(zone, new Zone(name, uid, theme, zone)); + zones.addNode(zone, zoneFactory.createZoneWithTheme(name, uid, zone, theme)); } public Collection getZones() { diff --git a/src/main/java/neon/maps/MapLoader.java b/src/main/java/neon/maps/MapLoader.java index b01dea1..ccdedf1 100644 --- a/src/main/java/neon/maps/MapLoader.java +++ b/src/main/java/neon/maps/MapLoader.java @@ -21,7 +21,6 @@ import java.awt.Point; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.IOException; import neon.core.*; import neon.entities.Container; import neon.entities.Creature; @@ -33,16 +32,7 @@ import neon.entities.components.Lock; import neon.maps.model.DungeonModel; import neon.maps.model.WorldModel; -import neon.maps.services.EngineEntityStore; -import neon.maps.services.EngineResourceProvider; -import neon.maps.services.EntityStore; -import neon.maps.services.ResourceProvider; -import neon.resources.RDungeonTheme; -import neon.resources.RItem; -import neon.resources.RRegionTheme; -import neon.resources.RSpell; -import neon.resources.RTerrain; -import neon.resources.RZoneTheme; +import neon.resources.*; import neon.systems.files.FileSystem; import neon.systems.files.JacksonMapper; import neon.systems.files.XMLTranslator; @@ -58,47 +48,31 @@ * @author mdriesen */ public class MapLoader { - private final EntityStore entityStore; - private final ResourceProvider resourceProvider; private final MapUtils mapUtils; + private final UIDStore uidStore; + private final ResourceManager resourceManager; private final FileSystem fileSystem; - - /** - * Creates a MapLoader with dependency injection. - * - * @param entityStore the entity store service - * @param resourceProvider the resource provider service - */ - public MapLoader( - EntityStore entityStore, ResourceProvider resourceProvider, FileSystem fileSystem) { - this(entityStore, resourceProvider, new MapUtils(), fileSystem); + private final ZoneFactory zoneFactory; + /** Creates a MapLoader with dependency injection. */ + public MapLoader(FileSystem fileSystem, UIDStore uidStore, ResourceManager resourceManager, ZoneFactory zoneFactory) { + this(fileSystem, uidStore, resourceManager, new MapUtils(), zoneFactory); } /** * Creates a MapLoader with dependency injection and custom random source. * - * @param entityStore the entity store service - * @param resourceProvider the resource provider service * @param mapUtils the MapUtils instance for random operations */ public MapLoader( - EntityStore entityStore, - ResourceProvider resourceProvider, - MapUtils mapUtils, - FileSystem fileSystem) { - this.entityStore = entityStore; - this.resourceProvider = resourceProvider; - this.mapUtils = mapUtils; + FileSystem fileSystem, + UIDStore uidStore, + ResourceManager resourceManager, + MapUtils mapUtils, ZoneFactory zoneFactory) { this.fileSystem = fileSystem; - } - - /** - * Creates a MapLoader using Engine singletons (for backward compatibility). - * - * @return a new MapLoader instance - */ - private static MapLoader createDefault() throws IOException { - return new MapLoader(new EngineEntityStore(), new EngineResourceProvider(), new FileSystem()); + this.uidStore = uidStore; + this.resourceManager = resourceManager; + this.mapUtils = mapUtils; + this.zoneFactory = zoneFactory; } /** @@ -106,7 +80,6 @@ private static MapLoader createDefault() throws IOException { * * @param path the pathname of a map file * @param uid the unique identifier of this map - * @param files the file system * @return the Map described by the map file */ public Map load(@NotNull String[] path, int uid) { @@ -124,25 +97,6 @@ public Map load(@NotNull String[] path, int uid) { } } - /** - * Loads a dungeon behind a themed door. - * - * @param theme - * @return - */ - /** - * Loads a dungeon with a theme (static wrapper for backward compatibility). - * - * @param theme the theme ID - * @return a new Dungeon - * @deprecated Use instance method {@link #loadThemedDungeon(String, String, int)} instead - */ - @Deprecated - public static Dungeon loadDungeon(String theme) throws IOException { - MapLoader loader = createDefault(); - return loader.loadThemedDungeon(theme, theme, loader.entityStore.createNewMapUID()); - } - private World loadWorld(Element root, int uid) { try { // Convert JDOM Element to XML string @@ -181,9 +135,9 @@ private Dungeon loadDungeon(Element root, int uid) { } } - private Dungeon loadThemedDungeon(String name, String dungeon, int uid) { - Dungeon map = new Dungeon(name, uid); - RDungeonTheme theme = (RDungeonTheme) resourceProvider.getResource(dungeon, "theme"); + public Dungeon loadThemedDungeon(String name, String dungeonTheme, int uid) { + Dungeon map = new Dungeon(name, uid,zoneFactory); + RDungeonTheme theme = (RDungeonTheme) resourceManager.getResource(dungeonTheme, "theme"); int minZ = theme.min; int maxZ = theme.max; @@ -195,7 +149,7 @@ private Dungeon loadThemedDungeon(String name, String dungeon, int uid) { while (z > -1) { int t = mapUtils.random(0, types.length - 1); zones[z] = 1; - RZoneTheme rzt = (RZoneTheme) resourceProvider.getResource(types[t], "theme"); + RZoneTheme rzt = (RZoneTheme) resourceManager.getResource(types[t], "theme"); map.addZone(z, "zone " + z, rzt); z--; } @@ -221,7 +175,7 @@ private Dungeon loadThemedDungeon(String name, String dungeon, int uid) { private World buildWorldFromModel(WorldModel model, int uid) { World world = new World(model.header.name, uid); Zone zone = world.getZone(0); // outdoor maps have only zone 0 - + EntityFactory entityFactory = new EntityFactory(uidStore, resourceManager); // Add regions for (WorldModel.RegionData regionData : model.regions) { Region region = buildRegionFromModel(regionData); @@ -231,32 +185,32 @@ private World buildWorldFromModel(WorldModel model, int uid) { // Add creatures for (WorldModel.CreaturePlacement cp : model.creatures) { long creatureUID = UIDStore.getObjectUID(uid, cp.uid); - Creature creature = EntityFactory.getCreature(cp.id, cp.x, cp.y, creatureUID); - entityStore.addEntity(creature); + Creature creature = entityFactory.getCreature(cp.id, cp.x, cp.y, creatureUID); + uidStore.addEntity(creature); zone.addCreature(creature); } // Add items (simple items) for (WorldModel.ItemPlacement ip : model.items.items) { long itemUID = UIDStore.getObjectUID(uid, ip.uid); - Item item = EntityFactory.getItem(ip.id, ip.x, ip.y, itemUID); - entityStore.addEntity(item); + Item item = entityFactory.getItem(ip.id, ip.x, ip.y, itemUID); + uidStore.addEntity(item); zone.addItem(item); } // Add doors for (WorldModel.DoorPlacement dp : model.items.doors) { long doorUID = UIDStore.getObjectUID(uid, dp.uid); - Door door = buildDoorFromModel(dp, uid, doorUID); - entityStore.addEntity(door); + Door door = buildDoorFromModel(dp, uid, doorUID, entityFactory); + uidStore.addEntity(door); zone.addItem(door); } // Add containers for (WorldModel.ContainerPlacement cp : model.items.containers) { long containerUID = UIDStore.getObjectUID(uid, cp.uid); - Container container = buildContainerFromModel(cp, uid, containerUID); - entityStore.addEntity(container); + Container container = buildContainerFromModel(cp, uid, containerUID, entityFactory); + uidStore.addEntity(container); zone.addItem(container); } @@ -275,8 +229,8 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { if (model.header.theme != null) { return loadThemedDungeon(model.header.name, model.header.theme, uid); } - - Dungeon dungeon = new Dungeon(model.header.name, uid); + EntityFactory entityFactory = new EntityFactory(uidStore, resourceManager); + Dungeon dungeon = new Dungeon(model.header.name, uid,zoneFactory); for (DungeonModel.Level levelData : model.levels) { int level = levelData.l; @@ -284,7 +238,7 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { if (levelData.theme != null) { // Themed zone - add theme reference - RZoneTheme theme = (RZoneTheme) resourceProvider.getResource(levelData.theme, "theme"); + RZoneTheme theme = (RZoneTheme) resourceManager.getResource(levelData.theme, "theme"); dungeon.addZone(level, name, theme); if (levelData.out != null) { @@ -306,32 +260,32 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { // Add creatures for (WorldModel.CreaturePlacement cp : levelData.creatures) { long creatureUID = UIDStore.getObjectUID(uid, cp.uid); - Creature creature = EntityFactory.getCreature(cp.id, cp.x, cp.y, creatureUID); - entityStore.addEntity(creature); + Creature creature = entityFactory.getCreature(cp.id, cp.x, cp.y, creatureUID); + uidStore.addEntity(creature); zone.addCreature(creature); } // Add items for (WorldModel.ItemPlacement ip : levelData.items.items) { long itemUID = UIDStore.getObjectUID(uid, ip.uid); - Item item = EntityFactory.getItem(ip.id, ip.x, ip.y, itemUID); - entityStore.addEntity(item); + Item item = entityFactory.getItem(ip.id, ip.x, ip.y, itemUID); + uidStore.addEntity(item); zone.addItem(item); } // Add doors for (WorldModel.DoorPlacement dp : levelData.items.doors) { long doorUID = UIDStore.getObjectUID(uid, dp.uid); - Door door = buildDoorFromModel(dp, uid, doorUID); - entityStore.addEntity(door); + Door door = buildDoorFromModel(dp, uid, doorUID, entityFactory); + uidStore.addEntity(door); zone.addItem(door); } // Add containers for (WorldModel.ContainerPlacement cp : levelData.items.containers) { long containerUID = UIDStore.getObjectUID(uid, cp.uid); - Container container = buildContainerFromModel(cp, uid, containerUID); - entityStore.addEntity(container); + Container container = buildContainerFromModel(cp, uid, containerUID, entityFactory); + uidStore.addEntity(container); zone.addItem(container); } } @@ -347,8 +301,8 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { * @return the constructed Region */ private Region buildRegionFromModel(WorldModel.RegionData regionData) { - RTerrain terrain = (RTerrain) resourceProvider.getResource(regionData.text, "terrain"); - RRegionTheme theme = (RRegionTheme) resourceProvider.getResource(regionData.random, "theme"); + RTerrain terrain = (RTerrain) resourceManager.getResource(regionData.text, "terrain"); + RRegionTheme theme = (RRegionTheme) resourceManager.getResource(regionData.random, "theme"); Region region = new Region( @@ -378,8 +332,9 @@ private Region buildRegionFromModel(WorldModel.RegionData regionData) { * @param doorUID the door entity UID * @return the constructed Door */ - private Door buildDoorFromModel(WorldModel.DoorPlacement doorData, int mapUID, long doorUID) { - Door door = (Door) EntityFactory.getItem(doorData.id, doorData.x, doorData.y, doorUID); + private Door buildDoorFromModel( + WorldModel.DoorPlacement doorData, int mapUID, long doorUID, EntityFactory entityFactory) { + Door door = (Door) entityFactory.getItem(doorData.id, doorData.x, doorData.y, doorUID); // Lock if (doorData.lock != null) { @@ -388,7 +343,7 @@ private Door buildDoorFromModel(WorldModel.DoorPlacement doorData, int mapUID, l // Key if (doorData.key != null) { - RItem key = (RItem) resourceProvider.getResource(doorData.key); + RItem key = (RItem) resourceManager.getResource(doorData.key); door.lock.setKey(key); } @@ -413,7 +368,7 @@ private Door buildDoorFromModel(WorldModel.DoorPlacement doorData, int mapUID, l // Spell if (doorData.spell != null) { RSpell.Enchantment enchantment = - (RSpell.Enchantment) resourceProvider.getResource(doorData.spell, "magic"); + (RSpell.Enchantment) resourceManager.getResource(doorData.spell, "magic"); door.setMagicComponent(new Enchantment(enchantment, 0, door.getUID())); } @@ -451,10 +406,13 @@ private Door buildDoorFromModel(WorldModel.DoorPlacement doorData, int mapUID, l * @return the constructed Container */ private Container buildContainerFromModel( - WorldModel.ContainerPlacement containerData, int mapUID, long containerUID) { + WorldModel.ContainerPlacement containerData, + int mapUID, + long containerUID, + EntityFactory entityFactory) { Container container = (Container) - EntityFactory.getItem(containerData.id, containerData.x, containerData.y, containerUID); + entityFactory.getItem(containerData.id, containerData.x, containerData.y, containerUID); // Lock if (containerData.lock != null) { @@ -464,7 +422,7 @@ private Container buildContainerFromModel( // Key if (containerData.key != null) { - RItem key = (RItem) resourceProvider.getResource(containerData.key); + RItem key = (RItem) resourceManager.getResource(containerData.key); container.lock.setKey(key); } @@ -476,7 +434,7 @@ private Container buildContainerFromModel( // Spell if (containerData.spell != null) { RSpell.Enchantment enchantment = - (RSpell.Enchantment) resourceProvider.getResource(containerData.spell, "magic"); + (RSpell.Enchantment) resourceManager.getResource(containerData.spell, "magic"); container.setMagicComponent(new Enchantment(enchantment, 0, container.getUID())); } @@ -484,14 +442,14 @@ private Container buildContainerFromModel( if (!containerData.contents.isEmpty()) { for (WorldModel.ContainerPlacement.ContainerItem contentData : containerData.contents) { long contentUID = UIDStore.getObjectUID(mapUID, contentData.uid); - entityStore.addEntity(EntityFactory.getItem(contentData.id, contentUID)); + uidStore.addEntity(entityFactory.getItem(contentData.id, contentUID)); container.addItem(contentUID); } } else { // Default items from resource definition for (String itemId : ((RItem.Container) container.resource).contents) { - Item item = EntityFactory.getItem(itemId, entityStore.createNewEntityUID()); - entityStore.addEntity(item); + Item item = entityFactory.getItem(itemId, uidStore.createNewEntityUID()); + uidStore.addEntity(item); container.addItem(item.getUID()); } } @@ -499,7 +457,7 @@ private Container buildContainerFromModel( return container; } - private void loadZone(Element root, Map map, int l, int uid) { + private void loadZone(Element root, Map map, int l, int uid, EntityFactory entityFactory) { for (Element region : root.getChild("regions").getChildren()) { // load regions map.getZone(l).addRegion(loadRegion(region)); } @@ -509,8 +467,8 @@ private void loadZone(Element root, Map map, int l, int uid) { int x = Integer.parseInt(c.getAttributeValue("x")); int y = Integer.parseInt(c.getAttributeValue("y")); long creatureUID = UIDStore.getObjectUID(uid, Integer.parseInt(c.getAttributeValue("uid"))); - Creature creature = EntityFactory.getCreature(species, x, y, creatureUID); - entityStore.addEntity(creature); + Creature creature = entityFactory.getCreature(species, x, y, creatureUID); + uidStore.addEntity(creature); map.getZone(l).addCreature(creature); } } @@ -522,14 +480,18 @@ private void loadZone(Element root, Map map, int l, int uid) { int y = Integer.parseInt(i.getAttributeValue("y")); Item item = null; if (i.getName().equals("container")) { - item = loadContainer(i, id, x, y, itemUID, uid); // because containers are complicated + item = + loadContainer( + i, id, x, y, itemUID, uid, entityFactory); // because containers are complicated } else if (i.getName().equals("door")) { - item = loadDoor(i, id, x, y, itemUID, uid); // because doors are complicated too + item = + loadDoor( + i, id, x, y, itemUID, uid, entityFactory); // because doors are complicated too } else { - item = EntityFactory.getItem(id, x, y, itemUID); + item = entityFactory.getItem(id, x, y, itemUID); } map.getZone(l).addItem(item); - entityStore.addEntity(item); + uidStore.addEntity(item); } } } @@ -537,8 +499,15 @@ private void loadZone(Element root, Map map, int l, int uid) { /* * this is going to get messy, with a whole if-then-else heap */ - private Door loadDoor(Element door, String id, int x, int y, long itemUID, int mapUID) { - Door d = (Door) EntityFactory.getItem(id, x, y, itemUID); + private Door loadDoor( + Element door, + String id, + int x, + int y, + long itemUID, + int mapUID, + EntityFactory entityFactory) { + Door d = (Door) entityFactory.getItem(id, x, y, itemUID); // lock difficulty int lock = 0; @@ -548,7 +517,7 @@ private Door loadDoor(Element door, String id, int x, int y, long itemUID, int m } // key if (door.getAttribute("key") != null) { - RItem key = (RItem) resourceProvider.getResource(door.getAttributeValue("key")); + RItem key = (RItem) resourceManager.getResource(door.getAttributeValue("key")); d.lock.setKey(key); } // state of the door (open, closed or locked) @@ -572,7 +541,7 @@ private Door loadDoor(Element door, String id, int x, int y, long itemUID, int m if (door.getAttribute("spell") != null) { String spell = door.getAttributeValue("spell"); RSpell.Enchantment enchantment = - (RSpell.Enchantment) resourceProvider.getResource(spell, "magic"); + (RSpell.Enchantment) resourceManager.getResource(spell, "magic"); d.setMagicComponent(new Enchantment(enchantment, 0, d.getUID())); } @@ -614,8 +583,14 @@ private Door loadDoor(Element door, String id, int x, int y, long itemUID, int m } private Container loadContainer( - Element container, String id, int x, int y, long itemUID, int mapUID) { - Container cont = (Container) EntityFactory.getItem(id, x, y, itemUID); + Element container, + String id, + int x, + int y, + long itemUID, + int mapUID, + EntityFactory entityFactory) { + Container cont = (Container) entityFactory.getItem(id, x, y, itemUID); // lock difficulty if (container.getAttribute("lock") != null) { @@ -626,7 +601,7 @@ private Container loadContainer( // key RItem key = null; if (container.getAttribute("key") != null) { - key = (RItem) resourceProvider.getResource(container.getAttributeValue("key")); + key = (RItem) resourceManager.getResource(container.getAttributeValue("key")); cont.lock.setKey(key); } @@ -640,7 +615,7 @@ private Container loadContainer( if (container.getAttribute("spell") != null) { String spell = container.getAttributeValue("spell"); RSpell.Enchantment enchantment = - (RSpell.Enchantment) resourceProvider.getResource(spell, "magic"); + (RSpell.Enchantment) resourceManager.getResource(spell, "magic"); cont.setMagicComponent(new Enchantment(enchantment, 0, cont.getUID())); } @@ -648,13 +623,13 @@ private Container loadContainer( for (Element e : container.getChildren("item")) { long contentUID = UIDStore.getObjectUID(mapUID, Integer.parseInt(e.getAttributeValue("uid"))); - entityStore.addEntity(EntityFactory.getItem(e.getAttributeValue("id"), contentUID)); + uidStore.addEntity(entityFactory.getItem(e.getAttributeValue("id"), contentUID)); cont.addItem(contentUID); } } else { // otherwise default items for (String s : ((RItem.Container) cont.resource).contents) { - Item i = EntityFactory.getItem(s, entityStore.createNewEntityUID()); - entityStore.addEntity(i); + Item i = entityFactory.getItem(s, uidStore.createNewEntityUID()); + uidStore.addEntity(i); cont.addItem(i.getUID()); } } @@ -671,9 +646,9 @@ private Region loadRegion(Element element) { String text = element.getAttributeValue("text"); RRegionTheme theme = - (RRegionTheme) resourceProvider.getResource(element.getAttributeValue("random"), "theme"); + (RRegionTheme) resourceManager.getResource(element.getAttributeValue("random"), "theme"); - RTerrain rt = (RTerrain) resourceProvider.getResource(text, "terrain"); + RTerrain rt = (RTerrain) resourceManager.getResource(text, "terrain"); Region r = new Region(text, x, y, w, h, theme, order, rt); r.setLabel(element.getAttributeValue("label")); for (Element e : element.getChildren("script")) { diff --git a/src/main/java/neon/maps/Region.java b/src/main/java/neon/maps/Region.java index 164b9c1..5977dc3 100644 --- a/src/main/java/neon/maps/Region.java +++ b/src/main/java/neon/maps/Region.java @@ -24,7 +24,6 @@ import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.*; -import neon.core.Engine; import neon.resources.RRegionTheme; import neon.resources.RTerrain; import neon.systems.scripting.Activator; @@ -186,23 +185,23 @@ public String getLabel() { } public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { - theme = (RRegionTheme) Engine.getResources().getResource(input.readUTF(), "theme"); - label = input.readUTF(); - if (label.isEmpty()) { - label = null; - } - id = input.readUTF(); - terrain = (RTerrain) Engine.getResources().getResource(id, "terrain"); - x = input.readInt(); - y = input.readInt(); - z = input.readInt(); - width = input.readInt(); - height = input.readInt(); - int size = input.readInt(); - scripts = new ArrayList(); - for (int i = 0; i < size; i++) { - scripts.add(input.readUTF()); - } + // theme = (RRegionTheme) Engine.getResources().getResource(input.readUTF(), "theme"); + // label = input.readUTF(); + // if (label.isEmpty()) { + // label = null; + // } + // id = input.readUTF(); + // terrain = (RTerrain) Engine.getResources().getResource(id, "terrain"); + // x = input.readInt(); + // y = input.readInt(); + // z = input.readInt(); + // width = input.readInt(); + // height = input.readInt(); + // int size = input.readInt(); + // scripts = new ArrayList(); + // for (int i = 0; i < size; i++) { + // scripts.add(input.readUTF()); + // } } public void writeExternal(ObjectOutput output) throws IOException { diff --git a/src/main/java/neon/maps/World.java b/src/main/java/neon/maps/World.java index 28ce0e6..2de8c2f 100644 --- a/src/main/java/neon/maps/World.java +++ b/src/main/java/neon/maps/World.java @@ -22,6 +22,8 @@ import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.*; +import lombok.Getter; +import lombok.Setter; /** * This class represents the surface of the game world. It can be seamlessly traversed. @@ -29,7 +31,7 @@ * @author mdriesen */ public class World implements Map { - private String name; + @Getter @Setter private String name; private int uid; private Zone zone; @@ -40,7 +42,6 @@ public class World implements Map { * @param uid the uid of this map */ public World(String name, int uid) { - zone = new Zone("world", uid, 0); this.name = name; this.uid = uid; } @@ -51,22 +52,12 @@ public Zone getZone(int i) { return zone; } - public void setName(String name) { - this.name = name; - } - public int getUID() { return uid; } - public String getName() { - return name; - } - public Collection getZones() { - ArrayList zones = new ArrayList(); - zones.add(zone); - return zones; + return List.of(zone); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { diff --git a/src/main/java/neon/maps/Zone.java b/src/main/java/neon/maps/Zone.java index ae0ab98..40066c4 100644 --- a/src/main/java/neon/maps/Zone.java +++ b/src/main/java/neon/maps/Zone.java @@ -20,30 +20,33 @@ import java.awt.Point; import java.awt.Rectangle; -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; import java.util.*; -import neon.core.Engine; +import lombok.Getter; +import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Item; +import neon.entities.UIDStore; import neon.resources.RZoneTheme; +import neon.resources.ResourceManager; import neon.ui.graphics.*; import neon.util.mapstorage.MapStore; import neon.util.spatial.*; -public class Zone implements Externalizable { +public class Zone /* implements Externalizable */ { private static final ZComparator comparator = new ZComparator(); - private String name; - private int map; - private RZoneTheme theme; - private int index; - private HashMap lights = new HashMap(); - private SimpleIndex creatures = new SimpleIndex(); - private GridIndex items = new GridIndex(); - private RTree regions; - private RTree top = new RTree(100, 40); + + @Getter private final String name; + @Getter private final int map; + @Getter private final int index; + @Getter private RZoneTheme theme; + + private final HashMap lights = new HashMap<>(); + private final SimpleIndex creatures = new SimpleIndex<>(); + private final GridIndex items = new GridIndex<>(); + private final RTree regions; + private final RTree top = new RTree<>(100, 40); + private final UIDStore uidStore; + private final ResourceManager resourceManager; /** * Initializes a new zone. @@ -51,19 +54,16 @@ public class Zone implements Externalizable { * @param name the zone name * @param map the map UID * @param index the zone index - * @deprecated Use {@link ZoneFactory#createZone(String, int, int)} instead to avoid constructor - * side effects */ - @Deprecated - public Zone(String name, int map, int index) { + public Zone(String name, int map, int index, UIDStore uidStore, ResourceManager resourceManager, RTree tree) { this.map = map; this.name = name; this.index = index; - regions = new RTree(100, 40, Engine.getAtlas().getCache(), map + ":" + index); + this.uidStore = uidStore; + this.resourceManager = resourceManager; + this.regions = tree; } - /** Default constructor for serialization. */ - public Zone() {} /** * Initializes a new zone with a theme. @@ -72,59 +72,12 @@ public Zone() {} * @param map the map UID * @param theme the zone theme * @param index the zone index - * @deprecated Use {@link ZoneFactory#createZone(String, int, RZoneTheme, int)} instead to avoid - * constructor side effects */ - @Deprecated - public Zone(String name, int map, RZoneTheme theme, int index) { - this(name, map, index); + public Zone(String name, int map, RZoneTheme theme, int index, UIDStore uidStore, ResourceManager resourceManager, RTree tree) { + this(name, map, index, uidStore,resourceManager,tree); this.theme = theme; } - /** - * Private constructor for factory creation. - * - * @param name the zone name - * @param map the map UID - * @param index the zone index - * @param cache the MapDB cache for spatial indices - */ - private Zone(String name, int map, int index, MapStore cache) { - this.map = map; - this.name = name; - this.index = index; - regions = new RTree(100, 40, cache, map + ":" + index); - } - - /** - * Factory method to create a zone with dependency injection. - * - * @param name the zone name - * @param mapUID the map UID - * @param index the zone index - * @param cache the MapDB cache for spatial indices - * @return a new Zone instance - */ - static Zone create(String name, int mapUID, int index, MapStore cache) { - return new Zone(name, mapUID, index, cache); - } - - /** - * Factory method to create a zone with a theme and dependency injection. - * - * @param name the zone name - * @param mapUID the map UID - * @param theme the zone theme - * @param index the zone index - * @param cache the MapDB cache for spatial indices - * @return a new Zone instance with a theme - */ - static Zone create(String name, int mapUID, RZoneTheme theme, int index, MapStore cache) { - Zone zone = new Zone(name, mapUID, index, cache); - zone.theme = theme; - return zone; - } - /** * @param bounds * @return all renderables within the given bounds @@ -132,27 +85,20 @@ static Zone create(String name, int mapUID, RZoneTheme theme, int index, MapStor public Collection getRenderables(Rectangle bounds) { ArrayList elements = new ArrayList(); for (long uid : creatures.getElements(bounds)) { - elements.add(Engine.getStore().getEntity(uid).getRenderComponent()); + elements.add(uidStore.getEntity(uid).getRenderComponent()); } for (long uid : items.getElements(bounds)) { - elements.add(Engine.getStore().getEntity(uid).getRenderComponent()); + elements.add(uidStore.getEntity(uid).getRenderComponent()); } // for(Region r : regions.getElements(bounds)) { elements.addAll(regions.getElements(bounds)); // } for (long uid : top.getElements(bounds)) { - elements.add(Engine.getStore().getEntity(uid).getRenderComponent()); + elements.add(uidStore.getEntity(uid).getRenderComponent()); } return elements; } - /** - * @return the index of this zone - */ - public int getIndex() { - return index; - } - /** * @return whether this is a randomly generated zone */ @@ -164,14 +110,6 @@ public void fix() { theme = null; } - public RZoneTheme getTheme() { - return theme; - } - - public int getMap() { - return map; - } - @Override public String toString() { return name; @@ -193,7 +131,7 @@ public Collection getCreatures() { public Collection getCreatures(Rectangle box) { ArrayList list = new ArrayList(); for (long uid : creatures.getElements()) { - Creature c = (Creature) Engine.getStore().getEntity(uid); + Creature c = (Creature) uidStore.getEntity(uid); Rectangle bounds = c.getShapeComponent(); if (box.contains(bounds.x, bounds.y)) { list.add(c); @@ -210,7 +148,7 @@ public Collection getCreatures(Rectangle box) { */ public Creature getCreature(Point p) { for (long uid : creatures.getElements()) { - Creature c = (Creature) Engine.getStore().getEntity(uid); + Creature c = (Creature) uidStore.getEntity(uid); Rectangle bounds = c.getShapeComponent(); if (p.distance(bounds.x, bounds.y) < 1) { return c; @@ -229,13 +167,6 @@ public void addCreature(Creature c) { creatures.insert(c.getUID(), bounds); } - /** - * @return the name of this zone - */ - public String getName() { - return name; - } - /** * @return the height of this zone */ @@ -292,8 +223,8 @@ public Collection getItems() { */ public Region getRegion(Point p) { ArrayList buffer = new ArrayList(getRegions(p)); - Collections.sort(buffer, comparator); - return buffer.size() > 0 ? buffer.get(buffer.size() - 1) : null; + buffer.sort(comparator); + return !buffer.isEmpty() ? buffer.getLast() : null; } /** @@ -365,69 +296,69 @@ public HashMap getLightMap() { return lights; } - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - index = in.readInt(); - map = in.readInt(); - name = in.readUTF(); - String t = in.readUTF(); - if (!t.isEmpty()) { - theme = (RZoneTheme) Engine.getResources().getResource(t, "theme"); - } - - // items - top = new RTree(100, 40); - items = new GridIndex(); - lights = new HashMap(); - int iSize = in.readInt(); - for (int i = 0; i < iSize; i++) { - long uid = in.readLong(); - Item item = (Item) Engine.getStore().getEntity(uid); - addItem(item); - } - int tSize = in.readInt(); - for (int i = 0; i < tSize; i++) { - long uid = in.readLong(); - Item item = (Item) Engine.getStore().getEntity(uid); - addItem(item); - } - - // creatures - creatures = new SimpleIndex(); - int cSize = in.readInt(); - for (int i = 0; i < cSize; i++) { - long uid = in.readLong(); - Rectangle bounds = Engine.getStore().getEntity(uid).getShapeComponent(); - creatures.insert(uid, bounds); - } - - // regions - regions = new RTree(100, 40, Engine.getAtlas().getCache(), map + ":" + index); - } - - public void writeExternal(ObjectOutput out) throws IOException { - out.writeInt(index); - out.writeInt(map); - out.writeUTF(name); - if (theme != null) { - out.writeUTF(theme.id); - } else { - out.writeUTF(""); - } - - // items - out.writeInt(items.getElements().size()); - for (long l : items.getElements()) { - out.writeLong(l); - } - out.writeInt(top.getElements().size()); - for (long l : top.getElements()) { - out.writeLong(l); - } - - // creatures - out.writeInt(creatures.getElements().size()); - for (long l : creatures.getElements()) { - out.writeLong(l); - } - } + // public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // index = in.readInt(); + // map = in.readInt(); + // name = in.readUTF(); + // String t = in.readUTF(); + // if (!t.isEmpty()) { + // theme = (RZoneTheme) Engine.getResources().getResource(t, "theme"); + // } + // + // // items + // top = new RTree(100, 40); + // items = new GridIndex(); + // lights = new HashMap(); + // int iSize = in.readInt(); + // for (int i = 0; i < iSize; i++) { + // long uid = in.readLong(); + // Item item = (Item) Engine.getStore().getEntity(uid); + // addItem(item); + // } + // int tSize = in.readInt(); + // for (int i = 0; i < tSize; i++) { + // long uid = in.readLong(); + // Item item = (Item) Engine.getStore().getEntity(uid); + // addItem(item); + // } + // + // // creatures + // creatures = new SimpleIndex(); + // int cSize = in.readInt(); + // for (int i = 0; i < cSize; i++) { + // long uid = in.readLong(); + // Rectangle bounds = Engine.getStore().getEntity(uid).getShapeComponent(); + // creatures.insert(uid, bounds); + // } + // + // // regions + // regions = new RTree(100, 40, Engine.getAtlas().getCache(), map + ":" + index); + // } + // + // public void writeExternal(ObjectOutput out) throws IOException { + // out.writeInt(index); + // out.writeInt(map); + // out.writeUTF(name); + // if (theme != null) { + // out.writeUTF(theme.id); + // } else { + // out.writeUTF(""); + // } + // + // // items + // out.writeInt(items.getElements().size()); + // for (long l : items.getElements()) { + // out.writeLong(l); + // } + // out.writeInt(top.getElements().size()); + // for (long l : top.getElements()) { + // out.writeLong(l); + // } + // + // // creatures + // out.writeInt(creatures.getElements().size()); + // for (long l : creatures.getElements()) { + // out.writeLong(l); + // } + // } } diff --git a/src/main/java/neon/maps/ZoneFactory.java b/src/main/java/neon/maps/ZoneFactory.java index 419c789..10af084 100644 --- a/src/main/java/neon/maps/ZoneFactory.java +++ b/src/main/java/neon/maps/ZoneFactory.java @@ -18,8 +18,11 @@ package neon.maps; +import neon.entities.UIDStore; import neon.resources.RZoneTheme; +import neon.resources.ResourceManager; import neon.util.mapstorage.MapStore; +import neon.util.spatial.RTree; /** * Factory for creating Zone instances with proper dependency injection. Eliminates the constructor @@ -29,38 +32,28 @@ */ public class ZoneFactory { private final MapStore cache; - + private final UIDStore uidStore; + private final ResourceManager resourceManager; /** * Creates a new ZoneFactory with the given cache database. * * @param cache the MapDB cache database for spatial indices */ - public ZoneFactory(MapStore cache) { + public ZoneFactory(MapStore cache, UIDStore uidStore, ResourceManager resourceManager) { this.cache = cache; + this.uidStore = uidStore; + this.resourceManager = resourceManager; + } - /** - * Creates a new zone with the given parameters. - * - * @param name the zone name - * @param mapUID the UID of the map containing this zone - * @param index the zone index within its map - * @return a new Zone instance - */ - public Zone createZone(String name, int mapUID, int index) { - return Zone.create(name, mapUID, index, cache); + public Zone createZone(String name, int map, int index) { + RTree regions = new RTree<>(100, 40, cache, map + ":" + index); + return new Zone(name,map,index,uidStore,resourceManager,regions); } - /** - * Creates a new zone with a theme for random generation. - * - * @param name the zone name - * @param mapUID the UID of the map containing this zone - * @param theme the zone theme for random generation - * @param index the zone index within its map - * @return a new Zone instance with a theme - */ - public Zone createZone(String name, int mapUID, RZoneTheme theme, int index) { - return Zone.create(name, mapUID, theme, index, cache); + public Zone createZoneWithTheme(String name, int map, int index, RZoneTheme theme) { + RTree regions = new RTree<>(100, 40, cache, map + ":" + index); + return new Zone(name,map,theme,index,uidStore,resourceManager,regions); } + } diff --git a/src/main/java/neon/maps/generators/DungeonGenerator.java b/src/main/java/neon/maps/generators/DungeonGenerator.java index 088010e..b92568b 100644 --- a/src/main/java/neon/maps/generators/DungeonGenerator.java +++ b/src/main/java/neon/maps/generators/DungeonGenerator.java @@ -23,21 +23,16 @@ import java.awt.*; import java.awt.geom.*; import java.util.*; + +import neon.entities.*; import neon.entities.Container; -import neon.entities.Creature; -import neon.entities.Door; -import neon.entities.EntityFactory; -import neon.entities.Item; import neon.entities.property.Habitat; import neon.maps.*; import neon.maps.Region.Modifier; import neon.maps.services.EntityStore; import neon.maps.services.QuestProvider; import neon.maps.services.ResourceProvider; -import neon.resources.RCreature; -import neon.resources.RItem; -import neon.resources.RTerrain; -import neon.resources.RZoneTheme; +import neon.resources.*; import neon.util.Dice; /** @@ -56,7 +51,7 @@ public class DungeonGenerator { private final EntityStore entityStore; private final ResourceProvider resourceProvider; private final QuestProvider questProvider; - + private final EntityFactory entityFactory; // random sources private final MapUtils mapUtils; private final Dice dice; @@ -82,8 +77,8 @@ public class DungeonGenerator { */ public DungeonGenerator( RZoneTheme theme, - EntityStore entityStore, - ResourceProvider resourceProvider, + neon.entities.UIDStore entityStore, + ResourceManager resourceProvider, QuestProvider questProvider) { this(theme, entityStore, resourceProvider, questProvider, new MapUtils(), new Dice()); } @@ -100,8 +95,8 @@ public DungeonGenerator( */ public DungeonGenerator( RZoneTheme theme, - EntityStore entityStore, - ResourceProvider resourceProvider, + neon.entities.UIDStore entityStore, + ResourceManager resourceProvider, QuestProvider questProvider, MapUtils mapUtils, Dice dice) { @@ -117,6 +112,7 @@ public DungeonGenerator( this.caveGenerator = new CaveGenerator(dice); this.mazeGenerator = new MazeGenerator(dice); this.featureGenerator = new FeatureGenerator(mapUtils); + this.entityFactory = new EntityFactory(entityStore,resourceProvider); } /** @@ -129,8 +125,8 @@ public DungeonGenerator( */ public DungeonGenerator( Zone zone, - EntityStore entityStore, - ResourceProvider resourceProvider, + UIDStore entityStore, + ResourceManager resourceProvider, QuestProvider questProvider) { this(zone, entityStore, resourceProvider, questProvider, new MapUtils(), new Dice()); } @@ -148,8 +144,8 @@ public DungeonGenerator( */ public DungeonGenerator( Zone zone, - EntityStore entityStore, - ResourceProvider resourceProvider, + UIDStore entityStore, + ResourceManager resourceProvider, QuestProvider questProvider, MapUtils mapUtils, Dice dice) { @@ -165,6 +161,7 @@ public DungeonGenerator( this.caveGenerator = new CaveGenerator(dice); this.mazeGenerator = new MazeGenerator(dice); this.featureGenerator = new FeatureGenerator(mapUtils); + this.entityFactory = new EntityFactory(entityStore,resourceProvider); } /** @@ -200,7 +197,7 @@ public void generate(Door door, Zone previous, Atlas atlas) { int destMap = previous.getMap(); int destZone = previous.getIndex(); String doorType = theme.doors.split(",")[0]; - Door tdoor = (Door) EntityFactory.getItem(doorType, p.x, p.y, entityStore.createNewEntityUID()); + Door tdoor = (Door) entityFactory.getItem(doorType, p.x, p.y, entityStore.createNewEntityUID()); entityStore.addEntity(tdoor); tiles[p.x][p.y] = MapUtils.DOOR; tdoor.portal.setDestination(destPoint, destZone, destMap); @@ -223,7 +220,7 @@ public void generate(Door door, Zone previous, Atlas atlas) { Door toDoor = (Door) - EntityFactory.getItem( + entityFactory.getItem( theme.doors.split(",")[0], pos.x, pos.y, entityStore.createNewEntityUID()); entityStore.addEntity(toDoor); tiles[pos.x][pos.y] = MapUtils.DOOR; @@ -244,7 +241,7 @@ public void generate(Door door, Zone previous, Atlas atlas) { Door toDoor = (Door) - EntityFactory.getItem( + entityFactory.getItem( theme.doors.split(",")[0], pos.x, pos.y, @@ -274,12 +271,12 @@ public void generate(Door door, Zone previous, Atlas atlas) { p1.y = dice.rollDice(1, height, -1); } while (tiles[p1.x][p1.y] != MapUtils.FLOOR); if (resourceProvider.getResource(object) instanceof RItem) { - Item item = EntityFactory.getItem(object, p1.x, p1.y, entityStore.createNewEntityUID()); + Item item = entityFactory.getItem(object, p1.x, p1.y, entityStore.createNewEntityUID()); entityStore.addEntity(item); zone.addItem(item); } else if (resourceProvider.getResource(object) instanceof RCreature) { Creature creature = - EntityFactory.getCreature(object, p1.x, p1.y, entityStore.createNewEntityUID()); + entityFactory.getCreature(object, p1.x, p1.y, entityStore.createNewEntityUID()); entityStore.addEntity(creature); zone.addCreature(creature); } @@ -495,7 +492,7 @@ private void generateEngineContent(int width, int height) { } private void addDoor(String terrain, String id, int x, int y, int layer) { - Door door = (Door) EntityFactory.getItem(id, x, y, entityStore.createNewEntityUID()); + Door door = (Door) entityFactory.getItem(id, x, y, entityStore.createNewEntityUID()); entityStore.addEntity(door); if (tiles[x][y] == MapUtils.DOOR_LOCKED) { door.lock.setLockDC(10); @@ -510,7 +507,7 @@ private void addDoor(String terrain, String id, int x, int y, int layer) { private void addCreature(String description, int x, int y) { String id = description.replace("c:", ""); - Creature creature = EntityFactory.getCreature(id, x, y, entityStore.createNewEntityUID()); + Creature creature = entityFactory.getCreature(id, x, y, entityStore.createNewEntityUID()); // no land creatures in water Rectangle bounds = creature.getShapeComponent(); Modifier modifier = zone.getRegion(bounds.getLocation()).getMovMod(); @@ -524,11 +521,11 @@ private void addCreature(String description, int x, int y) { private void addItem(String description, int x, int y) { String id = description.replace("i:", ""); - Item item = EntityFactory.getItem(id, x, y, entityStore.createNewEntityUID()); + Item item = entityFactory.getItem(id, x, y, entityStore.createNewEntityUID()); entityStore.addEntity(item); if (item instanceof Container) { for (String s : ((RItem.Container) item.resource).contents) { - Item i = EntityFactory.getItem(s, entityStore.createNewEntityUID()); + Item i = entityFactory.getItem(s, entityStore.createNewEntityUID()); ((Container) item).addItem(i.getUID()); entityStore.addEntity(i); } diff --git a/src/main/java/neon/maps/generators/TownGenerator.java b/src/main/java/neon/maps/generators/TownGenerator.java index cae2952..3467cb0 100644 --- a/src/main/java/neon/maps/generators/TownGenerator.java +++ b/src/main/java/neon/maps/generators/TownGenerator.java @@ -22,13 +22,13 @@ import java.util.ArrayList; import neon.entities.Door; import neon.entities.EntityFactory; +import neon.entities.UIDStore; import neon.maps.MapUtils; import neon.maps.Region; import neon.maps.Zone; -import neon.maps.services.EntityStore; -import neon.maps.services.ResourceProvider; import neon.resources.RRegionTheme; import neon.resources.RTerrain; +import neon.resources.ResourceManager; /** * This class generates random towns. @@ -37,10 +37,10 @@ */ public class TownGenerator { private final Zone zone; - private final EntityStore entityStore; - private final ResourceProvider resourceProvider; + private final UIDStore entityStore; + private final ResourceManager resourceProvider; private final MapUtils mapUtils; - + private final EntityFactory entityFactory; /** * Creates a town generator with dependency injection. Uses default (non-deterministic) random * number generation. @@ -49,8 +49,9 @@ public class TownGenerator { * @param entityStore the entity store service * @param resourceProvider the resource provider service */ - public TownGenerator(Zone zone, EntityStore entityStore, ResourceProvider resourceProvider) { + public TownGenerator(Zone zone, UIDStore entityStore, ResourceManager resourceProvider) { this(zone, entityStore, resourceProvider, new MapUtils()); + } /** @@ -61,14 +62,14 @@ public TownGenerator(Zone zone, EntityStore entityStore, ResourceProvider resour * @param entityStore the entity store service * @param resourceProvider the resource provider service * @param mapUtils the map utilities with configured random source - * @param dice the dice roller with configured random source */ public TownGenerator( - Zone zone, EntityStore entityStore, ResourceProvider resourceProvider, MapUtils mapUtils) { + Zone zone, UIDStore entityStore, ResourceManager resourceProvider, MapUtils mapUtils) { this.zone = zone; this.entityStore = entityStore; this.resourceProvider = resourceProvider; this.mapUtils = mapUtils; + entityFactory = new EntityFactory(entityStore,resourceProvider); } /** @@ -136,7 +137,7 @@ private void makeDoor(Region r, RRegionTheme theme) { }; long uid = entityStore.createNewEntityUID(); - Door door = (Door) EntityFactory.getItem(theme.door, x, y, uid); + Door door = (Door) entityFactory.getItem(theme.door, x, y, uid); entityStore.addEntity(door); door.lock.close(); zone.addItem(door); diff --git a/src/main/java/neon/maps/generators/WildernessGenerator.java b/src/main/java/neon/maps/generators/WildernessGenerator.java index 07b832b..10d5ae8 100644 --- a/src/main/java/neon/maps/generators/WildernessGenerator.java +++ b/src/main/java/neon/maps/generators/WildernessGenerator.java @@ -24,6 +24,8 @@ import java.awt.geom.Area; import java.util.ArrayList; import java.util.Collection; + +import neon.core.GameStores; import neon.entities.*; import neon.entities.property.Habitat; import neon.maps.Decomposer; @@ -35,6 +37,7 @@ import neon.resources.RItem; import neon.resources.RRegionTheme; import neon.resources.RTerrain; +import neon.resources.ResourceManager; import neon.util.Dice; /** @@ -54,6 +57,7 @@ public class WildernessGenerator { private String[][] terrain; // general terrain info private final EntityStore entityStore; private final ResourceProvider resourceProvider; + private final EntityFactory entityFactory; // random sources private final MapUtils mapUtils; @@ -71,8 +75,8 @@ public class WildernessGenerator { * @param resourceProvider the resource provider service */ public WildernessGenerator( - Zone zone, EntityStore entityStore, ResourceProvider resourceProvider) { - this(zone, entityStore, resourceProvider, new MapUtils(), new Dice()); + Zone zone, GameStores gameStores) { + this(zone, gameStores, new MapUtils(), new Dice()); } /** @@ -86,17 +90,17 @@ public WildernessGenerator( */ public WildernessGenerator( Zone zone, - EntityStore entityStore, - ResourceProvider resourceProvider, + GameStores gameStores, MapUtils mapUtils, Dice dice) { this.zone = zone; - this.entityStore = entityStore; - this.resourceProvider = resourceProvider; + this.entityStore = gameStores.getStore(); + this.resourceProvider = gameStores.getResources(); this.mapUtils = mapUtils; this.dice = dice; this.blocksGenerator = new BlocksGenerator(mapUtils); this.caveGenerator = new CaveGenerator(dice); + this.entityFactory = new EntityFactory(gameStores.getStore(),gameStores.getResources()); } /** @@ -107,7 +111,7 @@ public WildernessGenerator( * @param resourceProvider the resource provider service */ public WildernessGenerator( - String[][] terrain, EntityStore entityStore, ResourceProvider resourceProvider) { + String[][] terrain, UIDStore entityStore, ResourceManager resourceProvider) { this(terrain, entityStore, resourceProvider, new MapUtils(), new Dice()); } @@ -123,8 +127,8 @@ public WildernessGenerator( */ public WildernessGenerator( String[][] terrain, - EntityStore entityStore, - ResourceProvider resourceProvider, + UIDStore entityStore, + ResourceManager resourceProvider, MapUtils mapUtils, Dice dice) { this.terrain = terrain; @@ -134,6 +138,7 @@ public WildernessGenerator( this.dice = dice; this.blocksGenerator = new BlocksGenerator(mapUtils); this.caveGenerator = new CaveGenerator(dice); + this.entityFactory = new EntityFactory(entityStore,resourceProvider); } /** Generates a piece of wilderness using the supplied parameters. */ @@ -348,7 +353,7 @@ private void addCreatures( String region = t.isEmpty() ? base : t; Creature creature = - EntityFactory.getCreature(id, rx + x, ry + y, entityStore.createNewEntityUID()); + entityFactory.getCreature(id, rx + x, ry + y, entityStore.createNewEntityUID()); RTerrain terrain = (RTerrain) resourceProvider.getResource(region, "terrain"); // Only spawn creatures if their habitat matches the terrain // LAND creatures should NOT spawn in SWIM terrain @@ -374,11 +379,11 @@ private void generateEngineContent(Region region) { if (entry.startsWith("i:")) { String id = entry.replace("i:", ""); long uid = entityStore.createNewEntityUID(); - Item item = EntityFactory.getItem(id, region.getX() + i, region.getY() + j, uid); + Item item = entityFactory.getItem(id, region.getX() + i, region.getY() + j, uid); entityStore.addEntity(item); if (item instanceof Container) { for (String s : ((RItem.Container) item.resource).contents) { - Item content = EntityFactory.getItem(s, entityStore.createNewEntityUID()); + Item content = entityFactory.getItem(s, entityStore.createNewEntityUID()); ((Container) item).addItem(content.getUID()); entityStore.addEntity(content); } @@ -388,7 +393,7 @@ private void generateEngineContent(Region region) { String id = entry.replace("c:", ""); long uid = entityStore.createNewEntityUID(); Creature creature = - EntityFactory.getCreature(id, region.getX() + i, region.getY() + j, uid); + entityFactory.getCreature(id, region.getX() + i, region.getY() + j, uid); entityStore.addEntity(creature); zone.addCreature(creature); } else if (!entry.isEmpty() && !entry.equals(region.getTextureType())) { @@ -441,7 +446,7 @@ private void addVegetation(int width, int height, RRegionTheme theme, String bas String[][] fauna = new String[width][height]; for (String id : theme.vegetation.keySet()) { int abundance = theme.vegetation.get(id); - Item dummy = EntityFactory.getItem(id, 0); + Item dummy = entityFactory.getItem(id, 0); int size = dummy.getShapeComponent().width; // size van boom in rekening brengen int ratio = (width / size) * (height / size); boolean[][] fill = generateIslands(width / size, height / size, abundance, 5, ratio / size); diff --git a/src/main/java/neon/maps/services/EngineEntityStore.java b/src/main/java/neon/maps/services/EngineEntityStore.java deleted file mode 100644 index e3f2893..0000000 --- a/src/main/java/neon/maps/services/EngineEntityStore.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2024 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.maps.services; - -import neon.core.Engine; -import neon.entities.Entity; - -/** - * Adapter implementation of EntityStore that delegates to the Engine singleton. This class provides - * a bridge during the transition to dependency injection. - * - * @author mdriesen - */ -public class EngineEntityStore implements EntityStore { - @Override - public Entity getEntity(long uid) { - return Engine.getStore().getEntity(uid); - } - - @Override - public void addEntity(Entity entity) { - Engine.getStore().addEntity(entity); - } - - @Override - public long createNewEntityUID() { - return Engine.getStore().createNewEntityUID(); - } - - @Override - public int createNewMapUID() { - return Engine.getStore().createNewMapUID(); - } - - @Override - public String[] getMapPath(int uid) { - return Engine.getStore().getMapPath(uid); - } -} diff --git a/src/main/java/neon/maps/services/EngineResourceProvider.java b/src/main/java/neon/maps/services/EngineResourceProvider.java deleted file mode 100644 index 48d53a0..0000000 --- a/src/main/java/neon/maps/services/EngineResourceProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2024 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.maps.services; - -import neon.core.Engine; -import neon.resources.Resource; - -/** - * Adapter implementation of ResourceProvider that delegates to the Engine singleton. This class - * provides a bridge during the transition to dependency injection. - * - * @author mdriesen - */ -public class EngineResourceProvider implements ResourceProvider { - @Override - public Resource getResource(String id) { - return Engine.getResources().getResource(id); - } - - @Override - public Resource getResource(String id, String type) { - return Engine.getResources().getResource(id, type); - } -} diff --git a/src/main/java/neon/maps/services/GameContextEntityStore.java b/src/main/java/neon/maps/services/GameContextEntityStore.java deleted file mode 100644 index a370040..0000000 --- a/src/main/java/neon/maps/services/GameContextEntityStore.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.maps.services; - -import neon.core.GameContext; -import neon.entities.Entity; - -/** - * Adapter implementation of EntityStore that delegates to a GameContext. This class provides proper - * dependency injection without relying on deprecated Engine static methods. - * - * @author mdriesen - */ -public class GameContextEntityStore implements EntityStore { - private final GameContext context; - - public GameContextEntityStore(GameContext context) { - this.context = context; - } - - @Override - public Entity getEntity(long uid) { - return context.getStore().getEntity(uid); - } - - @Override - public void addEntity(Entity entity) { - context.getStore().addEntity(entity); - } - - @Override - public long createNewEntityUID() { - return context.getStore().createNewEntityUID(); - } - - @Override - public int createNewMapUID() { - return context.getStore().createNewMapUID(); - } - - @Override - public String[] getMapPath(int uid) { - return context.getStore().getMapPath(uid); - } -} diff --git a/src/main/java/neon/maps/services/GameContextResourceProvider.java b/src/main/java/neon/maps/services/GameContextResourceProvider.java deleted file mode 100644 index f64f845..0000000 --- a/src/main/java/neon/maps/services/GameContextResourceProvider.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.maps.services; - -import neon.core.GameContext; -import neon.resources.Resource; - -/** - * Adapter implementation of ResourceProvider that delegates to a GameContext. This class provides - * proper dependency injection without relying on deprecated Engine static methods. - * - * @author mdriesen - */ -public class GameContextResourceProvider implements ResourceProvider { - private final GameContext context; - - public GameContextResourceProvider(GameContext context) { - this.context = context; - } - - @Override - public Resource getResource(String id) { - return context.getResources().getResource(id); - } - - @Override - public Resource getResource(String id, String type) { - return context.getResources().getResource(id, type); - } -} diff --git a/src/main/java/neon/narrative/QuestTracker.java b/src/main/java/neon/narrative/QuestTracker.java index dace167..644a128 100644 --- a/src/main/java/neon/narrative/QuestTracker.java +++ b/src/main/java/neon/narrative/QuestTracker.java @@ -21,6 +21,7 @@ import java.util.*; import lombok.extern.slf4j.Slf4j; import neon.core.Engine; +import neon.core.GameStores; import neon.core.event.TurnEvent; import neon.entities.Creature; import neon.resources.quest.Conversation; @@ -35,8 +36,11 @@ public class QuestTracker { private final HashMap quests = new HashMap<>(); // temporary map for quests that have been loaded for the dialog module private final HashMap temp = new HashMap<>(); + private final GameStores gameStores; - public QuestTracker() {} + public QuestTracker(GameStores gameStores) { + this.gameStores = gameStores; + } /** * Return all dialog topics for the given creature. The caller of this method should take care to @@ -98,7 +102,7 @@ public void startQuest(String id) { Quest quest = temp.remove(id); quests.put(id, quest); } else if (!quests.containsKey(id)) { - RQuest quest = (RQuest) Engine.getResources().getResource(id, "quest"); + RQuest quest = (RQuest) gameStores.getResources().getResource(id, "quest"); quests.put(id, new Quest(quest)); } } @@ -148,7 +152,7 @@ void checkTransition(TransitionEvent te) {} public void start(TurnEvent te) { log.trace("start {}", te); if (te.isStart()) { - for (RQuest quest : Engine.getResources().getResources(RQuest.class)) { + for (RQuest quest : gameStores.getResources().getResources(RQuest.class)) { if (quest.initial) { startQuest(quest.id); } diff --git a/src/main/java/neon/narrative/Resolver.java b/src/main/java/neon/narrative/Resolver.java index 1b4b468..5e23c50 100644 --- a/src/main/java/neon/narrative/Resolver.java +++ b/src/main/java/neon/narrative/Resolver.java @@ -18,87 +18,80 @@ package neon.narrative; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import neon.core.Engine; -import neon.resources.RCreature; -import neon.resources.RItem; -import neon.util.Dice; -import org.jdom2.Element; public class Resolver { - QuestTracker tracker; - - public Resolver(QuestTracker tracker) { - this.tracker = tracker; - } - - /** - * Resolves variables in a quest resource. Even elements are the original strings, odd elements - * are the resolved strings. - * - * @param vars - * @return - */ - protected List resolveVariables(Element vars) { - ArrayList strings = new ArrayList(); - - if (vars == null) { - return strings; - } - - for (Element var : vars.getChildren()) { - if (var.getName().equals("item")) { - addItem(var, strings); - } else if (var.getName().equals("npc")) { - addPerson(var, strings); - } else if (var.getName().equals("creature")) { - addCreature(var, strings); - } - } - - return strings; - } - - private void addItem(Element var, List strings) { - Collection items = Engine.getResources().getResources(RItem.class); - if (var.getAttributeValue("type") != null) { - for (RItem item : items) { - if (item.type.name().equals(var.getAttributeValue("type"))) { - strings.add("$" + var.getTextTrim() + "$"); - strings.add(item.toString()); - tracker.addObject(item.toString()); - break; // uit de for loop halen - } - } - } else if (var.getAttributeValue("id") != null) { - String[] things = var.getAttributeValue("id").split(","); - String item = things[Dice.roll(1, things.length, -1)]; - strings.add("$" + var.getTextTrim() + "$"); - strings.add(item.toString()); - tracker.addObject(item); - } else { - String item = items.toArray()[Dice.roll(1, items.size(), -1)].toString(); - strings.add("$" + var.getTextTrim() + "$"); - strings.add(item.toString()); - tracker.addObject(item.toString()); - } - } - - private void addPerson(Element var, List strings) { - String[] npcs = var.getAttributeValue("id").split(","); - String npc = npcs[Dice.roll(1, npcs.length, -1)]; - strings.add("$" + var.getTextTrim() + "$"); - strings.add(npc); - tracker.addObject(npc); - } - - private void addCreature(Element var, List strings) { - List creatures = Engine.getResources().getResources(RCreature.class); - String creature = creatures.get(Dice.roll(1, creatures.size(), -1)).toString(); - strings.add("$" + var.getTextTrim() + "$"); - strings.add(creature); - tracker.addObject(creature); - } + // QuestTracker tracker; + // + // public Resolver(QuestTracker tracker) { + // this.tracker = tracker; + // } + // + // /** + // * Resolves variables in a quest resource. Even elements are the original strings, odd + // elements + // * are the resolved strings. + // * + // * @param vars + // * @return + // */ + // protected List resolveVariables(Element vars) { + // ArrayList strings = new ArrayList(); + // + // if (vars == null) { + // return strings; + // } + // + // for (Element var : vars.getChildren()) { + // if (var.getName().equals("item")) { + // addItem(var, strings); + // } else if (var.getName().equals("npc")) { + // addPerson(var, strings); + // } else if (var.getName().equals("creature")) { + // addCreature(var, strings); + // } + // } + // + // return strings; + // } + // + // private void addItem(Element var, List strings) { + // Collection items = Engine.getResources().getResources(RItem.class); + // if (var.getAttributeValue("type") != null) { + // for (RItem item : items) { + // if (item.type.name().equals(var.getAttributeValue("type"))) { + // strings.add("$" + var.getTextTrim() + "$"); + // strings.add(item.toString()); + // tracker.addObject(item.toString()); + // break; // uit de for loop halen + // } + // } + // } else if (var.getAttributeValue("id") != null) { + // String[] things = var.getAttributeValue("id").split(","); + // String item = things[Dice.roll(1, things.length, -1)]; + // strings.add("$" + var.getTextTrim() + "$"); + // strings.add(item.toString()); + // tracker.addObject(item); + // } else { + // String item = items.toArray()[Dice.roll(1, items.size(), -1)].toString(); + // strings.add("$" + var.getTextTrim() + "$"); + // strings.add(item.toString()); + // tracker.addObject(item.toString()); + // } + // } + // + // private void addPerson(Element var, List strings) { + // String[] npcs = var.getAttributeValue("id").split(","); + // String npc = npcs[Dice.roll(1, npcs.length, -1)]; + // strings.add("$" + var.getTextTrim() + "$"); + // strings.add(npc); + // tracker.addObject(npc); + // } + // + // private void addCreature(Element var, List strings) { + // List creatures = Engine.getResources().getResources(RCreature.class); + // String creature = creatures.get(Dice.roll(1, creatures.size(), -1)).toString(); + // strings.add("$" + var.getTextTrim() + "$"); + // strings.add(creature); + // tracker.addObject(creature); + // } } diff --git a/src/main/java/neon/ui/Client.java b/src/main/java/neon/ui/Client.java index 3e55959..ce81efc 100644 --- a/src/main/java/neon/ui/Client.java +++ b/src/main/java/neon/ui/Client.java @@ -24,6 +24,7 @@ import javax.swing.UIManager; import lombok.extern.slf4j.Slf4j; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.event.LoadEvent; import neon.core.event.MagicEvent; import neon.core.event.MessageEvent; @@ -48,11 +49,13 @@ public class Client implements Runnable { private final MBassador bus; private final String version; private final GameContext context; + private final GameStores gameStores; - public Client(Port port, String version, GameContext context) { + public Client(Port port, String version, GameContext context, GameStores gameStores) { bus = port.getBus(); this.version = version; this.context = context; + this.gameStores = gameStores; fsm = new FiniteStateMachine(); bus.subscribe(new BusAdapter()); } @@ -73,37 +76,37 @@ private void initUI() { } // UI components - CClient client = (CClient) context.getResources().getResource("client", "config"); + CClient client = (CClient) gameStores.getResources().getResource("client", "config"); ui = new UserInterface(client.getTitle()); ui.show(); } private void initFSM() { // main menu - MainMenuState main = new MainMenuState(fsm, bus, ui, version, context); + MainMenuState main = new MainMenuState(fsm, bus, ui, version, context, gameStores); // all game substates - GameState game = new GameState(fsm, bus, ui, context); + GameState game = new GameState(fsm, bus, ui, context, gameStores); bus.subscribe(game); // doors - DoorState doors = new DoorState(game, bus, ui, context); + DoorState doors = new DoorState(game, bus, ui, context, gameStores); // locks LockState locks = new LockState(game, bus, ui, context); // bumping - BumpState bump = new BumpState(game, bus, ui, context); + BumpState bump = new BumpState(game, bus, ui, context, gameStores); // move - MoveState move = new MoveState(game, bus, context); + MoveState move = new MoveState(game, bus, context, gameStores); // aim - AimState aim = new AimState(game, bus, ui, context); + AimState aim = new AimState(game, bus, ui, context, gameStores); // dialog state - DialogState dialog = new DialogState(fsm, bus, ui, context); + DialogState dialog = new DialogState(fsm, bus, ui, context, gameStores); // inventory state - InventoryState inventory = new InventoryState(fsm, bus, ui, context); + InventoryState inventory = new InventoryState(fsm, bus, ui, context, gameStores); // containers - ContainerState container = new ContainerState(fsm, bus, ui, context); + ContainerState container = new ContainerState(fsm, bus, ui, context, gameStores); // journal state - JournalState journal = new JournalState(fsm, bus, ui, context); + JournalState journal = new JournalState(fsm, bus, ui, context, gameStores); // set start states fsm.addStartStates(main, move); diff --git a/src/main/java/neon/ui/GamePanel.java b/src/main/java/neon/ui/GamePanel.java index 9f4ce8e..65cb286 100644 --- a/src/main/java/neon/ui/GamePanel.java +++ b/src/main/java/neon/ui/GamePanel.java @@ -29,6 +29,7 @@ import javax.swing.text.DefaultCaret; import lombok.Getter; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.handlers.CombatUtils; import neon.entities.Player; import neon.entities.components.HealthComponent; @@ -55,15 +56,16 @@ public class GamePanel extends JComponent { private TitledBorder sBorder, aBorder, cBorder; private JVectorPane drawing; @Getter private final GameContext context; - + private final CombatUtils combatUtils; // components of the stats panel private JLabel intLabel, conLabel, dexLabel, strLabel, wisLabel, chaLabel; private JLabel healthLabel, magicLabel, AVLabel, DVLabel; /** Initializes this GamePanel. */ - public GamePanel(GameContext context) { + public GamePanel(GameContext context, CombatUtils combatUtils) { this.context = context; - drawing = new JVectorPane(); + this.combatUtils = combatUtils; + drawing = new JVectorPane(); drawing.setFilter(new LightFilter()); // stats field (hacky way to make it semi-transparent) @@ -239,7 +241,7 @@ private void drawStats() { + (int) (player.species.mana * player.species.iq)); } AVLabel.setText("AV: " + player.getAVString()); - DVLabel.setText("DV: " + CombatUtils.getDV(player)); + DVLabel.setText("DV: " + combatUtils.getDV(player)); Stats stats = player.getStatsComponent(); if (stats.getStr() > (int) player.species.str) { diff --git a/src/main/java/neon/ui/dialog/ChargeDialog.java b/src/main/java/neon/ui/dialog/ChargeDialog.java index f196fea..45e4f3f 100644 --- a/src/main/java/neon/ui/dialog/ChargeDialog.java +++ b/src/main/java/neon/ui/dialog/ChargeDialog.java @@ -26,6 +26,7 @@ import javax.swing.*; import javax.swing.border.*; import neon.core.GameContext; +import neon.core.GameStores; import neon.entities.Item; import neon.entities.Player; import neon.entities.components.Enchantment; @@ -38,6 +39,7 @@ public class ChargeDialog implements KeyListener { private JScrollPane scroller; private UserInterface ui; private final GameContext context; + private final GameStores gameStores; public ChargeDialog(UserInterface ui, GameContext context) { this.ui = ui; @@ -116,7 +118,7 @@ public void keyPressed(KeyEvent e) { private void initItems() { Vector listData = new Vector(); for (long uid : player.getInventoryComponent()) { - Item item = (Item) context.getStore().getEntity(uid); + Item item = (Item) gameStores.getStore().getEntity(uid); Enchantment enchantment = item.getMagicComponent(); if (enchantment != null && enchantment.getMana() < enchantment.getBaseMana()) { listData.add(item); diff --git a/src/main/java/neon/ui/dialog/CrafterDialog.java b/src/main/java/neon/ui/dialog/CrafterDialog.java index 587e13f..35b3a6c 100644 --- a/src/main/java/neon/ui/dialog/CrafterDialog.java +++ b/src/main/java/neon/ui/dialog/CrafterDialog.java @@ -28,6 +28,7 @@ import javax.swing.*; import javax.swing.border.*; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.event.StoreEvent; import neon.core.handlers.InventoryHandler; import neon.entities.Creature; @@ -47,11 +48,21 @@ public class CrafterDialog implements KeyListener { private MBassador bus; private UserInterface ui; private final GameContext context; + private final GameStores gameStores; + private final InventoryHandler inventoryHandler; + private final EntityFactory entityFactory; public CrafterDialog( - UserInterface ui, String coin, MBassador bus, GameContext context) { + UserInterface ui, + String coin, + MBassador bus, + GameContext context, + GameStores gameStores) { this.ui = ui; this.context = context; + this.gameStores = gameStores; + inventoryHandler = new InventoryHandler(gameStores.getStore()); + entityFactory = new EntityFactory(gameStores.getStore(), gameStores.getResources()); JFrame parent = ui.getWindow(); this.coin = coin; this.bus = bus; @@ -120,11 +131,12 @@ public void keyPressed(KeyEvent e) { RCraft craft = items.getSelectedValue(); if (player.getInventoryComponent().getMoney() >= craft.cost) { Collection removed = - InventoryHandler.removeItems(player, craft.raw, craft.amount); + inventoryHandler.removeItems(player, craft.raw, craft.amount); for (long uid : removed) { // remove used items bus.publishAsync(new StoreEvent(this, uid)); } - Item item = EntityFactory.getItem(craft.name, context.getStore().createNewEntityUID()); + Item item = + entityFactory.getItem(craft.name, gameStores.getStore().createNewEntityUID()); bus.publishAsync(new StoreEvent(this, item)); player.getInventoryComponent().addItem(item.getUID()); player.getInventoryComponent().addMoney(-craft.cost); @@ -142,8 +154,8 @@ public void keyPressed(KeyEvent e) { private void initItems() { DefaultListModel model = new DefaultListModel(); - for (RCraft thing : context.getResources().getResources(RCraft.class)) { - if (InventoryHandler.getAmount(player, thing.raw) >= thing.amount) { + for (RCraft thing : gameStores.getResources().getResources(RCraft.class)) { + if (inventoryHandler.getAmount(player, thing.raw) >= thing.amount) { model.addElement(thing); } } diff --git a/src/main/java/neon/ui/dialog/EnchantDialog.java b/src/main/java/neon/ui/dialog/EnchantDialog.java index 042d680..94e694b 100644 --- a/src/main/java/neon/ui/dialog/EnchantDialog.java +++ b/src/main/java/neon/ui/dialog/EnchantDialog.java @@ -28,6 +28,7 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import neon.core.GameContext; +import neon.core.GameStores; import neon.entities.Clothing; import neon.entities.Creature; import neon.entities.Item; @@ -47,10 +48,12 @@ public class EnchantDialog implements KeyListener, ListSelectionListener { private DefaultListModel spellModel; private UserInterface ui; private final GameContext context; + private final GameStores gameStores; - public EnchantDialog(UserInterface ui, GameContext context) { + public EnchantDialog(UserInterface ui, GameContext context, GameStores gameStores) { this.ui = ui; this.context = context; + this.gameStores = gameStores; JFrame parent = ui.getWindow(); frame = new JDialog(parent, true); frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 100)); @@ -110,7 +113,7 @@ public void initLists() { spellModel.clear(); for (Long uid : context.getPlayer().getInventoryComponent()) { - Item item = (Item) context.getStore().getEntity(uid); + Item item = (Item) gameStores.getStore().getEntity(uid); if ((item instanceof Weapon || item instanceof Clothing) && item.getMagicComponent() == null) { itemModel.addElement(item); diff --git a/src/main/java/neon/ui/dialog/NewGameDialog.java b/src/main/java/neon/ui/dialog/NewGameDialog.java index 8587c27..985bf75 100644 --- a/src/main/java/neon/ui/dialog/NewGameDialog.java +++ b/src/main/java/neon/ui/dialog/NewGameDialog.java @@ -25,7 +25,7 @@ import java.util.HashMap; import javax.swing.*; import javax.swing.border.*; -import neon.core.GameContext; +import neon.core.GameStores; import neon.core.event.LoadEvent; import neon.entities.Player; import neon.entities.property.Gender; @@ -46,12 +46,12 @@ public class NewGameDialog { private HashMap raceList; private MBassador bus; private UserInterface ui; - private final GameContext context; + private final GameStores gameStores; - public NewGameDialog(UserInterface ui, MBassador bus, GameContext context) { + public NewGameDialog(UserInterface ui, MBassador bus, GameStores gameStores) { this.bus = bus; this.ui = ui; - this.context = context; + this.gameStores = gameStores; JFrame parent = ui.getWindow(); frame = new JDialog(parent, false); frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 100)); @@ -83,9 +83,9 @@ public NewGameDialog(UserInterface ui, MBassador bus, GameContext c // race JPanel racePanel = new JPanel(); raceList = new HashMap(); - CGame game = (CGame) context.getResources().getResource("game", "config"); + CGame game = (CGame) gameStores.getResources().getResource("game", "config"); for (String s : game.getPlayableRaces()) { - raceList.put(((RCreature) context.getResources().getResource(s)).getName(), s); + raceList.put(((RCreature) gameStores.getResources().getResource(s)).getName(), s); } race = new JComboBox(raceList.keySet().toArray(new String[raceList.size()])); racePanel.add(race); @@ -106,7 +106,7 @@ public NewGameDialog(UserInterface ui, MBassador bus, GameContext c // birthsign JPanel signPanel = new JPanel(); - signBox = new JComboBox(context.getResources().getResources(RSign.class)); + signBox = new JComboBox(gameStores.getResources().getResources(RSign.class)); signPanel.add(signBox); signPanel.setBorder(new TitledBorder("Birthsign")); middle.add(signPanel); diff --git a/src/main/java/neon/ui/dialog/OptionDialog.java b/src/main/java/neon/ui/dialog/OptionDialog.java index c56a269..9299225 100644 --- a/src/main/java/neon/ui/dialog/OptionDialog.java +++ b/src/main/java/neon/ui/dialog/OptionDialog.java @@ -29,6 +29,7 @@ import lombok.extern.slf4j.Slf4j; import neon.core.Configuration; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.model.NeonConfig; import neon.resources.CClient; import neon.systems.files.JacksonMapper; @@ -40,10 +41,12 @@ public class OptionDialog { private ButtonGroup group; private JDialog frame; private final GameContext context; + private final GameStores gameStores; - public OptionDialog(JFrame parent, GameContext context) { + public OptionDialog(JFrame parent, GameContext context, GameStores gameStores) { this.context = context; frame = new JDialog(parent, false); + this.gameStores = gameStores; frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 100)); frame.setUndecorated(true); frame.setTitle("Options"); @@ -141,7 +144,7 @@ public OptionDialog(JFrame parent, GameContext context) { } public void show() { - CClient keys = (CClient) context.getResources().getResource("client", "config"); + CClient keys = (CClient) gameStores.getResources().getResource("client", "config"); switch (keys.getSettings()) { case CClient.AZERTY: @@ -206,7 +209,7 @@ private void save() { Configuration.audio = audioBox.isSelected(); // Update keyboard layout - CClient keys = (CClient) context.getResources().getResource("client", "config"); + CClient keys = (CClient) gameStores.getResources().getResource("client", "config"); if (group.isSelected(numpad.getModel())) { keys.setKeys(CClient.NUMPAD); config.keys = "numpad"; diff --git a/src/main/java/neon/ui/dialog/PotionDialog.java b/src/main/java/neon/ui/dialog/PotionDialog.java index 4eb428e..2d82b70 100644 --- a/src/main/java/neon/ui/dialog/PotionDialog.java +++ b/src/main/java/neon/ui/dialog/PotionDialog.java @@ -25,7 +25,7 @@ import java.awt.event.KeyListener; import javax.swing.*; import javax.swing.border.*; -import neon.core.GameContext; +import neon.core.GameStores; import neon.core.handlers.InventoryHandler; import neon.entities.Creature; import neon.entities.EntityFactory; @@ -40,12 +40,16 @@ public class PotionDialog implements KeyListener { private JList potions; private String coin; private UserInterface ui; - private final GameContext context; + private final GameStores gameStores; + private final EntityFactory entityFactory; + private final InventoryHandler inventoryHandler; - public PotionDialog(UserInterface ui, String coin, GameContext context) { + public PotionDialog(UserInterface ui, String coin, GameStores gameStores) { this.ui = ui; this.coin = coin; - this.context = context; + this.gameStores = gameStores; + inventoryHandler = new InventoryHandler(gameStores.getStore()); + entityFactory = new EntityFactory(gameStores.getStore(), gameStores.getResources()); JFrame parent = ui.getWindow(); frame = new JDialog(parent, true); frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 100)); @@ -112,11 +116,12 @@ public void keyPressed(KeyEvent e) { if (player.getInventoryComponent().getMoney() >= potion.cost) { for (String item : potion.ingredients) { long uid = removeItem(player, item); - context.getStore().removeEntity(uid); + gameStores.getStore().removeEntity(uid); } Item item = - EntityFactory.getItem(potion.toString(), context.getStore().createNewEntityUID()); - context.getStore().addEntity(item); + entityFactory.getItem( + potion.toString(), gameStores.getStore().createNewEntityUID()); + gameStores.getStore().addEntity(item); player.getInventoryComponent().addItem(item.getUID()); player.getInventoryComponent().addMoney(-potion.cost); initPotions(); @@ -133,7 +138,7 @@ public void keyPressed(KeyEvent e) { private void initPotions() { DefaultListModel model = new DefaultListModel(); - for (RRecipe recipe : context.getResources().getResources(RRecipe.class)) { + for (RRecipe recipe : gameStores.getResources().getResources(RRecipe.class)) { boolean ok = true; for (String item : recipe.ingredients) { if (!hasItem(player, item)) { @@ -186,7 +191,7 @@ public Component getListCellRendererComponent( private boolean hasItem(Creature creature, String item) { for (long uid : creature.getInventoryComponent()) { - if (context.getStore().getEntity(uid).getID().equals(item)) { + if (gameStores.getStore().getEntity(uid).getID().equals(item)) { return true; } } @@ -195,9 +200,9 @@ private boolean hasItem(Creature creature, String item) { private long removeItem(Creature creature, String id) { for (long uid : creature.getInventoryComponent()) { - Item item = (Item) context.getStore().getEntity(uid); + Item item = (Item) gameStores.getStore().getEntity(uid); if (item.getID().equals(id)) { - InventoryHandler.removeItem(creature, uid); + inventoryHandler.removeItem(creature, uid); return uid; } } diff --git a/src/main/java/neon/ui/dialog/RepairDialog.java b/src/main/java/neon/ui/dialog/RepairDialog.java index c9c0128..1b5a1f7 100644 --- a/src/main/java/neon/ui/dialog/RepairDialog.java +++ b/src/main/java/neon/ui/dialog/RepairDialog.java @@ -25,7 +25,7 @@ import java.util.ArrayList; import javax.swing.*; import javax.swing.border.*; -import neon.core.GameContext; +import neon.core.GameStores; import neon.entities.Armor; import neon.entities.Creature; import neon.entities.Item; @@ -39,11 +39,11 @@ public class RepairDialog implements KeyListener { private JList items; private ArrayList listData; private UserInterface ui; - private final GameContext context; + private final GameStores gameStores; - public RepairDialog(UserInterface ui, GameContext context) { + public RepairDialog(UserInterface ui, GameStores gameStores) { this.ui = ui; - this.context = context; + this.gameStores = gameStores; JFrame parent = ui.getWindow(); frame = new JDialog(parent, true); frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 100)); @@ -121,7 +121,7 @@ public void keyPressed(KeyEvent e) { private void initItems() { listData = new ArrayList(); for (long uid : player.getInventoryComponent()) { - Item item = (Item) context.getStore().getEntity(uid); + Item item = (Item) gameStores.getStore().getEntity(uid); if (item instanceof Weapon && ((Weapon) item).getState() < 100) { listData.add(item); } else if (item instanceof Armor && ((Armor) item).getState() < 100) { diff --git a/src/main/java/neon/ui/dialog/TattooDialog.java b/src/main/java/neon/ui/dialog/TattooDialog.java index d75d6c3..e36871d 100644 --- a/src/main/java/neon/ui/dialog/TattooDialog.java +++ b/src/main/java/neon/ui/dialog/TattooDialog.java @@ -25,7 +25,7 @@ import java.awt.event.KeyListener; import javax.swing.*; import javax.swing.border.*; -import neon.core.GameContext; +import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Player; import neon.resources.RTattoo; @@ -38,12 +38,12 @@ public class TattooDialog implements KeyListener { private JPanel panel; private String coin; private UserInterface ui; - private final GameContext context; + private final GameStores gameStores; - public TattooDialog(UserInterface ui, String coin, GameContext context) { + public TattooDialog(UserInterface ui, String coin, GameStores gameStores) { this.coin = coin; this.ui = ui; - this.context = context; + this.gameStores = gameStores; JFrame parent = ui.getWindow(); frame = new JDialog(parent, true); @@ -128,7 +128,7 @@ public void keyPressed(KeyEvent e) { } private void initTattoos() { - tattoos.setListData(context.getResources().getResources(RTattoo.class)); + tattoos.setListData(gameStores.getResources().getResources(RTattoo.class)); tattoos.setSelectedIndex(0); } diff --git a/src/main/java/neon/ui/dialog/TradeDialog.java b/src/main/java/neon/ui/dialog/TradeDialog.java index 6d8944c..27722ef 100644 --- a/src/main/java/neon/ui/dialog/TradeDialog.java +++ b/src/main/java/neon/ui/dialog/TradeDialog.java @@ -29,6 +29,7 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.handlers.InventoryHandler; import neon.entities.Creature; import neon.entities.Entity; @@ -52,17 +53,21 @@ public class TradeDialog implements KeyListener, ListSelectionListener { private String big, small; private UserInterface ui; private final GameContext context; + private final GameStores gameStores; + private final InventoryHandler inventoryHandler; /** * @param big name of major denominations (euro, dollar) * @param small name of minor denominations (cents) */ - public TradeDialog(UserInterface ui, String big, String small, GameContext context) { + public TradeDialog( + UserInterface ui, String big, String small, GameContext context, GameStores gameStores) { this.big = big; this.small = small; this.ui = ui; this.context = context; - + this.gameStores = gameStores; + this.inventoryHandler = new InventoryHandler(gameStores.getStore()); JFrame parent = ui.getWindow(); frame = new JDialog(parent, true); frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 100)); @@ -178,13 +183,13 @@ public void keyPressed(KeyEvent key) { private void initGoods() { Vector sellData = new Vector(); for (long uid : context.getPlayer().getInventoryComponent()) { - sellData.add((Item) context.getStore().getEntity(uid)); + sellData.add((Item) gameStores.getStore().getEntity(uid)); } sellList.setListData(sellData); Vector buyData = new Vector(); for (long uid : trader.getInventoryComponent()) { - buyData.add((Item) context.getStore().getEntity(uid)); + buyData.add((Item) gameStores.getStore().getEntity(uid)); } buyList.setListData(buyData); @@ -207,14 +212,14 @@ private void buy(Item item) { if (price > player.getInventoryComponent().getMoney()) { ui.showMessage("Not enough money to buy this item.", 2); } else { - InventoryHandler.removeItem(trader, item.getUID()); + inventoryHandler.removeItem(trader, item.getUID()); player.getInventoryComponent().addItem(item.getUID()); player.getInventoryComponent().addMoney(-price); } } private void sell(Item item) { - InventoryHandler.removeItem(player, item.getUID()); + inventoryHandler.removeItem(player, item.getUID()); trader.getInventoryComponent().addItem(item.getUID()); player.getInventoryComponent().addMoney(item.resource.cost); } diff --git a/src/main/java/neon/ui/dialog/TrainingDialog.java b/src/main/java/neon/ui/dialog/TrainingDialog.java index 84980dd..d117ef3 100644 --- a/src/main/java/neon/ui/dialog/TrainingDialog.java +++ b/src/main/java/neon/ui/dialog/TrainingDialog.java @@ -25,7 +25,7 @@ import java.util.EventObject; import javax.swing.*; import javax.swing.border.*; -import neon.core.GameContext; +import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Player; import neon.entities.property.Skill; @@ -42,12 +42,12 @@ public class TrainingDialog implements KeyListener { private JScrollPane scroller; private MBassador bus; private UserInterface ui; - private final GameContext context; + private final GameStores gameStores; - public TrainingDialog(UserInterface ui, MBassador bus, GameContext context) { + public TrainingDialog(UserInterface ui, MBassador bus, GameStores gameStores) { this.bus = bus; this.ui = ui; - this.context = context; + this.gameStores = gameStores; JFrame parent = ui.getWindow(); frame = new JDialog(parent, true); frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 100)); @@ -124,7 +124,7 @@ public void keyPressed(KeyEvent e) { private void initTraining() { DefaultListModel model = new DefaultListModel(); for (RPerson.Service service : - ((RPerson) context.getResources().getResource(trainer.getName())).services) { + ((RPerson) gameStores.getResources().getResource(trainer.getName())).services) { if (service.id.equals("training")) { for (String skillName : service.skills) { model.addElement(Skill.valueOf(skillName.toUpperCase())); diff --git a/src/main/java/neon/ui/dialog/TravelDialog.java b/src/main/java/neon/ui/dialog/TravelDialog.java index 2a6b1c4..64fadab 100644 --- a/src/main/java/neon/ui/dialog/TravelDialog.java +++ b/src/main/java/neon/ui/dialog/TravelDialog.java @@ -28,7 +28,7 @@ import java.util.HashMap; import javax.swing.*; import javax.swing.border.*; -import neon.core.GameContext; +import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Player; import neon.resources.RPerson; @@ -46,12 +46,13 @@ public class TravelDialog implements KeyListener { private JScrollPane scroller; private MBassador bus; private UserInterface ui; - private final GameContext context; + private final GameStores gameStores; - public TravelDialog(UserInterface ui, MBassador bus, GameContext context) { + public TravelDialog(UserInterface ui, MBassador bus, GameStores gameStores) { this.bus = bus; this.ui = ui; - this.context = context; + + this.gameStores = gameStores; JFrame parent = ui.getWindow(); frame = new JDialog(parent, true); frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 100)); @@ -133,7 +134,7 @@ private void initDestinations() { listData = new HashMap(); costData = new HashMap(); for (RPerson.Service service : - ((RPerson) context.getResources().getResource(agent.getID())).services) { + ((RPerson) gameStores.getResources().getResource(agent.getID())).services) { if (service.id.equals("travel")) { for (RPerson.Service.Destination dest : service.destinations) { listData.put(dest.name + ": " + dest.cost + " cp", new Point(dest.x, dest.y)); diff --git a/src/main/java/neon/ui/states/AimState.java b/src/main/java/neon/ui/states/AimState.java index 6f5aa92..7462c95 100644 --- a/src/main/java/neon/ui/states/AimState.java +++ b/src/main/java/neon/ui/states/AimState.java @@ -24,6 +24,7 @@ import java.util.*; import javax.swing.Popup; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.event.CombatEvent; import neon.core.event.MagicEvent; import neon.core.handlers.*; @@ -59,14 +60,23 @@ public class AimState extends State implements KeyListener { private MBassador bus; private UserInterface ui; private final GameContext context; - + private final GameStores gameStores; + private final CombatUtils combatUtils; /** Constructs a new AimModule. */ - public AimState(State state, MBassador bus, UserInterface ui, GameContext context) { + public AimState( + State state, + MBassador bus, + UserInterface ui, + GameContext context, + GameStores gameStores) { super(state); this.bus = bus; this.ui = ui; this.context = context; - keys = (CClient) context.getResources().getResource("client", "config"); + this.gameStores = gameStores; + this.combatUtils = new CombatUtils(gameStores.getStore()); + keys = (CClient) gameStores.getResources().getResource("client", "config"); + target = new Point(); } @@ -146,12 +156,12 @@ private void shoot() { Creature victim = context.getAtlasPosition().getCurrentZone().getCreature(target); if (victim != null) { Weapon ammo = - (Weapon) context.getStore().getEntity(player.getInventoryComponent().get(Slot.AMMO)); + (Weapon) gameStores.getStore().getEntity(player.getInventoryComponent().get(Slot.AMMO)); if (player.getInventoryComponent().hasEquiped(Slot.AMMO) && ammo.getWeaponType() == WeaponType.THROWN) { shoot(ammo, victim); bus.publishAsync(new CombatEvent(CombatEvent.FLING, player, victim)); - } else if (CombatUtils.getWeaponType(player) == WeaponType.BOW) { + } else if (combatUtils.getWeaponType(player) == WeaponType.BOW) { if (player.getInventoryComponent().hasEquiped(Slot.AMMO) && ammo.getWeaponType() == WeaponType.ARROW) { shoot(ammo, victim); @@ -159,7 +169,7 @@ private void shoot() { } else { ui.showMessage("No arrows equiped!", 1); } - } else if (CombatUtils.getWeaponType(player) == WeaponType.CROSSBOW) { + } else if (combatUtils.getWeaponType(player) == WeaponType.CROSSBOW) { if (player.getInventoryComponent().hasEquiped(Slot.AMMO) && ammo.getWeaponType() == WeaponType.BOLT) { bus.publishAsync(new CombatEvent(CombatEvent.SHOOT, player, victim)); @@ -217,7 +227,7 @@ private void cast() { bus.publishAsync(new MagicEvent.CreatureOnPoint(this, player, target)); } else if (player.getInventoryComponent().hasEquiped(Slot.MAGIC)) { Item item = - (Item) context.getStore().getEntity(player.getInventoryComponent().get(Slot.MAGIC)); + (Item) gameStores.getStore().getEntity(player.getInventoryComponent().get(Slot.MAGIC)); bus.publishAsync(new MagicEvent.ItemOnPoint(this, player, item, target)); } @@ -236,7 +246,7 @@ private void look() { String actors = ""; ArrayList things = new ArrayList(zone.getItems(target)); if (things.size() == 1) { - items = ", " + context.getStore().getEntity(things.get(0)); + items = ", " + gameStores.getStore().getEntity(things.get(0)); } else if (things.size() > 1) { items = ", several items"; } @@ -252,8 +262,8 @@ private void look() { private void act() { for (long uid : context.getAtlasPosition().getCurrentZone().getItems(target)) { - if (context.getStore().getEntity(uid) instanceof Door) { - bus.publishAsync(new TransitionEvent("door", "door", context.getStore().getEntity(uid))); + if (gameStores.getStore().getEntity(uid) instanceof Door) { + bus.publishAsync(new TransitionEvent("door", "door", gameStores.getStore().getEntity(uid))); break; } } diff --git a/src/main/java/neon/ui/states/BumpState.java b/src/main/java/neon/ui/states/BumpState.java index b22c00b..b0a29ba 100644 --- a/src/main/java/neon/ui/states/BumpState.java +++ b/src/main/java/neon/ui/states/BumpState.java @@ -24,6 +24,7 @@ import java.util.EventObject; import javax.swing.Popup; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.event.CombatEvent; import neon.core.handlers.MotionHandler; import neon.entities.Creature; @@ -43,10 +44,18 @@ public class BumpState extends State implements KeyListener { private MBassador bus; private UserInterface ui; private final GameContext context; + private final GameStores gameStores; + private final MotionHandler motionHandler; public BumpState( - State parent, MBassador bus, UserInterface ui, GameContext context) { + State parent, + MBassador bus, + UserInterface ui, + GameContext context, + GameStores gameStores) { super(parent); + this.gameStores = gameStores; + this.motionHandler = new MotionHandler(context,gameStores); this.bus = bus; this.ui = ui; this.context = context; @@ -126,7 +135,7 @@ private void swap() { Rectangle pBounds = player.getShapeComponent(); Rectangle cBounds = creature.getShapeComponent(); - if (MotionHandler.move(player, cBounds.x, cBounds.y) == MotionHandler.OK) { + if (motionHandler.move(player, cBounds.x, cBounds.y) == MotionHandler.OK) { cBounds.setLocation(pBounds.x, pBounds.y); } } diff --git a/src/main/java/neon/ui/states/ContainerState.java b/src/main/java/neon/ui/states/ContainerState.java index e348d99..02987fe 100644 --- a/src/main/java/neon/ui/states/ContainerState.java +++ b/src/main/java/neon/ui/states/ContainerState.java @@ -28,6 +28,7 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.handlers.InventoryHandler; import neon.core.handlers.MotionHandler; import neon.entities.Container; @@ -51,7 +52,7 @@ public class ContainerState extends State implements KeyListener, ListSelectionL private MBassador bus; private UserInterface ui; private final GameContext context; - + private final GameStores gameStores; // components of the JPanel private JPanel panel; private JList iList; @@ -61,14 +62,22 @@ public class ContainerState extends State implements KeyListener, ListSelectionL // lists private HashMap cData, iData; + private final InventoryHandler inventoryHandler; + private final MotionHandler motionHandler; public ContainerState( - State parent, MBassador bus, UserInterface ui, GameContext context) { + State parent, + MBassador bus, + UserInterface ui, + GameContext context, + GameStores gameStores) { super(parent); this.bus = bus; this.ui = ui; this.context = context; - + this.gameStores = gameStores; + this.inventoryHandler = new InventoryHandler(gameStores.getStore()); + this.motionHandler = new MotionHandler(context,gameStores); panel = new JPanel(new BorderLayout()); JPanel center = new JPanel(new java.awt.GridLayout(0, 3)); panel.addKeyListener(this); @@ -85,7 +94,7 @@ public ContainerState( center.add(iScroll); // description panel klaarmaken - CClient ini = (CClient) context.getResources().getResource("client", "config"); + CClient ini = (CClient) gameStores.getResources().getResource("client", "config"); description = new DescriptionPanel(ini.getSmall()); center.add(description); @@ -152,7 +161,7 @@ public void keyPressed(KeyEvent key) { try { if (iList.hasFocus()) { // drop something Item item = (Item) iList.getSelectedValue(); - InventoryHandler.removeItem(player, item.getUID()); + inventoryHandler.removeItem(player, item.getUID()); if (container instanceof Container) { // register change ((Container) container).addItem(item.getUID()); } else if (container instanceof Zone) { // adjust item position @@ -161,7 +170,7 @@ public void keyPressed(KeyEvent key) { iBounds.setLocation(pBounds.x, pBounds.y); context.getAtlasPosition().getCurrentZone().addItem(item); } else if (container instanceof Creature) { - InventoryHandler.addItem(((Creature) container), item.getUID()); + inventoryHandler.addItem(((Creature) container), item.getUID()); } update(); } else { // pick up something @@ -170,7 +179,7 @@ public void keyPressed(KeyEvent key) { bus.publishAsync(new TransitionEvent("return")); bus.publishAsync(new TransitionEvent("container", "holder", item)); } else if (item instanceof Door) { - MotionHandler.teleport(player, (Door) item); + motionHandler.teleport(player, (Door) item); bus.publishAsync(new TransitionEvent("return")); } else if (item instanceof Creature) { bus.publishAsync(new TransitionEvent("return")); @@ -179,11 +188,11 @@ public void keyPressed(KeyEvent key) { if (container instanceof Zone) { context.getAtlasPosition().getCurrentZone().removeItem((Item) item); } else if (container instanceof Creature) { - InventoryHandler.removeItem(((Creature) container), item.getUID()); + inventoryHandler.removeItem(((Creature) container), item.getUID()); } else { ((Container) container).removeItem(item.getUID()); } - InventoryHandler.addItem(player, item.getUID()); + inventoryHandler.addItem(player, item.getUID()); update(); } } @@ -219,7 +228,7 @@ private void update() { if (o instanceof Item) { item = (Item) o; } else { - item = (Item) context.getStore().getEntity((Long) o); + item = (Item) gameStores.getStore().getEntity((Long) o); } if (!cData.containsKey(item.getID())) { cData.put(item.getID(), 1); @@ -230,7 +239,7 @@ private void update() { } for (long uid : player.getInventoryComponent()) { - Item i = (Item) context.getStore().getEntity(uid); + Item i = (Item) gameStores.getStore().getEntity(uid); if (!iData.containsKey(i.getID())) { iData.put(i.getID(), 1); iBuffer.add(i); diff --git a/src/main/java/neon/ui/states/DialogState.java b/src/main/java/neon/ui/states/DialogState.java index ff8b2eb..b18116d 100644 --- a/src/main/java/neon/ui/states/DialogState.java +++ b/src/main/java/neon/ui/states/DialogState.java @@ -32,6 +32,7 @@ import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; import neon.core.GameContext; +import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Player; import neon.entities.components.HealthComponent; @@ -77,14 +78,20 @@ public class DialogState extends State implements KeyListener { private UserInterface ui; private Topic topic; private final GameContext context; + private final GameStores gameStores; public DialogState( - State parent, MBassador bus, UserInterface ui, GameContext context) { + State parent, + MBassador bus, + UserInterface ui, + GameContext context, + GameStores gameStores) { super(parent); this.bus = bus; this.ui = ui; this.context = context; - CClient ini = (CClient) context.getResources().getResource("client", "config"); + this.gameStores = gameStores; + CClient ini = (CClient) gameStores.getResources().getResource("client", "config"); big = ini.getSmall(); small = ini.getBig(); panel = new JPanel(new BorderLayout()); @@ -206,29 +213,30 @@ public void keyPressed(KeyEvent ke) { } else { String value = list.getSelectedValue().toString(); if (value.equals("travel")) { - new TravelDialog(ui, bus, context).show(context.getPlayer(), target); + new TravelDialog(ui, bus, gameStores).show(context.getPlayer(), target); } else if (value.equals("training")) { - new TrainingDialog(ui, bus, context).show(context.getPlayer(), target); + new TrainingDialog(ui, bus, gameStores).show(context.getPlayer(), target); } else if (value.equals("spells")) { new SpellTradeDialog(ui, big, small).show(context.getPlayer(), target); } else if (value.equals("trade")) { - new TradeDialog(ui, big, small, context).show(context.getPlayer(), target); + new TradeDialog(ui, big, small, context, gameStores).show(context.getPlayer(), target); } else if (value.equals("spell maker")) { new SpellMakerDialog(ui).show(context.getPlayer(), target); } else if (value.equals("potion maker")) { - new PotionDialog(ui, small, context).show(context.getPlayer(), target); + new PotionDialog(ui, small, gameStores).show(context.getPlayer(), target); } else if (value.equals("healer")) { heal(); } else if (value.equals("charge")) { new ChargeDialog(ui, context).show(context.getPlayer()); } else if (value.equals("craft")) { - new CrafterDialog(ui, small, bus, context).show(context.getPlayer(), target); + new CrafterDialog(ui, small, bus, context, gameStores) + .show(context.getPlayer(), target); } else if (value.equals("enchant")) { - new EnchantDialog(ui, context).show(context.getPlayer(), target); + new EnchantDialog(ui, context, gameStores).show(context.getPlayer(), target); } else if (value.equals("repair")) { - new RepairDialog(ui, context).show(context.getPlayer(), target); + new RepairDialog(ui, gameStores).show(context.getPlayer(), target); } else if (value.equals("tattoos")) { - new TattooDialog(ui, small, context).show(context.getPlayer(), target); + new TattooDialog(ui, small, gameStores).show(context.getPlayer(), target); } else { System.out.println("not implemented"); } @@ -305,7 +313,7 @@ private void initServices() { private boolean hasService(String name, String id) { try { - RPerson person = (RPerson) context.getResources().getResource(name); + RPerson person = (RPerson) gameStores.getResources().getResource(name); for (RPerson.Service service : person.services) { if (service.id.equals(id)) { return true; diff --git a/src/main/java/neon/ui/states/DoorState.java b/src/main/java/neon/ui/states/DoorState.java index c4a7ee1..1fca920 100644 --- a/src/main/java/neon/ui/states/DoorState.java +++ b/src/main/java/neon/ui/states/DoorState.java @@ -23,6 +23,7 @@ import java.util.EventObject; import javax.swing.Popup; import neon.core.GameContext; +import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Door; import neon.entities.Player; @@ -39,12 +40,19 @@ public class DoorState extends State implements KeyListener { private MBassador bus; private UserInterface ui; private final GameContext context; + private final GameStores gameStores; - public DoorState(State state, MBassador bus, UserInterface ui, GameContext context) { + public DoorState( + State state, + MBassador bus, + UserInterface ui, + GameContext context, + GameStores gameStores) { super(state); this.bus = bus; this.ui = ui; this.context = context; + this.gameStores = gameStores; } @Override @@ -138,7 +146,7 @@ public void keyPressed(KeyEvent ke) { private boolean hasItem(Creature creature, RItem item) { for (long uid : creature.getInventoryComponent()) { - if (context.getStore().getEntity(uid).getID().equals(item.id)) { + if (gameStores.getStore().getEntity(uid).getID().equals(item.id)) { return true; } } diff --git a/src/main/java/neon/ui/states/GameState.java b/src/main/java/neon/ui/states/GameState.java index df21691..0c10fe5 100644 --- a/src/main/java/neon/ui/states/GameState.java +++ b/src/main/java/neon/ui/states/GameState.java @@ -24,8 +24,10 @@ import java.util.Scanner; import lombok.extern.slf4j.Slf4j; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.ScriptInterface; import neon.core.event.*; +import neon.core.handlers.CombatUtils; import neon.core.handlers.TurnHandler; import neon.entities.Player; import neon.entities.components.HealthComponent; @@ -48,20 +50,26 @@ public class GameState extends State implements KeyListener, CollisionListener { private MBassador bus; private UserInterface ui; private final GameContext context; + private final GameStores gameStores; public GameState( - State parent, MBassador bus, UserInterface ui, GameContext context) { + State parent, + MBassador bus, + UserInterface ui, + GameContext context, + GameStores gameStores) { super(parent, "game module"); this.bus = bus; this.ui = ui; this.context = context; - keys = (CClient) context.getResources().getResource("client", "config"); - panel = new GamePanel(context); + keys = (CClient) gameStores.getResources().getResource("client", "config"); + panel = new GamePanel(context,new CombatUtils(gameStores.getStore())); + this.gameStores = gameStores; setVariable("panel", panel); // makes functions available for scripting: - context.getScriptEngine().getBindings("js").putMember("engine", new ScriptInterface(panel)); - bus.subscribe(new TurnHandler(panel)); + context.getScriptEngine().getBindings("js").putMember("engine", new ScriptInterface(panel,gameStores.getStore(),context)); + bus.subscribe(new TurnHandler(panel, gameStores)); } @Override @@ -162,12 +170,12 @@ public void collisionOccured(CollisionEvent event) { try { if (one.equals(0L) && two instanceof neon.maps.Region) { for (String s : ((neon.maps.Region) two).getScripts()) { - RScript rs = (RScript) context.getResources().getResource(s, "script"); + RScript rs = (RScript) gameStores.getResources().getResource(s, "script"); context.execute(rs.script); } } else if (one instanceof neon.maps.Region && two.equals(0L)) { for (String s : ((neon.maps.Region) one).getScripts()) { - RScript rs = (RScript) context.getResources().getResource(s, "script"); + RScript rs = (RScript) gameStores.getResources().getResource(s, "script"); context.execute(rs.script); } } diff --git a/src/main/java/neon/ui/states/InventoryState.java b/src/main/java/neon/ui/states/InventoryState.java index ad8f22b..6e4501a 100644 --- a/src/main/java/neon/ui/states/InventoryState.java +++ b/src/main/java/neon/ui/states/InventoryState.java @@ -26,6 +26,7 @@ import javax.swing.*; import javax.swing.border.*; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.handlers.InventoryHandler; import neon.core.handlers.MagicHandler; import neon.core.handlers.SkillHandler; @@ -53,15 +54,24 @@ public class InventoryState extends State implements KeyListener, MouseListener private MBassador bus; private UserInterface ui; private final GameContext context; + private final GameStores gameStores; + private final MagicHandler magicHandler; + private final InventoryHandler inventoryHandler; public InventoryState( - State parent, MBassador bus, UserInterface ui, GameContext context) { + State parent, + MBassador bus, + UserInterface ui, + GameContext context, + GameStores gameStores) { super(parent, "inventory module"); this.bus = bus; this.ui = ui; this.context = context; + this.gameStores = gameStores; panel = new JPanel(new BorderLayout()); - + magicHandler = new MagicHandler(context.getQueue(), gameStores, context); + inventoryHandler = new InventoryHandler(gameStores.getStore()); // info info = new JLabel(); info.setBorder( @@ -82,7 +92,7 @@ public InventoryState( scroller.setBorder(new TitledBorder("Inventory")); contents.add(scroller); - CClient ini = (CClient) context.getResources().getResource("client", "config"); + CClient ini = (CClient) gameStores.getResources().getResource("client", "config"); description = new DescriptionPanel(ini.getSmall()); contents.add(description); @@ -111,29 +121,29 @@ public void enter(TransitionEvent t) { private void use(Item item) { // System.out.println(item.getClass()); if (item instanceof Item.Potion) { - InventoryHandler.removeItem(player, item.getUID()); - MagicHandler.drink(player, (Item.Potion) item); + inventoryHandler.removeItem(player, item.getUID()); + magicHandler.drink(player, (Item.Potion) item); initList(); } else if (item instanceof Item.Book && !(item instanceof Item.Scroll)) { RText text = (RText) - context + gameStores .getResources() .getResource(((RItem.Text) item.resource).content + ".html", "text"); new BookDialog(ui.getWindow()).show(item.toString(), text.getText()); } else if (item instanceof Item.Food) { - InventoryHandler.removeItem(player, item.getUID()); - MagicHandler.eat(player, (Item.Food) item); + inventoryHandler.removeItem(player, item.getUID()); + magicHandler.eat(player, (Item.Food) item); initList(); } else if (item instanceof Item.Aid) { - InventoryHandler.removeItem(player, item.getUID()); + inventoryHandler.removeItem(player, item.getUID()); initList(); HealthComponent health = player.getHealthComponent(); health.heal(SkillHandler.check(player, Skill.MEDICAL) / 5f); } else if (!player.getInventoryComponent().hasEquiped(item.getUID())) { - InventoryHandler.equip(item, player); + inventoryHandler.equip(item, player); } else { - InventoryHandler.unequip(item.getUID(), player); + inventoryHandler.unequip(item.getUID(), player); } inventory.repaint(); } @@ -143,7 +153,7 @@ private void initList() { listData.clear(); for (long uid : context.getPlayer().getInventoryComponent()) { - Item i = (Item) context.getStore().getEntity(uid); + Item i = (Item) gameStores.getStore().getEntity(uid); if (!listData.containsKey(i.getID())) { listData.put(i.getID(), 1); buffer.add(i); @@ -154,7 +164,7 @@ private void initList() { info.setText( "Weight: " - + InventoryHandler.getWeight(player) + + inventoryHandler.getWeight(player) + " kg. Money: " + moneyString(player.getInventoryComponent().getMoney()) + "."); @@ -167,7 +177,7 @@ private String moneyString(int money) { } else { int gold = money / 100; int copper = money % 100; - CClient ini = (CClient) context.getResources().getResource("client", "config"); + CClient ini = (CClient) gameStores.getResources().getResource("client", "config"); return gold + " " + ini.getBig() + " and " + copper + " " + ini.getSmall(); } } @@ -200,7 +210,7 @@ public void keyPressed(KeyEvent e) { case KeyEvent.VK_SPACE: if (inventory.getSelectedValue() != null) { Item item = inventory.getSelectedValue(); - InventoryHandler.removeItem(player, item.getUID()); + inventoryHandler.removeItem(player, item.getUID()); Rectangle pBounds = player.getShapeComponent(); Rectangle iBounds = item.getShapeComponent(); iBounds.setLocation(pBounds.x, pBounds.y); diff --git a/src/main/java/neon/ui/states/JournalState.java b/src/main/java/neon/ui/states/JournalState.java index 4b30a76..9cbe65f 100644 --- a/src/main/java/neon/ui/states/JournalState.java +++ b/src/main/java/neon/ui/states/JournalState.java @@ -24,6 +24,7 @@ import javax.swing.*; import javax.swing.border.*; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.handlers.CombatUtils; import neon.core.handlers.InventoryHandler; import neon.entities.Player; @@ -53,18 +54,27 @@ public class JournalState extends State implements FocusListener { private JPanel stats, stuff, skills; private JPanel feats, traits, abilities; private JScrollPane skillScroller, featScroller, traitScroller, abilityScroller; - + private final GameStores gameStores; + private final InventoryHandler inventoryHandler; + private final CombatUtils combatUtils; // spells panel private JList sList; public JournalState( - State parent, MBassador bus, UserInterface ui, GameContext context) { + State parent, + MBassador bus, + UserInterface ui, + GameContext context, + GameStores gameStores) { super(parent); + this.bus = bus; this.ui = ui; this.context = context; + this.gameStores = gameStores; main = new JPanel(new BorderLayout()); - + inventoryHandler = new InventoryHandler(gameStores.getStore()); + combatUtils = new CombatUtils(gameStores.getStore()); // cardlayout om verschillende panels weer te geven. layout = new CardLayout(); cards = new JPanel(layout); @@ -221,7 +231,7 @@ private void initStats() { stuff.add( new JLabel( "Encumbrance: " - + InventoryHandler.getWeight(player) + + inventoryHandler.getWeight(player) + " (of " + light + "/" @@ -229,7 +239,7 @@ private void initStats() { + "/" + heavy + ") kg")); - stuff.add(new JLabel("Defense value: " + CombatUtils.getDV(player))); + stuff.add(new JLabel("Defense value: " + combatUtils.getDV(player))); stuff.add(new JLabel("Attack value: " + player.getAVString())); for (Skill skill : Skill.values()) { diff --git a/src/main/java/neon/ui/states/MainMenuState.java b/src/main/java/neon/ui/states/MainMenuState.java index 25d74e0..9b61bd5 100644 --- a/src/main/java/neon/ui/states/MainMenuState.java +++ b/src/main/java/neon/ui/states/MainMenuState.java @@ -29,6 +29,7 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; import neon.core.GameContext; +import neon.core.GameStores; import neon.resources.CClient; import neon.ui.UserInterface; import neon.ui.dialog.LoadGameDialog; @@ -43,25 +44,27 @@ public class MainMenuState extends State { private MBassador bus; private UserInterface ui; private final GameContext context; + private final GameStores gameStores; public MainMenuState( State parent, MBassador bus, UserInterface ui, String version, - GameContext context) { + GameContext context, + GameStores gameStores) { super(parent, "main menu"); this.bus = bus; this.ui = ui; this.context = context; - + this.gameStores = gameStores; // the main menu JPanel itself main = new JPanel(new BorderLayout()); JPanel buttons = new JPanel(new GridLayout(0, 1)); buttons.setBorder(new EmptyBorder(70, 120, 70, 120)); - CClient ini = (CClient) context.getResources().getResource("client", "config"); + CClient ini = (CClient) gameStores.getResources().getResource("client", "config"); JLabel title = new JLabel("" + ini.getTitle() + "", JLabel.CENTER); @@ -128,11 +131,11 @@ public ButtonAction(String text, String command) { public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("n")) { - new NewGameDialog(ui, bus, context).show(); + new NewGameDialog(ui, bus, gameStores).show(); } else if (e.getActionCommand().equals("l")) { new LoadGameDialog(ui.getWindow(), bus).show(); } else if (e.getActionCommand().equals("o")) { - new OptionDialog(ui.getWindow(), context).show(); + new OptionDialog(ui.getWindow(), context, gameStores).show(); } else if (e.getActionCommand().equals("q")) { System.exit(0); } diff --git a/src/main/java/neon/ui/states/MoveState.java b/src/main/java/neon/ui/states/MoveState.java index 825fa33..f9aa29d 100644 --- a/src/main/java/neon/ui/states/MoveState.java +++ b/src/main/java/neon/ui/states/MoveState.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.EventObject; import neon.core.GameContext; +import neon.core.GameStores; import neon.core.event.CombatEvent; import neon.core.event.MagicEvent; import neon.core.event.TurnEvent; @@ -46,12 +47,19 @@ public class MoveState extends State implements KeyListener { private CClient keys; private MBassador bus; private final GameContext context; + private final GameStores gameStores; + private final InventoryHandler inventoryHandler; + private final MotionHandler motionHandler; - public MoveState(State parent, MBassador bus, GameContext context) { + public MoveState( + State parent, MBassador bus, GameContext context, GameStores gameStores) { super(parent, "move module"); this.bus = bus; this.context = context; - keys = (CClient) context.getResources().getResource("client", "config"); + this.gameStores = gameStores; + keys = (CClient) gameStores.getResources().getResource("client", "config"); + inventoryHandler = new InventoryHandler(gameStores.getStore()); + motionHandler = new MotionHandler(context,gameStores); } @Override @@ -81,11 +89,11 @@ private void move(int x, int y) { bus.publishAsync(new TransitionEvent("bump", "creature", other)); } } else { // no one in the way, so move - if (MotionHandler.move(player, p) == MotionHandler.DOOR) { + if (motionHandler.move(player, p) == MotionHandler.DOOR) { for (long uid : context.getAtlasPosition().getCurrentZone().getItems(p)) { - if (context.getStore().getEntity(uid) instanceof Door) { + if (gameStores.getStore().getEntity(uid) instanceof Door) { bus.publishAsync( - new TransitionEvent("door", "door", context.getStore().getEntity(uid))); + new TransitionEvent("door", "door", gameStores.getStore().getEntity(uid))); } } } @@ -107,7 +115,7 @@ private void act() { } if (items.size() == 1) { - Entity entity = context.getStore().getEntity(items.get(0)); + Entity entity = gameStores.getStore().getEntity(items.get(0)); if (entity instanceof Container) { Container container = (Container) entity; if (container.lock.isLocked()) { @@ -120,14 +128,14 @@ private void act() { bus.publishAsync(new TransitionEvent("container", "holder", entity)); } } else if (entity instanceof Door) { - if (MotionHandler.teleport(player, (Door) entity) == MotionHandler.OK) { + if (motionHandler.teleport(player, (Door) entity) == MotionHandler.OK) { bus.publishAsync(new TurnEvent(context.getTimer().addTick())); } } else if (entity instanceof Creature) { bus.publishAsync(new TransitionEvent("container", "holder", entity)); } else { context.getAtlasPosition().getCurrentZone().removeItem((Item) entity); - InventoryHandler.addItem(player, entity.getUID()); + inventoryHandler.addItem(player, entity.getUID()); } } else if (items.size() > 1) { bus.publishAsync( @@ -186,7 +194,7 @@ public void keyPressed(KeyEvent key) { } } else if (player.getInventoryComponent().hasEquiped(Slot.MAGIC)) { Item item = - (Item) context.getStore().getEntity(player.getInventoryComponent().get(Slot.MAGIC)); + (Item) gameStores.getStore().getEntity(player.getInventoryComponent().get(Slot.MAGIC)); if (item.getMagicComponent().getSpell().range > 0) { bus.publishAsync(new TransitionEvent("aim")); } else { @@ -198,7 +206,7 @@ public void keyPressed(KeyEvent key) { private boolean hasItem(Creature creature, RItem item) { for (long uid : creature.getInventoryComponent()) { - if (context.getStore().getEntity(uid).getID().equals(item.id)) { + if (gameStores.getStore().getEntity(uid).getID().equals(item.id)) { return true; } } diff --git a/src/main/java/neon/util/Graph.java b/src/main/java/neon/util/Graph.java index 6f80350..9c10ccf 100644 --- a/src/main/java/neon/util/Graph.java +++ b/src/main/java/neon/util/Graph.java @@ -18,14 +18,16 @@ package neon.util; +import java.io.Serial; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; public class Graph implements Serializable { + @Serial private static final long serialVersionUID = -6431348687813884897L; - private HashMap> nodes = new HashMap>(); + private final HashMap> nodes = new HashMap>(); /** * Adds a node to the graph. Any existing node with the given index is overwritten. Connections to @@ -86,9 +88,10 @@ public Collection getNodes() { } private static class Node implements Serializable { + @Serial private static final long serialVersionUID = 2326885959259937816L; - private T content; - private ArrayList connections = new ArrayList(); + private final T content; + private final ArrayList connections = new ArrayList(); private Node(T content) { this.content = content; diff --git a/src/test/java/neon/maps/AtlasIntegrationTest.java b/src/test/java/neon/maps/AtlasIntegrationTest.java index 503975a..c92e4ee 100644 --- a/src/test/java/neon/maps/AtlasIntegrationTest.java +++ b/src/test/java/neon/maps/AtlasIntegrationTest.java @@ -32,15 +32,15 @@ void setUp() throws Exception { new Atlas( TestEngineContext.getStubFileSystem(), "test-atlas", - TestEngineContext.getTestEntityStore(), + TestEngineContext.getTestStore(), TestEngineContext.getMapLoader()); atlasPosition = new AtlasPosition( atlas, TestEngineContext.getTestZoneActivator(), TestEngineContext.getTestResources(), - new QuestTracker(), - TestEngineContext.getTestEntityStore()); + new QuestTracker(TestEngineContext.getGameStores()), + TestEngineContext.getTestStore()); } @AfterEach @@ -54,6 +54,7 @@ void tearDown() { @Test void testZoneUsesAtlasDatabase() { + Zone worldZone = World world = new World("DB Test World", 1000); atlasPosition.setMap(world); diff --git a/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java b/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java index 696aefa..eabbe60 100644 --- a/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java +++ b/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java @@ -6,11 +6,12 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; + +import neon.entities.UIDStore; import neon.maps.Atlas; import neon.maps.MapUtils; import neon.maps.Region; import neon.maps.Zone; -import neon.maps.services.EntityStore; import neon.resources.RRegionTheme; import neon.test.MapDbTestHelper; import neon.test.TestEngineContext; @@ -111,7 +112,7 @@ static Stream townThemeProviderSingleSeed() { class GenerateWithFullContextTests { private MapStore testDb; private Atlas testAtlas; - private EntityStore entityStore; + private UIDStore entityStore; @BeforeEach void setUp() throws Exception { @@ -119,7 +120,7 @@ void setUp() throws Exception { TestEngineContext.initialize(testDb); TestEngineContext.loadTestResourceViaConfig("src/test/resources/neon.ini.sampleMod1.xml"); testAtlas = TestEngineContext.getTestAtlas(); - entityStore = TestEngineContext.getTestEntityStore(); + entityStore = TestEngineContext.getTestEntityStore() } @AfterEach diff --git a/src/test/java/neon/test/TestEngineContext.java b/src/test/java/neon/test/TestEngineContext.java index f239b5b..30135d2 100644 --- a/src/test/java/neon/test/TestEngineContext.java +++ b/src/test/java/neon/test/TestEngineContext.java @@ -1,17 +1,17 @@ package neon.test; import java.awt.Rectangle; -import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import neon.core.DefaultGameStores; import neon.core.Engine; import neon.core.Game; +import neon.core.GameStores; import neon.core.event.TaskQueue; import neon.entities.Entity; import neon.entities.Player; -import neon.entities.UIDStore; import neon.entities.components.PhysicsComponent; import neon.entities.property.Gender; import neon.maps.*; @@ -23,9 +23,6 @@ import neon.systems.physics.PhysicsSystem; import neon.util.mapstorage.MapStore; import org.h2.mvstore.MVStore; -import org.jdom2.Document; -import org.jdom2.Element; -import org.jdom2.input.SAXBuilder; /** * Test utility for managing Engine singleton dependencies in tests. @@ -40,10 +37,12 @@ public class TestEngineContext { /** -- GETTER -- Gets the test Atlas instance. */ @Getter private static Atlas testAtlas; - +@Getter + private static GameStores gameStores; + @Getter private static StubResourceManager testResources; private static Game testGame; - private static UIDStore testStore; + @Getter private static neon.entities.UIDStore testStore; @Getter private static PhysicsManager stubPhysicsManager; @Getter private static AtlasPosition atlasPosition; @@ -51,9 +50,6 @@ public class TestEngineContext { /** -- GETTER -- Gets the test ZoneFactory instance. */ @Getter private static ZoneFactory testZoneFactory; - /** -- GETTER -- Gets the test ResourceProvider instance. */ - @Getter private static EntityStore testEntityStore; - @Getter private static ZoneActivator testZoneActivator; @Getter private static PhysicsSystem physicsSystem; @@ -96,10 +92,10 @@ public static void initialize(MapStore db) throws Exception { setStaticField(Engine.class, "resources", testResources); // Create test UIDStore - testStore = new UIDStore(testDb); - questTracker = new QuestTracker(); + testStore = new neon.entities.UIDStore(testDb); + // Create test EntityStore - testEntityStore = new StubEntityStore(testStore); + // Create stub PhysicsManager and ZoneActivator stubPhysicsManager = new StubPhysicsManager(); @@ -108,15 +104,18 @@ public static void initialize(MapStore db) throws Exception { // Create ZoneFactory for tests testZoneFactory = new ZoneFactory(db); - mapLoader = new MapLoader(testEntityStore, testResources, getStubFileSystem()); + mapLoader = new MapLoader( getStubFileSystem(),testStore, testResources); // Create test Atlas with dependency injection (doesn't need Engine.game) - testAtlas = new Atlas(getStubFileSystem(), testDb, getTestEntityStore(), mapLoader); + testAtlas = new Atlas(getStubFileSystem(), testDb, testStore, mapLoader); + gameStores = + new DefaultGameStores(getTestResources(), getStubFileSystem(), testStore, testAtlas); + questTracker = new QuestTracker(gameStores); atlasPosition = new AtlasPosition( - testAtlas, testZoneActivator, testResources, questTracker, testEntityStore); + testAtlas, testZoneActivator, testResources, questTracker, testStore); // Create test Game using new DI constructor - testGame = new Game(stubPlayer, testAtlas, testStore, atlasPosition); + testGame = new Game(stubPlayer, gameStores, atlasPosition); setStaticField(Engine.class, "game", testGame); // Create stub FileSystem @@ -127,8 +126,7 @@ public static void initialize(MapStore db) throws Exception { // Create and initialize test GameContext testContext = new neon.core.DefaultGameContext(); - testContext.setResources(testResources); - testContext.setFileSystem(stubFileSystem); + testContext.setPhysicsEngine(new StubPhysicsSystem()); testContext.setQueue(new neon.core.event.TaskQueue()); testContext.setGame(testGame); @@ -185,81 +183,6 @@ public static void loadTestResourceViaConfig(String configFilename) throws Excep iniBuilder.build(getTestResources()); } - /** - * Loads test resources from a mod path following the same pattern as ModLoader. - * - *

Loads items, creatures, terrain, and themes from XML files in the specified path. - * - * @param modPath the path to the mod directory (e.g., "src/test/resources/sampleMod1") - */ - public static void loadTestResources(String modPath) throws Exception { - SAXBuilder builder = new SAXBuilder(); - - // Load items - File itemsFile = new File(modPath + "/objects/items.xml"); - if (itemsFile.exists()) { - Document doc = builder.build(itemsFile); - for (Element e : doc.getRootElement().getChildren()) { - switch (e.getName()) { - case "book", "scroll" -> Engine.getResources().addResource(new RItem.Text(e)); - case "weapon" -> Engine.getResources().addResource(new RWeapon(e)); - case "door" -> Engine.getResources().addResource(new RItem.Door(e)); - case "potion" -> Engine.getResources().addResource(new RItem.Potion(e)); - case "container" -> Engine.getResources().addResource(new RItem.Container(e)); - case "armor", "clothing" -> Engine.getResources().addResource(new RClothing(e)); - case "list" -> Engine.getResources().addResource(new LItem(e)); - default -> Engine.getResources().addResource(new RItem(e)); - } - } - } - - // Load creatures - File monstersFile = new File(modPath + "/objects/monsters.xml"); - if (monstersFile.exists()) { - Document doc = builder.build(monstersFile); - for (Element c : doc.getRootElement().getChildren()) { - switch (c.getName()) { - case "list" -> Engine.getResources().addResource(new LCreature(c)); - default -> Engine.getResources().addResource(new RCreature(c)); - } - } - } - - // Load terrain - File terrainFile = new File(modPath + "/terrain.xml"); - if (terrainFile.exists()) { - Document doc = builder.build(terrainFile); - for (Element e : doc.getRootElement().getChildren()) { - Engine.getResources().addResource(new RTerrain(e), "terrain"); - } - } - - // Load themes - File dungeonsFile = new File(modPath + "/themes/dungeons.xml"); - if (dungeonsFile.exists()) { - Document doc = builder.build(dungeonsFile); - for (Element theme : doc.getRootElement().getChildren("dungeon")) { - Engine.getResources().addResource(new RDungeonTheme(theme), "theme"); - } - } - - File zonesFile = new File(modPath + "/themes/zones.xml"); - if (zonesFile.exists()) { - Document doc = builder.build(zonesFile); - for (Element theme : doc.getRootElement().getChildren("zone")) { - Engine.getResources().addResource(new RZoneTheme(theme), "theme"); - } - } - - File regionsFile = new File(modPath + "/themes/regions.xml"); - if (regionsFile.exists()) { - Document doc = builder.build(regionsFile); - for (Element theme : doc.getRootElement().getChildren("region")) { - Engine.getResources().addResource(new RRegionTheme(theme), "theme"); - } - } - } - /** Sets a static field using reflection. */ private static void setStaticField(Class clazz, String fieldName, Object value) throws Exception { @@ -301,9 +224,9 @@ static class StubPhysicsSystem extends PhysicsSystem { /** Stub EntityStore for testing. */ static class StubEntityStore implements EntityStore { - private final UIDStore store; + private final neon.entities.UIDStore store; - public StubEntityStore(UIDStore store) { + public StubEntityStore(neon.entities.UIDStore store) { this.store = store; } @@ -356,7 +279,7 @@ static class StubPlayer extends Player { private final PhysicsComponent physicsComponent; public StubPlayer() { - super(new RCreature("test"), "TestPlayer", Gender.MALE, Specialisation.combat, "Warrior"); + super(new RCreature("test"), "TestPlayer", Gender.MALE, Specialisation.combat, "Warrior",getGameStores()); this.physicsComponent = new PhysicsComponent(0L, new Rectangle(0, 0, 1, 1)); } From eb38679d10eb243cdae036b6194f200e91fd1973 Mon Sep 17 00:00:00 2001 From: Peter Riewe Date: Tue, 13 Jan 2026 01:22:24 +0000 Subject: [PATCH 05/12] Checkpoint --- pom.xml | 6 +- src/main/java/neon/ai/AI.java | 77 +- src/main/java/neon/ai/AIFactory.java | 26 +- src/main/java/neon/ai/BasicAI.java | 20 +- src/main/java/neon/ai/GuardAI.java | 23 +- src/main/java/neon/ai/HuntBehaviour.java | 15 +- src/main/java/neon/ai/PathFinder.java | 25 +- src/main/java/neon/ai/ScheduleAI.java | 21 +- .../java/neon/core/DefaultGameStores.java | 25 +- src/main/java/neon/core/Engine.java | 5 +- src/main/java/neon/core/Game.java | 9 +- src/main/java/neon/core/GameLoader.java | 35 +- src/main/java/neon/core/ScriptInterface.java | 11 +- .../neon/core/handlers/CombatHandler.java | 1 + .../neon/core/handlers/MotionHandler.java | 90 +- .../neon/core/handlers/TeleportHandler.java | 98 ++ .../java/neon/core/handlers/TurnHandler.java | 8 +- src/main/java/neon/editor/CCEditor.java | 819 +++++------ src/main/java/neon/editor/DataStore.java | 92 +- src/main/java/neon/editor/Editor.java | 1291 ++++++++--------- src/main/java/neon/editor/EventEditor.java | 394 ++--- src/main/java/neon/editor/InfoEditor.java | 16 +- .../java/neon/editor/ModCellRenderer.java | 8 +- src/main/java/neon/editor/ModFiler.java | 85 +- .../java/neon/editor/NewObjectDialog.java | 9 +- src/main/java/neon/editor/ObjectNode.java | 22 +- .../neon/editor/ObjectTransferHandler.java | 12 +- .../java/neon/editor/ObjectTreeListener.java | 482 +++--- src/main/java/neon/editor/ResourceAction.java | 52 +- src/main/java/neon/editor/ResourceNode.java | 9 +- .../neon/editor/ResourceTreeListener.java | 294 ++-- src/main/java/neon/editor/ScriptEditor.java | 338 ++--- .../neon/editor/editors/AfflictionEditor.java | 270 ++-- .../neon/editor/editors/AlchemyEditor.java | 260 ++-- .../java/neon/editor/editors/ArmorEditor.java | 18 +- .../java/neon/editor/editors/BookEditor.java | 335 ++--- .../neon/editor/editors/ClothingEditor.java | 420 +++--- .../neon/editor/editors/ContainerEditor.java | 365 ++--- .../neon/editor/editors/CraftingEditor.java | 245 ++-- .../neon/editor/editors/CreatureEditor.java | 8 +- .../java/neon/editor/editors/DoorEditor.java | 322 ++-- .../editor/editors/DungeonThemeEditor.java | 266 ++-- .../editor/editors/EnchantmentEditor.java | 390 ++--- .../neon/editor/editors/FactionEditor.java | 108 +- .../java/neon/editor/editors/FoodEditor.java | 374 ++--- .../java/neon/editor/editors/ItemEditor.java | 13 +- .../editor/editors/LevelCreatureEditor.java | 280 ++-- .../neon/editor/editors/LevelItemEditor.java | 280 ++-- .../neon/editor/editors/LevelSpellEditor.java | 266 ++-- .../java/neon/editor/editors/LightEditor.java | 320 ++-- .../java/neon/editor/editors/MoneyEditor.java | 280 ++-- .../java/neon/editor/editors/NPCEditor.java | 20 +- .../neon/editor/editors/PoisonEditor.java | 298 ++-- .../neon/editor/editors/PotionEditor.java | 376 ++--- .../java/neon/editor/editors/PowerEditor.java | 382 ++--- .../java/neon/editor/editors/QuestEditor.java | 629 ++++---- .../editor/editors/RegionThemeEditor.java | 519 +++---- .../neon/editor/editors/ScrollEditor.java | 412 +++--- .../java/neon/editor/editors/SignEditor.java | 394 ++--- .../java/neon/editor/editors/SpellEditor.java | 8 +- .../neon/editor/editors/TattooEditor.java | 248 ++-- .../neon/editor/editors/TerrainEditor.java | 238 +-- .../neon/editor/editors/WeaponEditor.java | 32 +- .../neon/editor/editors/ZoneThemeEditor.java | 14 +- .../java/neon/editor/help/HelpLabels.java | 16 +- .../editor/maps/ContainerInstanceEditor.java | 16 +- .../neon/editor/maps/DoorInstanceEditor.java | 15 +- .../java/neon/editor/maps/EditablePane.java | 25 +- .../java/neon/editor/maps/LevelDialog.java | 11 +- src/main/java/neon/editor/maps/MapDialog.java | 11 +- src/main/java/neon/editor/maps/MapEditor.java | 29 +- .../java/neon/editor/maps/MapInfoEditor.java | 12 +- .../neon/editor/maps/MapTreeListener.java | 56 +- .../java/neon/editor/maps/MapTreeNode.java | 8 +- .../editor/maps/RegionInstanceEditor.java | 26 +- .../neon/editor/maps/TerrainListener.java | 14 +- .../java/neon/editor/maps/ZoneEditor.java | 13 +- .../java/neon/editor/maps/ZoneTreeNode.java | 26 +- .../neon/editor/resources/IContainer.java | 21 +- .../java/neon/editor/resources/IDoor.java | 23 +- .../java/neon/editor/resources/IObject.java | 12 +- .../java/neon/editor/resources/IPerson.java | 15 +- .../java/neon/editor/resources/IRegion.java | 21 +- .../java/neon/editor/resources/Instance.java | 8 +- src/main/java/neon/editor/resources/RMap.java | 33 +- .../java/neon/editor/resources/RZone.java | 23 +- .../services/EditorResourceProvider.java | 41 - ...ntityFactory.java => CreatureFactory.java} | 100 +- src/main/java/neon/entities/ItemFactory.java | 104 ++ src/main/java/neon/entities/Player.java | 75 +- src/main/java/neon/entities/UIDStore.java | 10 +- .../java/neon/entities/components/Portal.java | 12 +- .../serialization/CreatureSerializer.java | 19 +- .../serialization/EntitySerializer.java | 18 +- .../serialization/ItemSerializer.java | 20 +- src/main/java/neon/magic/DefaultHandler.java | 2 +- src/main/java/neon/maps/Atlas.java | 2 +- src/main/java/neon/maps/AtlasPosition.java | 58 +- src/main/java/neon/maps/Dungeon.java | 10 +- src/main/java/neon/maps/MapLoader.java | 104 +- src/main/java/neon/maps/Zone.java | 22 +- src/main/java/neon/maps/ZoneActivator.java | 2 +- src/main/java/neon/maps/ZoneFactory.java | 14 +- .../maps/generators/DungeonGenerator.java | 293 +--- .../generators/DungeonTerrainGenerator.java | 229 +++ .../neon/maps/generators/TownGenerator.java | 39 +- .../maps/generators/WildernessGenerator.java | 350 +---- .../WildernessTerrainGenerator.java | 298 ++++ .../java/neon/narrative/QuestTracker.java | 14 +- src/main/java/neon/narrative/Resolver.java | 1 - .../neon/systems/files/XMLTranslator.java | 5 +- src/main/java/neon/ui/GamePanel.java | 7 +- .../java/neon/ui/dialog/ChargeDialog.java | 3 +- .../java/neon/ui/dialog/CrafterDialog.java | 9 +- .../java/neon/ui/dialog/PotionDialog.java | 9 +- src/main/java/neon/ui/states/AimState.java | 1 + src/main/java/neon/ui/states/BumpState.java | 2 +- .../java/neon/ui/states/ContainerState.java | 9 +- src/main/java/neon/ui/states/DialogState.java | 2 +- src/main/java/neon/ui/states/GameState.java | 9 +- src/main/java/neon/ui/states/MoveState.java | 8 +- src/main/java/neon/util/Graph.java | 6 +- src/test/java/neon/core/GameLoaderTest.java | 4 +- .../neon/editor/JacksonXmlBuilderTest.java | 17 +- src/test/java/neon/entities/UIDStoreTest.java | 7 +- .../java/neon/maps/AtlasIntegrationTest.java | 8 +- src/test/java/neon/maps/AtlasTest.java | 17 +- .../java/neon/maps/MapPerformanceTest.java | 55 +- .../java/neon/maps/MapSerializationTest.java | 20 +- src/test/java/neon/maps/MapTestFixtures.java | 60 - .../java/neon/maps/ZoneIntegrationTest.java | 38 +- .../java/neon/maps/ZoneSerializationTest.java | 37 +- .../maps/generators/DungeonGeneratorTest.java | 233 ++- .../DungeonGeneratorXmlIntegrationTest.java | 214 +-- .../TownGeneratorIntegrationTest.java | 11 +- .../WildernessGeneratorIntegrationTest.java | 73 +- .../generators/WildernessGeneratorTest.java | 50 +- .../java/neon/test/TestEngineContext.java | 35 +- 138 files changed, 8204 insertions(+), 7824 deletions(-) create mode 100644 src/main/java/neon/core/handlers/TeleportHandler.java delete mode 100644 src/main/java/neon/editor/services/EditorResourceProvider.java rename src/main/java/neon/entities/{EntityFactory.java => CreatureFactory.java} (56%) create mode 100644 src/main/java/neon/entities/ItemFactory.java create mode 100644 src/main/java/neon/maps/generators/DungeonTerrainGenerator.java create mode 100644 src/main/java/neon/maps/generators/WildernessTerrainGenerator.java diff --git a/pom.xml b/pom.xml index 681ca87..bc6458a 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ com.spotify.fmt fmt-maven-plugin - 2.21.1 + 2.29 checkFormat @@ -176,9 +176,9 @@ - org.fluttercode.jtexgen + org.priewe jtexgen - 1.2 + 2.0 org.junit.jupiter diff --git a/src/main/java/neon/ai/AI.java b/src/main/java/neon/ai/AI.java index 2ded80f..25f8326 100644 --- a/src/main/java/neon/ai/AI.java +++ b/src/main/java/neon/ai/AI.java @@ -24,16 +24,11 @@ import java.util.HashMap; import lombok.Getter; import neon.core.Engine; -import neon.core.GameContext; import neon.core.GameStores; import neon.core.event.CombatEvent; import neon.core.event.MagicEvent; import neon.core.handlers.*; -import neon.entities.Clothing; -import neon.entities.Creature; -import neon.entities.Door; -import neon.entities.Item; -import neon.entities.Weapon; +import neon.entities.*; import neon.entities.components.FactionComponent; import neon.entities.property.Condition; import neon.entities.property.Skill; @@ -42,6 +37,7 @@ import neon.resources.RItem; import neon.resources.RSpell; import neon.resources.RWeapon.WeaponType; +import neon.resources.ResourceManager; /** * This class implements a creature's AI. @@ -49,28 +45,21 @@ * @author mdriesen */ public abstract class AI implements Serializable { - /** - * -- GETTER -- - * - * @return the aggression of the creature with this AI - */ + @Getter protected byte aggression; - /** - * -- GETTER -- - * - * @return the confidence of the creature with this AI - */ @Getter protected byte confidence; protected Creature creature; protected HashMap dispositions = new HashMap(); - protected final GameStores gameStores; + protected final ResourceManager resourceManager; + protected final UIDStore uidStore; protected final InventoryHandler inventoryHandler; protected final MotionHandler motionHandler; protected final PathFinder pathFinder; protected final CombatUtils combatUtils; - protected final GameContext gameContext; + protected final Player player; + /** * Initializes a new AI. * @@ -78,17 +67,39 @@ public abstract class AI implements Serializable { * @param aggression * @param confidence */ - public AI(Creature creature, byte aggression, byte confidence, GameStores gameStores, GameContext gameContext) { + public AI( + Creature creature, byte aggression, byte confidence, GameStores gameStores, Player player) { this.aggression = aggression; this.confidence = confidence; this.creature = creature; - this.gameStores = gameStores; - this.gameContext = gameContext; + this.resourceManager = gameStores.getResources(); + this.uidStore = gameStores.getStore(); + this.player = player; + + inventoryHandler = new InventoryHandler(uidStore); + motionHandler = new MotionHandler(this.uidStore, player); + pathFinder = new PathFinder(this.uidStore, player); + combatUtils = new CombatUtils(this.uidStore); + } - inventoryHandler = new InventoryHandler(gameStores.getStore()); - motionHandler = new MotionHandler(gameContext,gameStores); - pathFinder = new PathFinder(gameStores); - combatUtils = new CombatUtils(gameStores.getStore()); + public AI( + Creature creature, + byte aggression, + byte confidence, + ResourceManager resourceManager, + UIDStore uidStore, + Player player) { + this.aggression = aggression; + this.confidence = confidence; + this.creature = creature; + this.resourceManager = resourceManager; + this.uidStore = uidStore; + this.player = player; + + inventoryHandler = new InventoryHandler(uidStore); + motionHandler = new MotionHandler(uidStore, player); + pathFinder = new PathFinder(uidStore, player); + combatUtils = new CombatUtils(uidStore); } /** Lets the creature with this AI act. */ @@ -101,7 +112,7 @@ public boolean isHostile() { if (creature.hasCondition(Condition.CALM)) { return false; } else { - return aggression > getDisposition(Engine.getPlayer()); + return aggression > getDisposition(player); } } @@ -186,7 +197,7 @@ public boolean sees(Point p) { protected boolean heal() { // first check potions and scrolls? for (long uid : creature.getInventoryComponent()) { - Item item = (Item) gameStores.getStore().getEntity(uid); + Item item = (Item) uidStore.getEntity(uid); if (item instanceof Item.Scroll || item instanceof Item.Potion) { RSpell formula = item.getMagicComponent().getSpell(); @@ -239,7 +250,7 @@ protected boolean cure() { private boolean cure(Effect effect) { // first check potions and scrolls? for (long uid : creature.getInventoryComponent()) { - Item item = (Item) gameStores.getStore().getEntity(uid); + Item item = (Item) uidStore.getEntity(uid); if (item instanceof Item.Scroll || item instanceof Item.Potion) { RSpell formula = item.getMagicComponent().getSpell(); if (formula.effect.equals(effect) && formula.range == 0) { @@ -272,7 +283,7 @@ private boolean cure(Effect effect) { */ private boolean equip(Slot slot) { for (long uid : creature.getInventoryComponent()) { - Item item = (Item) gameStores.getStore().getEntity(uid); + Item item = (Item) uidStore.getEntity(uid); if (item instanceof Weapon && slot.equals(((Weapon) item).getSlot())) { WeaponType type = ((Weapon) item).getWeaponType(); inventoryHandler.equip(item, creature); @@ -336,8 +347,8 @@ protected void flee(Creature hunter) { private boolean open(Point p) { Door door = null; for (long uid : Engine.getAtlasPosition().getCurrentZone().getItems(p)) { - if (gameStores.getStore().getEntity(uid) instanceof Door) { - door = (Door) gameStores.getStore().getEntity(uid); + if (uidStore.getEntity(uid) instanceof Door) { + door = (Door) uidStore.getEntity(uid); } } if (door != null) { @@ -471,7 +482,7 @@ protected void hunt(Creature prey) { if (p.distance(preyPos.x, preyPos.y) < 1) { long uid = creature.getInventoryComponent().get(Slot.WEAPON); - Weapon weapon = (Weapon) gameStores.getStore().getEntity(uid); + Weapon weapon = (Weapon) uidStore.getEntity(uid); if (creature.getInventoryComponent().hasEquiped(Slot.WEAPON) && weapon.isRanged()) { if (!(combatUtils.getWeaponType(creature).equals(WeaponType.THROWN) || equip(Slot.AMMO))) { inventoryHandler.unequip(weapon.getUID(), creature); @@ -491,7 +502,7 @@ protected void hunt(Creature prey) { private boolean hasItem(Creature creature, RItem item) { for (long uid : creature.getInventoryComponent()) { - if (gameStores.getStore().getEntity(uid).getID().equals(item.id)) { + if (uidStore.getEntity(uid).getID().equals(item.id)) { return true; } } diff --git a/src/main/java/neon/ai/AIFactory.java b/src/main/java/neon/ai/AIFactory.java index be06e4c..272d8fa 100644 --- a/src/main/java/neon/ai/AIFactory.java +++ b/src/main/java/neon/ai/AIFactory.java @@ -20,11 +20,26 @@ import java.awt.Point; import neon.entities.Creature; +import neon.entities.Player; +import neon.entities.UIDStore; import neon.resources.RCreature; import neon.resources.RCreature.AIType; import neon.resources.RPerson; +import neon.resources.ResourceManager; public class AIFactory { + + private final Player player; + + private final ResourceManager resourceManager; + private final UIDStore uidStore; + + public AIFactory(ResourceManager resourceManager, UIDStore uidStore, Player player) { + this.resourceManager = resourceManager; + this.uidStore = uidStore; + this.player = player; + } + /** * Loads the AI of an NPC. * @@ -73,13 +88,16 @@ public AI getAI(Creature creature) { private AI getAI(AIType type, Creature creature, byte aggression, byte confidence, int range) { switch (type) { case wander: - return new BasicAI(creature, aggression, confidence); + return new BasicAI(creature, aggression, confidence, resourceManager, uidStore, player); case guard: - return new GuardAI(creature, aggression, confidence, range); + return new GuardAI( + creature, aggression, confidence, range, resourceManager, uidStore, player); case schedule: - return new ScheduleAI(creature, aggression, confidence, new Point[0]); + return new ScheduleAI( + creature, aggression, confidence, new Point[0], resourceManager, uidStore, player); default: - return new GuardAI(creature, aggression, confidence, range); + return new GuardAI( + creature, aggression, confidence, range, resourceManager, uidStore, player); } } } diff --git a/src/main/java/neon/ai/BasicAI.java b/src/main/java/neon/ai/BasicAI.java index c9bd636..12336d2 100644 --- a/src/main/java/neon/ai/BasicAI.java +++ b/src/main/java/neon/ai/BasicAI.java @@ -18,26 +18,34 @@ package neon.ai; -import neon.core.Engine; import neon.entities.Creature; +import neon.entities.Player; +import neon.entities.UIDStore; import neon.entities.components.HealthComponent; +import neon.resources.ResourceManager; public class BasicAI extends AI { - public BasicAI(Creature creature, byte aggression, byte confidence) { - super(creature, aggression, confidence); + public BasicAI( + Creature creature, + byte aggression, + byte confidence, + ResourceManager resourceManager, + UIDStore uidStore, + Player player) { + super(creature, aggression, confidence, resourceManager, uidStore, player); } public void act() { // TODO: not only pay attention to player, but also to other creatures in sight - if (isHostile() && sees(Engine.getPlayer())) { + if (isHostile() && sees(player)) { HealthComponent health = creature.getHealthComponent(); if (100 * health.getHealth() / health.getBaseHealth() < confidence) { // 80% chance to just flee, 20% chance to heal; if no heal spell, flee anyway if (Math.random() > 0.2 || !(cure() || heal())) { - flee(Engine.getPlayer()); + flee(player); } } else { - hunt(Engine.getPlayer()); + hunt(player); } } else { wander(); diff --git a/src/main/java/neon/ai/GuardAI.java b/src/main/java/neon/ai/GuardAI.java index 0ec849a..6c1bf30 100644 --- a/src/main/java/neon/ai/GuardAI.java +++ b/src/main/java/neon/ai/GuardAI.java @@ -19,19 +19,26 @@ package neon.ai; import java.awt.Point; -import neon.core.Engine; -import neon.core.GameContext; -import neon.core.GameStores; import neon.entities.Creature; +import neon.entities.Player; +import neon.entities.UIDStore; import neon.entities.components.HealthComponent; import neon.entities.components.ShapeComponent; +import neon.resources.ResourceManager; public class GuardAI extends AI { private int range; private Point home; - public GuardAI(Creature creature, byte aggression, byte confidence, int range, GameStores gameStores, GameContext gameContext) { - super(creature, aggression, confidence,gameStores,gameContext); + public GuardAI( + Creature creature, + byte aggression, + byte confidence, + int range, + ResourceManager resourceManager, + UIDStore uidStore, + Player player) { + super(creature, aggression, confidence, resourceManager, uidStore, player); this.range = range; ShapeComponent bounds = creature.getShapeComponent(); home = new Point(bounds.x, bounds.y); @@ -40,16 +47,16 @@ public GuardAI(Creature creature, byte aggression, byte confidence, int range, G public void act() { // TODO: not only pay attention to player, but also to other creatures in sight ShapeComponent cBounds = creature.getShapeComponent(); - ShapeComponent pBounds = gameContext.getPlayer().getShapeComponent(); + ShapeComponent pBounds = player.getShapeComponent(); if (isHostile() && cBounds.getLocation().distance(pBounds.getLocation()) < range) { HealthComponent health = creature.getHealthComponent(); if (100 * health.getHealth() / health.getBaseHealth() < confidence / 100) { // 80% chance to just flee, 20% chance to heal; if no heal spell, flee anyway if (Math.random() > 0.2 || !(cure() || heal())) { - flee(gameContext.getPlayer()); + flee(player); } } else { - hunt(range, home, gameContext.getPlayer()); + hunt(range, home, player); } } else { wander(range, home); diff --git a/src/main/java/neon/ai/HuntBehaviour.java b/src/main/java/neon/ai/HuntBehaviour.java index 721537c..59a8d77 100644 --- a/src/main/java/neon/ai/HuntBehaviour.java +++ b/src/main/java/neon/ai/HuntBehaviour.java @@ -21,6 +21,8 @@ import java.awt.Point; import java.awt.Rectangle; import neon.core.Engine; +import neon.core.GameContext; +import neon.core.GameStores; import neon.core.event.MagicEvent; import neon.entities.Creature; import neon.entities.components.ShapeComponent; @@ -31,10 +33,17 @@ public class HuntBehaviour implements Behaviour { private Creature creature; private Creature prey; + private final PathFinder pathFinder; + private final GameContext gameContext; + private final GameStores gameStores; - public HuntBehaviour(Creature hunter, Creature prey) { + public HuntBehaviour( + Creature hunter, Creature prey, GameContext gameContext, GameStores gameStores) { creature = hunter; this.prey = prey; + this.gameContext = gameContext; + this.gameStores = gameStores; + this.pathFinder = new PathFinder(gameStores.getStore(), gameContext.getPlayer()); } public void act() { @@ -43,7 +52,7 @@ public void act() { Rectangle preyPos = prey.getShapeComponent(); if (dice == 1) { - int time = Engine.getTimer().getTime(); + int time = gameContext.getTimer().getTime(); for (RSpell.Power power : creature.getMagicComponent().getPowers()) { if (power.effect.getSchool().equals(Skill.DESTRUCTION) && creature.getMagicComponent().canUse(power, time) @@ -84,7 +93,7 @@ public void act() { } else { // if creature is smarter, try A* ShapeComponent cBounds = creature.getShapeComponent(); ShapeComponent pBounds = prey.getShapeComponent(); - p = PathFinder.findPath(creature, cBounds.getLocation(), pBounds.getLocation())[0]; + p = pathFinder.findPath(creature, cBounds.getLocation(), pBounds.getLocation())[0]; } if (p.distance(preyPos.x, preyPos.y) < 1) { diff --git a/src/main/java/neon/ai/PathFinder.java b/src/main/java/neon/ai/PathFinder.java index b61d387..8b75299 100644 --- a/src/main/java/neon/ai/PathFinder.java +++ b/src/main/java/neon/ai/PathFinder.java @@ -25,10 +25,10 @@ import java.util.HashMap; import java.util.PriorityQueue; import java.util.Queue; -import neon.core.Engine; -import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Door; +import neon.entities.Player; +import neon.entities.UIDStore; import neon.entities.property.Skill; import neon.maps.Region; import neon.resources.RItem; @@ -37,11 +37,12 @@ public class PathFinder { private static HashMap evaluated; private static Point to; private static Creature mover; + private final UIDStore uidStore; + private final Player player; - private final GameStores gameStores; - - public PathFinder(GameStores gameStores) { - this.gameStores = gameStores; + public PathFinder(UIDStore uidStore, Player player) { + this.uidStore = uidStore; + this.player = player; } public Point[] findPath(Creature creature, Point origin, Point destination) { @@ -70,7 +71,7 @@ public Point[] findPath(Creature creature, Point origin, Point destination) { links.put(to, next); next = null; break; - } else if (Engine.getAtlasPosition().getCurrentZone().getRegion(neighbour).getMovMod() + } else if (player.getCurrentZone().getRegion(neighbour).getMovMod() == Region.Modifier.BLOCK) { continue; // if terrain is blocked, skip to next point } @@ -132,7 +133,7 @@ private int manhattan(Point one, Point two) { private int terrainPenalty(Point neighbour) { // better modifiers? - return switch (Engine.getAtlasPosition().getCurrentZone().getRegion(neighbour).getMovMod()) { + return switch (player.getCurrentZone().getRegion(neighbour).getMovMod()) { case SWIM -> (100 - mover.getSkill(Skill.SWIMMING)) / 5; case CLIMB -> (100 - mover.getSkill(Skill.CLIMBING)) / 5; default -> 0; @@ -140,9 +141,9 @@ private int terrainPenalty(Point neighbour) { } private int doorPenalty(Point neighbour) { - for (long uid : Engine.getAtlasPosition().getCurrentZone().getItems(neighbour)) { - if (gameStores.getStore().getEntity(uid) instanceof Door) { - Door door = (Door) gameStores.getStore().getEntity(uid); + for (long uid : player.getCurrentZone().getItems(neighbour)) { + if (uidStore.getEntity(uid) instanceof Door) { + Door door = (Door) uidStore.getEntity(uid); if (door.lock.isLocked()) { RItem key = door.lock.getKey(); if (key != null && hasItem(mover, key)) { @@ -167,7 +168,7 @@ public int compare(Point one, Point two) { private boolean hasItem(Creature creature, RItem item) { for (long uid : creature.getInventoryComponent()) { - if (gameStores.getStore().getEntity(uid).getID().equals(item.id)) { + if (uidStore.getEntity(uid).getID().equals(item.id)) { return true; } } diff --git a/src/main/java/neon/ai/ScheduleAI.java b/src/main/java/neon/ai/ScheduleAI.java index 11443b5..2ec8061 100644 --- a/src/main/java/neon/ai/ScheduleAI.java +++ b/src/main/java/neon/ai/ScheduleAI.java @@ -19,31 +19,40 @@ package neon.ai; import java.awt.Point; -import neon.core.Engine; import neon.entities.Creature; +import neon.entities.Player; +import neon.entities.UIDStore; import neon.entities.components.HealthComponent; import neon.entities.components.ShapeComponent; +import neon.resources.ResourceManager; // TODO: schedule in editor public class ScheduleAI extends AI { private Point[] schedule; private int current = 0; - public ScheduleAI(Creature creature, byte aggression, byte confidence, Point[] schedule) { - super(creature, aggression, confidence); + public ScheduleAI( + Creature creature, + byte aggression, + byte confidence, + Point[] schedule, + ResourceManager resourceManager, + UIDStore uidStore, + Player player) { + super(creature, aggression, confidence, resourceManager, uidStore, player); this.schedule = schedule; } public void act() { - if (isHostile() && sees(Engine.getPlayer())) { + if (isHostile() && sees(player)) { HealthComponent health = creature.getHealthComponent(); if (100 * health.getHealth() / health.getBaseHealth() < confidence) { // 80% chance to just flee, 20% chance to heal; if no heal spell, flee anyway if (Math.random() > 0.2 || !(cure() || heal())) { - flee(Engine.getPlayer()); + flee(player); } } else { - hunt(Engine.getPlayer()); + hunt(player); } } else { ShapeComponent bounds = creature.getShapeComponent(); diff --git a/src/main/java/neon/core/DefaultGameStores.java b/src/main/java/neon/core/DefaultGameStores.java index 072ff73..03d00e2 100644 --- a/src/main/java/neon/core/DefaultGameStores.java +++ b/src/main/java/neon/core/DefaultGameStores.java @@ -1,6 +1,7 @@ package neon.core; import lombok.Getter; +import neon.entities.Player; import neon.entities.UIDStore; import neon.maps.Atlas; import neon.maps.MapLoader; @@ -8,7 +9,6 @@ import neon.resources.ResourceManager; import neon.systems.files.FileSystem; import neon.util.mapstorage.MapStore; -import org.h2.mvstore.MVStore; @Getter public class DefaultGameStores implements GameStores { @@ -19,24 +19,13 @@ public class DefaultGameStores implements GameStores { private final Atlas atlas; private final ZoneFactory zoneFactory; - public DefaultGameStores(ResourceManager resources, FileSystem fileSystem) { + public DefaultGameStores(ResourceManager resources, FileSystem fileSystem, Player player) { this.resources = resources; this.fileSystem = fileSystem; - this.store = new UIDStore(fileSystem.getFullPath("uidstore")); - MapStore mapStore = Atlas.getMapStore(fileSystem,"zones"); - this.zoneFactory = new ZoneFactory(mapStore,store,resources); - MapLoader mapLoader = new MapLoader(fileSystem, store, resources,zoneFactory); - this.atlas = new Atlas(fileSystem, fileSystem.getFullPath("atlas"), store, mapLoader); - } - - public DefaultGameStores( - ResourceManager resources, FileSystem fileSystem, UIDStore store, Atlas atlas) { - this.resources = resources; - this.fileSystem = fileSystem; - this.store = store; - this.atlas = atlas; - MapStore mapStore = Atlas.getMapStore(fileSystem,"zones"); - this.zoneFactory = new ZoneFactory(mapStore,store,resources); - + this.store = new UIDStore(fileSystem, fileSystem.getFullPath("uidstore")); + MapStore mapStore = Atlas.getMapStore(fileSystem, "zones"); + this.zoneFactory = new ZoneFactory(mapStore, store, resources); + MapLoader mapLoader = new MapLoader(fileSystem, store, resources, zoneFactory, player); + atlas = new Atlas(fileSystem, mapStore, store, mapLoader); } } diff --git a/src/main/java/neon/core/Engine.java b/src/main/java/neon/core/Engine.java index c481b7b..3707f61 100644 --- a/src/main/java/neon/core/Engine.java +++ b/src/main/java/neon/core/Engine.java @@ -101,7 +101,8 @@ public Engine(Port port) throws IOException { files = new FileSystem(); resources = new ResourceManager(); - gameStores = new DefaultGameStores(resources, files); + + gameStores = new DefaultGameStores(resources, files, null); physics = new PhysicsSystem(); physicsManager = new EnginePhysicsManager(physics); queue = new TaskQueue(); @@ -136,7 +137,7 @@ public void run() { bus.subscribe(adapter); bus.subscribe(quests); bus.subscribe(new GameLoader(context, gameStores, config)); - bus.subscribe(new GameSaver(queue,gameStores)); + bus.subscribe(new GameSaver(queue, gameStores)); } /** diff --git a/src/main/java/neon/core/Game.java b/src/main/java/neon/core/Game.java index 806a144..94242ff 100644 --- a/src/main/java/neon/core/Game.java +++ b/src/main/java/neon/core/Game.java @@ -23,7 +23,6 @@ import lombok.Getter; import neon.entities.Player; import neon.maps.AtlasPosition; -import neon.maps.ZoneActivator; import neon.maps.services.PhysicsManager; import neon.narrative.QuestTracker; import neon.systems.timing.Timer; @@ -43,13 +42,7 @@ public Game( QuestTracker questTracker) { this.player = player; this.gameStores = gameStores; - this.atlasPosition = - new AtlasPosition( - gameStores.getAtlas(), - new ZoneActivator(physicsManager), - gameStores.getResources(), - questTracker, - gameStores.getStore()); + this.atlasPosition = new AtlasPosition(gameStores, questTracker, player); } /** diff --git a/src/main/java/neon/core/GameLoader.java b/src/main/java/neon/core/GameLoader.java index ed9ad1d..6ea78b9 100644 --- a/src/main/java/neon/core/GameLoader.java +++ b/src/main/java/neon/core/GameLoader.java @@ -34,8 +34,8 @@ import neon.core.handlers.SkillHandler; import neon.core.model.SaveGameModel; import neon.entities.Entity; -import neon.entities.EntityFactory; import neon.entities.Item; +import neon.entities.ItemFactory; import neon.entities.Player; import neon.entities.UIDStore; import neon.entities.components.Stats; @@ -46,9 +46,7 @@ import neon.magic.Effect; import neon.magic.Spell; import neon.magic.SpellFactory; -import neon.maps.Atlas; -import neon.maps.Map; -import neon.maps.MapLoader; +import neon.maps.*; import neon.resources.CGame; import neon.resources.RCreature; import neon.resources.RMod; @@ -72,6 +70,7 @@ public class GameLoader { private final SpellFactory spellFactory; private final MapLoader mapLoader; @Getter @Setter private int worldMapUID; + private final ZoneFactory zoneFactory; public GameLoader(GameContext context, GameStores gameStores, Configuration config) { this.context = context; @@ -79,7 +78,15 @@ public GameLoader(GameContext context, GameStores gameStores, Configuration conf this.config = config; queue = context.getQueue(); mapLoader = - new MapLoader(gameStores.getFileSystem(), gameStores.getStore(), gameStores.getResources(),gameStores.getZoneFactory()); + new MapLoader( + gameStores.getFileSystem(), + gameStores.getStore(), + gameStores.getResources(), + gameStores.getZoneFactory(), + context.getPlayer()); + zoneFactory = + new ZoneFactory( + gameStores.getAtlas().getCache(), gameStores.getStore(), gameStores.getResources()); spellFactory = new SpellFactory(gameStores.getResources()); } @@ -130,8 +137,7 @@ public void initGame( // initialize player RCreature species = ((RCreature) gameStores.getResources().getResource(race)).clone(); - EntityFactory entityFactory = - new EntityFactory(gameStores.getStore(), gameStores.getResources()); + ItemFactory itemFactory = new ItemFactory(gameStores.getResources()); Player player = new Player(species, name, gender, spec, profession, gameStores); player.species.text = "@"; context.startGame( @@ -148,7 +154,7 @@ public void initGame( InventoryHandler inventoryHandler = new InventoryHandler(gameStores.getStore()); // starting items for (String i : game.getStartingItems()) { - Item item = entityFactory.getItem(i, gameStores.getStore().createNewEntityUID()); + Item item = itemFactory.getItem(i, gameStores.getStore().createNewEntityUID()); gameStores.getStore().addEntity(item); inventoryHandler.addItem(player, item.getUID()); } @@ -165,9 +171,11 @@ public void initGame( String[] startMap = game.getStartMap(); Map map = atlas.getMap(store.getMapUID(startMap)); + context.getScriptEngine().getBindings("js").putMember("map", map); context.getAtlasPosition().setMap(map); - context.getAtlasPosition().setCurrentZone(game.getStartZone(), player); + player.setCurrentZone(map.getZone(game.getStartZone())); + } catch (RuntimeException re) { log.error("Error during initGame", re); } @@ -295,10 +303,13 @@ private void loadPlayer(SaveGameModel.PlayerSaveData playerData) { bounds.setLocation(playerData.x, playerData.y); player.setSign(playerData.sign); player.species.text = "@"; - + Map currentMap = gameStores.getAtlas().getMap(playerData.map); + Zone currentZone = + zoneFactory.createZone(currentMap.getName(), currentMap.getUID(), playerData.level); // start map - context.getAtlasPosition().setMap(gameStores.getAtlas().getMap(playerData.map)); - context.getAtlasPosition().setCurrentZone(playerData.level, player); + context.getAtlasPosition().setMap(currentMap); + + player.setCurrentZone(currentZone); // stats Stats stats = player.getStatsComponent(); diff --git a/src/main/java/neon/core/ScriptInterface.java b/src/main/java/neon/core/ScriptInterface.java index 5ce70d0..018d66d 100644 --- a/src/main/java/neon/core/ScriptInterface.java +++ b/src/main/java/neon/core/ScriptInterface.java @@ -29,13 +29,14 @@ public class ScriptInterface { private final GamePanel panel; private final UIDStore uidStore; private final GameContext gameContext; + public ScriptInterface(GamePanel panel, UIDStore uidStore, GameContext gameContext) { this.panel = panel; - this.uidStore = uidStore; - this.gameContext = gameContext; - InputStream input = Engine.class.getResourceAsStream("scripts.js"); - assert input != null; - Scanner scanner = new Scanner(input, StandardCharsets.UTF_8); + this.uidStore = uidStore; + this.gameContext = gameContext; + InputStream input = Engine.class.getResourceAsStream("scripts.js"); + assert input != null; + Scanner scanner = new Scanner(input, StandardCharsets.UTF_8); gameContext.execute(scanner.useDelimiter("\\A").next()); scanner.close(); } diff --git a/src/main/java/neon/core/handlers/CombatHandler.java b/src/main/java/neon/core/handlers/CombatHandler.java index 7bb4a63..bad6dc4 100644 --- a/src/main/java/neon/core/handlers/CombatHandler.java +++ b/src/main/java/neon/core/handlers/CombatHandler.java @@ -51,6 +51,7 @@ public class CombatHandler { private final GameStores gameStores; private final InventoryHandler inventoryHandler; private final CombatUtils combatUtils; + public CombatHandler(GameStores gameStores) { this.gameStores = gameStores; inventoryHandler = new InventoryHandler(gameStores.getStore()); diff --git a/src/main/java/neon/core/handlers/MotionHandler.java b/src/main/java/neon/core/handlers/MotionHandler.java index 24af393..19fb413 100644 --- a/src/main/java/neon/core/handlers/MotionHandler.java +++ b/src/main/java/neon/core/handlers/MotionHandler.java @@ -20,18 +20,9 @@ import java.awt.Point; import java.awt.Rectangle; -import java.io.IOException; import java.util.Collection; -import javax.swing.SwingConstants; import lombok.extern.slf4j.Slf4j; -import neon.core.Engine; -import neon.core.GameContext; -import neon.core.GameStores; -import neon.core.event.MessageEvent; -import neon.entities.Creature; -import neon.entities.Door; -import neon.entities.Entity; -import neon.entities.Player; +import neon.entities.*; import neon.entities.components.Lock; import neon.entities.property.Condition; import neon.entities.property.Habitat; @@ -53,69 +44,12 @@ public class MotionHandler { public static final byte DOOR = 4; public static final byte NULL = 5; public static final byte HABITAT = 6; - public final GameContext context; - public final GameStores gameStores; - public final MapLoader mapLoader; + public final UIDStore uidStore; + private final Player player; - public MotionHandler(GameContext context, GameStores gameStores) { - this.context = context; - this.gameStores = gameStores; - mapLoader = new MapLoader(gameStores.getFileSystem(),gameStores.getStore(),gameStores.getResources(),gameStores.getZoneFactory()); - } - - /** - * Teleports a creature. Two results are possible: - * - *

    - *
  • OK - creature was teleported - *
  • DOOR - this portal is just a door and does not support teleporting - *
- * - * @param creature the creature to teleport. - * @param door the portal that the creature used - * @return the result - */ - public byte teleport(Player creature, Door door) { - if (door.portal.isPortal()) { - Zone previous = context.getAtlasPosition().getCurrentZone(); // briefly buffer current zone - if (door.portal.getDestMap() != 0) { - // load map and have door refer back - Map map = gameStores.getAtlas().getMap(door.portal.getDestMap()); - Zone zone = map.getZone(door.portal.getDestZone()); - for (long uid : zone.getItems(door.portal.getDestPos())) { - Entity i = gameStores.getStore().getEntity(uid); - if (i instanceof Door) { - ((Door) i).portal.setDestMap(context.getAtlasPosition().getCurrentMap()); - } - } - context.getAtlasPosition().setMap(map); - context.getScriptEngine().getBindings("js").putMember("map", map); - door.portal.setDestMap(context.getAtlasPosition().getCurrentMap()); - } else if (door.portal.getDestTheme() != null) { - Dungeon dungeon = mapLoader.loadThemedDungeon(door.portal.getDestTheme(), door.portal.getDestTheme(),door.portal.getDestZone()); - context.getAtlasPosition().setMap(dungeon); - door.portal.setDestMap(context.getAtlasPosition().getCurrentMap()); - } - - context.getAtlasPosition().enterZone(door, previous, creature); - - walk(creature, door.portal.getDestPos()); - // check if there is a door at the destination, if so, unlock and open this door - Rectangle bounds = creature.getShapeComponent(); - for (long uid : context.getAtlasPosition().getCurrentZone().getItems(bounds)) { - Entity i = gameStores.getStore().getEntity(uid); - if (i instanceof Door) { - ((Door) i).lock.open(); - } - } - - // if there is a sign on the door, show it now - if (door.hasSign()) { - Engine.post(new MessageEvent(door, door.toString(), 3, SwingConstants.BOTTOM)); - } - return OK; - } - return DOOR; + public MotionHandler(UIDStore uidStore, Player player) { + this.uidStore = uidStore; + this.player = player; } /** @@ -136,15 +70,15 @@ public byte teleport(Player creature, Door door) { * @return the result of the movement */ public byte move(Creature actor, Point p) { - Region region = context.getAtlasPosition().getCurrentZone().getRegion(p); + Region region = player.getCurrentZone().getRegion(p); if (p == null || region == null) { return NULL; } // check if there is no closed door present - Collection items = context.getAtlasPosition().getCurrentZone().getItems(p); + Collection items = player.getCurrentZone().getItems(p); for (long uid : items) { - Entity i = gameStores.getStore().getEntity(uid); + Entity i = uidStore.getEntity(uid); if (i instanceof Door) { if (((Door) i).lock.getState() != Lock.OPEN) { return DOOR; @@ -182,7 +116,7 @@ public byte move(Creature creature, int x, int y) { return move(creature, new Point(x, y)); } - private byte swim(Creature swimmer, Point p) { + public byte swim(Creature swimmer, Point p) { if (swimmer.species.habitat == Habitat.WATER) { return OK; } else if (SkillHandler.check(swimmer, Skill.SWIMMING) > 20) { @@ -200,7 +134,7 @@ private byte swim(Creature swimmer, Point p) { * * @param tile */ - private static byte climb(Creature climber, Point p) { + public static byte climb(Creature climber, Point p) { if (climber.species.habitat == Habitat.WATER) { return HABITAT; } @@ -213,7 +147,7 @@ private static byte climb(Creature climber, Point p) { } } - private static byte walk(Creature walker, Point p) { + public static byte walk(Creature walker, Point p) { Rectangle bounds = walker.getShapeComponent(); if (walker.species.habitat == Habitat.WATER) { return HABITAT; diff --git a/src/main/java/neon/core/handlers/TeleportHandler.java b/src/main/java/neon/core/handlers/TeleportHandler.java new file mode 100644 index 0000000..586626e --- /dev/null +++ b/src/main/java/neon/core/handlers/TeleportHandler.java @@ -0,0 +1,98 @@ +package neon.core.handlers; + +import java.awt.*; +import javax.swing.*; +import neon.core.Engine; +import neon.core.GameContext; +import neon.core.GameStores; +import neon.core.event.MessageEvent; +import neon.entities.Door; +import neon.entities.Entity; +import neon.entities.Player; +import neon.maps.*; +import org.graalvm.polyglot.Context; + +public class TeleportHandler { + private final GameStores gameStores; + private final GameContext gameContext; + private final AtlasPosition atlasPosition; + private final Context scriptEngine; + private final MapLoader mapLoader; + private final MotionHandler motionHandler; + + public TeleportHandler( + GameStores gameStores, + GameContext gameContext, + AtlasPosition atlasPosition, + Context scriptEngine) { + this.gameStores = gameStores; + this.gameContext = gameContext; + this.atlasPosition = atlasPosition; + this.scriptEngine = scriptEngine; + this.mapLoader = + new MapLoader( + gameStores.getFileSystem(), + gameStores.getStore(), + gameStores.getResources(), + gameStores.getZoneFactory(), + gameContext.getPlayer()); + this.motionHandler = new MotionHandler(gameStores.getStore(), gameContext.getPlayer()); + } + + /** + * Teleports a creature. Two results are possible: + * + *
    + *
  • OK - creature was teleported + *
  • DOOR - this portal is just a door and does not support teleporting + *
+ * + * @param creature the creature to teleport. + * @param door the portal that the creature used + * @return the result + */ + public byte teleport(Player creature, Door door) { + if (door.portal.isPortal()) { + Zone previous = atlasPosition.getCurrentZone(); // briefly buffer current zone + if (door.portal.getDestMap() != 0) { + // load map and have door refer back + Map map = gameStores.getAtlas().getMap(door.portal.getDestMap()); + Zone zone = map.getZone(door.portal.getDestZone()); + for (long uid : zone.getItems(door.portal.getDestPos())) { + Entity i = gameStores.getStore().getEntity(uid); + if (i instanceof Door) { + ((Door) i).portal.setDestMap(atlasPosition.getCurrentMap()); + } + } + atlasPosition.setMap(map); + scriptEngine.getBindings("js").putMember("map", map); + door.portal.setDestMap(atlasPosition.getCurrentMap()); + } else if (door.portal.getDestTheme() != null) { + Dungeon dungeon = + mapLoader.loadThemedDungeon( + door.portal.getDestTheme(), door.portal.getDestTheme(), door.portal.getDestZone()); + atlasPosition.setMap(dungeon); + door.portal.setDestMap(atlasPosition.getCurrentMap()); + } + + atlasPosition.enterZone(door, previous, creature); + + MotionHandler.walk(creature, door.portal.getDestPos()); + // check if there is a door at the destination, if so, unlock and open this door + Rectangle bounds = creature.getShapeComponent(); + for (long uid : atlasPosition.getCurrentZone().getItems(bounds)) { + Entity i = gameStores.getStore().getEntity(uid); + if (i instanceof Door) { + ((Door) i).lock.open(); + } + } + + // if there is a sign on the door, show it now + if (door.hasSign()) { + Engine.post(new MessageEvent(door, door.toString(), 3, SwingConstants.BOTTOM)); + } + return MotionHandler.OK; + } + return MotionHandler.DOOR; + } +} diff --git a/src/main/java/neon/core/handlers/TurnHandler.java b/src/main/java/neon/core/handlers/TurnHandler.java index 21555eb..8695b64 100644 --- a/src/main/java/neon/core/handlers/TurnHandler.java +++ b/src/main/java/neon/core/handlers/TurnHandler.java @@ -22,6 +22,7 @@ import java.util.Collection; import lombok.extern.slf4j.Slf4j; import neon.core.Configuration; +import neon.core.GameContext; import neon.core.GameStores; import neon.core.event.TurnEvent; import neon.core.event.UpdateEvent; @@ -50,12 +51,14 @@ public class TurnHandler { private final GameStores gameStores; private final InventoryHandler inventoryHandler; + private final GameContext gameContext; - public TurnHandler(GamePanel panel, GameStores gameStores) { + public TurnHandler(GamePanel panel, GameStores gameStores, GameContext gameContext) { this.panel = panel; this.gameStores = gameStores; inventoryHandler = new InventoryHandler(gameStores.getStore()); + this.gameContext = gameContext; CServer ini = (CServer) gameStores.getResources().getResource("ini", "config"); range = ini.getAIRange(); } @@ -153,7 +156,8 @@ private boolean checkRegions() { // die boolean is eigenlijk maar louche new TownGenerator(zone, gameStores.getStore(), gameStores.getResources()) .generate(r.getX(), r.getY(), r.getWidth(), r.getHeight(), theme, r.getZ()); } else { - new WildernessGenerator(zone, gameStores) + new WildernessGenerator( + zone, gameStores.getResources(), gameStores.getStore(), gameContext.getPlayer()) .generate(r, theme); } } diff --git a/src/main/java/neon/editor/CCEditor.java b/src/main/java/neon/editor/CCEditor.java index 2efdaa2..50e9219 100644 --- a/src/main/java/neon/editor/CCEditor.java +++ b/src/main/java/neon/editor/CCEditor.java @@ -1,408 +1,411 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor; - -import java.awt.*; -import java.awt.event.*; -import java.util.*; -import java.util.List; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import neon.editor.help.HelpLabels; -import neon.editor.resources.RMap; -import neon.editor.resources.RZone; -import neon.resources.RCreature; -import neon.resources.RCreature.Type; -import neon.resources.RItem; -import neon.resources.RMod; -import neon.resources.RSpell; -import neon.resources.RSpell.SpellType; - -public class CCEditor - implements ActionListener, ItemListener, ListSelectionListener, MouseListener { - private JDialog frame; - private JCheckBox raceBox; - private JFormattedTextField xField, yField; - private JComboBox mapBox; - private JComboBox zoneBox; - private HashMap races; - private JList raceList; - private JList itemList; - private JList spellList; - private RCreature currentRace; - private DefaultListModel spellListModel; - private DefaultListModel itemListModel; - private String[] spells; - private JPanel raceEditPanel; - - public CCEditor(JFrame parent) { - frame = new JDialog(parent, "Character Creation Editor", true); // modal dialog - JPanel content = new JPanel(new BorderLayout()); - frame.setPreferredSize(new Dimension(400, 300)); - frame.setContentPane(content); - JTabbedPane tabs = new JTabbedPane(); - content.add(tabs, BorderLayout.CENTER); - - // races - JPanel racePanel = new JPanel(new GridLayout(0, 2)); - raceList = new JList(); - raceList.addListSelectionListener(this); - JScrollPane raceScroller = new JScrollPane(raceList); - raceScroller.setBorder(new TitledBorder("Races")); - racePanel.add(raceScroller); - raceEditPanel = new JPanel(); - raceEditPanel.setBorder(new TitledBorder("Edit")); - raceBox = new JCheckBox("Playable"); - raceBox.addActionListener(this); - raceEditPanel.add(raceBox); - racePanel.add(raceEditPanel); - - // position - JPanel mapPanel = new JPanel(); - mapPanel.setBorder(new EmptyBorder(20, 20, 20, 20)); - GroupLayout layout = new GroupLayout(mapPanel); - mapPanel.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel mapLabel = new JLabel("Map: "); - JLabel zoneLabel = new JLabel("Zone: "); - JLabel xLabel = new JLabel("x-coordinate: "); - JLabel yLabel = new JLabel("y-coordinate: "); - mapBox = new JComboBox(); - mapBox.addItemListener(this); - xField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - yField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - zoneBox = new JComboBox(); - JLabel mapHelpLabel = HelpLabels.getStartMapHelpLabel(); - JLabel zoneHelpLabel = HelpLabels.getStartZoneLabel(); - JLabel xHelpLabel = HelpLabels.getStartXLabel(); - JLabel yHelpLabel = HelpLabels.getStartYLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(mapLabel) - .addComponent(mapBox) - .addComponent(mapHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(zoneLabel) - .addComponent(zoneBox) - .addComponent(zoneHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(xLabel) - .addComponent(xField) - .addComponent(xHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(yLabel) - .addComponent(yField) - .addComponent(yHelpLabel)) - .addGap(10)); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(mapLabel) - .addComponent(zoneLabel) - .addComponent(xLabel) - .addComponent(yLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - mapBox, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(zoneBox) - .addComponent(xField) - .addComponent(yField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(mapHelpLabel) - .addComponent(zoneHelpLabel) - .addComponent(xHelpLabel) - .addComponent(yHelpLabel))); - - // starting items - JPanel itemPanel = new JPanel(new BorderLayout()); - itemListModel = new DefaultListModel(); - itemList = new JList(itemListModel); - itemList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - itemPanel.add(new JScrollPane(itemList)); - - // starting spells - JPanel spellPanel = new JPanel(new BorderLayout()); - spellListModel = new DefaultListModel(); - spellList = new JList(spellListModel); - spellList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - spellPanel.add(new JScrollPane(spellList)); - - tabs.add(racePanel, "Playable races"); - tabs.add(mapPanel, "Starting position"); - tabs.add(itemPanel, "Starting items"); - tabs.add(spellPanel, "Starting spells"); - - JPanel buttons = new JPanel(); - content.add(buttons, BorderLayout.PAGE_END); - JButton ok = new JButton("Ok"); - ok.addActionListener(this); - JButton apply = new JButton("Apply"); - apply.addActionListener(this); - JButton cancel = new JButton("Cancel"); - cancel.addActionListener(this); - buttons.add(ok); - - itemList.addMouseListener(this); - spellList.addMouseListener(this); - buttons.add(cancel); - buttons.add(apply); - } - - public void show() { - DataStore store = Editor.getStore(); - RMod mod = store.getActive(); - List playableRaces = new ArrayList(); - // if species does not exist, automatically remove it - for (String race : mod.getList("races")) { - if (Editor.resources.getResource(race) instanceof RCreature) { - playableRaces.add((RCreature) Editor.resources.getResource(race)); - } else { - mod.ccRaces.remove(race); - } - } - itemListModel.clear(); - // if item does not exist, automatically remove it - for (String item : mod.getList("items")) { - if (Editor.resources.getResource(item) instanceof RItem) { - itemListModel.addElement((RItem) Editor.resources.getResource(item)); - } else { - mod.ccRaces.remove(item); - } - } - spellListModel.clear(); - // if spell does not exist, automatically remove it - for (String spell : mod.getList("spells")) { - if (Editor.resources.getResource(spell, "magic") != null) { - spellListModel.addElement((RSpell) Editor.resources.getResource(spell, "magic")); - } else { - mod.ccRaces.remove(spell); - } - } - - races = new HashMap(); - for (RCreature rc : Editor.resources.getResources(RCreature.class)) { - // only humanoids or goblins - if (rc.type == Type.humanoid || rc.type == Type.goblin) { - races.put(rc, playableRaces.contains(rc)); - } - } - raceList.setListData(races.keySet().toArray(new RCreature[0])); - - for (RMap map : Editor.resources.getResources(RMap.class)) { - if (map.theme == null) { // do not allow random maps - mapBox.addItem(map); - } - } - RMap map = (RMap) Editor.resources.getResource(mod.get("map"), "maps"); - mapBox.setSelectedItem(map); - for (RZone zone : map.zones.values()) { - if (zone.theme == null) { // do not allow random zones - zoneBox.addItem(zone); - } - } - zoneBox.setSelectedItem(map.getZone(Integer.parseInt(mod.get("z")))); - xField.setValue(Integer.parseInt(mod.get("x"))); - yField.setValue(Integer.parseInt(mod.get("y"))); - - ArrayList temp = new ArrayList(); - for (RSpell spell : Editor.resources.getResources(RSpell.class)) { - if (spell.type == SpellType.SPELL) { - temp.add(spell.id); - } - } - spells = temp.toArray(new String[temp.size()]); - - frame.pack(); - frame.setLocationRelativeTo(null); - frame.setVisible(true); - } - - private void saveAll() { - RMod mod = Editor.getStore().getActive(); - if (mapBox.getSelectedItem() != null) { - RMap map = (RMap) mapBox.getSelectedItem(); - mod.set("map", map.id); - RZone zone = (RZone) zoneBox.getSelectedItem(); - mod.set("z", Integer.toString(map.getZone(zone))); - mod.set("x", xField.getText()); - mod.set("y", yField.getText()); - } else { - JOptionPane.showMessageDialog(frame, "No start map selected!"); - } - - mod.ccRaces.clear(); - for (RCreature rc : races.keySet()) { - if (races.get(rc)) { - mod.ccRaces.add(rc.id); - } - } - mod.ccItems.clear(); - for (Enumeration e = itemListModel.elements(); e.hasMoreElements(); ) { - RItem ri = e.nextElement(); - mod.ccItems.add(ri.id); - } - mod.ccSpells.clear(); - for (Enumeration e = spellListModel.elements(); e.hasMoreElements(); ) { - RSpell rs = e.nextElement(); - mod.ccSpells.add(rs.id); - } - } - - public void actionPerformed(ActionEvent e) { - if ("Playable".equals(e.getActionCommand())) { - races.put(currentRace, raceBox.isSelected()); - } else if ("Ok".equals(e.getActionCommand())) { - saveAll(); - frame.dispose(); - } else if ("Cancel".equals(e.getActionCommand())) { - frame.dispose(); - } else if ("Apply".equals(e.getActionCommand())) { - saveAll(); - } - } - - public void mouseExited(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mousePressed(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - if (e.getComponent() == spellList) { - JPopupMenu menu = new JPopupMenu(); - menu.add(new SpellListAction("Add spell")); - menu.add(new SpellListAction("Delete spell")); - menu.show(e.getComponent(), e.getX(), e.getY()); - spellList.setSelectedIndex(spellList.locationToIndex(e.getPoint())); - } else if (e.getComponent() == itemList) { - JPopupMenu menu = new JPopupMenu(); - menu.add(new ItemListAction("Add item")); - menu.add(new ItemListAction("Delete item")); - menu.show(e.getComponent(), e.getX(), e.getY()); - itemList.setSelectedIndex(itemList.locationToIndex(e.getPoint())); - } - } - } - - public void valueChanged(ListSelectionEvent e) { - // apparently two events are fired on selection - if (e.getValueIsAdjusting()) { - currentRace = raceList.getSelectedValue(); - raceBox.setSelected(races.get(currentRace)); - raceEditPanel.setBorder(new TitledBorder(currentRace.id)); - } - } - - public void itemStateChanged(ItemEvent e) { - if (mapBox.equals(e.getSource())) { - // load zones - zoneBox.setModel(new DefaultComboBoxModel()); - RMap map = (RMap) mapBox.getSelectedItem(); - if (map != null) { - for (RZone zone : map.zones.values()) { - if (zone.theme == null) { // do not allow random zones - zoneBox.addItem(zone); - } - } - } - frame.pack(); - } - } - - @SuppressWarnings("serial") - private class SpellListAction extends AbstractAction { - public SpellListAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add spell")) { - RSpell rs = - (RSpell) - JOptionPane.showInputDialog( - neon.editor.Editor.getFrame(), - "Add spell:", - "Add spell", - JOptionPane.PLAIN_MESSAGE, - null, - spells, - 0); - if (rs != null) { - spellListModel.addElement(rs); - } - } else if (e.getActionCommand().equals("Delete spell")) { - spellListModel.remove(spellList.getSelectedIndex()); - } - } - } - - @SuppressWarnings("serial") - private class ItemListAction extends AbstractAction { - public ItemListAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add item")) { - Object[] items = Editor.resources.getResources(RItem.class).toArray(); - RItem ri = - (RItem) - JOptionPane.showInputDialog( - neon.editor.Editor.getFrame(), - "Add item:", - "Add item", - JOptionPane.PLAIN_MESSAGE, - null, - items, - 0); - if (ri != null) { - itemListModel.addElement(ri); - } - } else if (e.getActionCommand().equals("Delete item")) { - itemListModel.remove(itemList.getSelectedIndex()); - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2013 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import java.util.List; +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; +import neon.editor.help.HelpLabels; +import neon.editor.resources.RMap; +import neon.editor.resources.RZone; +import neon.resources.RCreature; +import neon.resources.RCreature.Type; +import neon.resources.RItem; +import neon.resources.RMod; +import neon.resources.RSpell; +import neon.resources.RSpell.SpellType; + +public class CCEditor + implements ActionListener, ItemListener, ListSelectionListener, MouseListener { + private JDialog frame; + private JCheckBox raceBox; + private JFormattedTextField xField, yField; + private JComboBox mapBox; + private JComboBox zoneBox; + private HashMap races; + private JList raceList; + private JList itemList; + private JList spellList; + private RCreature currentRace; + private DefaultListModel spellListModel; + private DefaultListModel itemListModel; + private String[] spells; + private JPanel raceEditPanel; + private final DataStore dataStore; + + public CCEditor(JFrame parent, DataStore dataStore) { + this.dataStore = dataStore; + frame = new JDialog(parent, "Character Creation Editor", true); // modal dialog + JPanel content = new JPanel(new BorderLayout()); + frame.setPreferredSize(new Dimension(400, 300)); + frame.setContentPane(content); + JTabbedPane tabs = new JTabbedPane(); + content.add(tabs, BorderLayout.CENTER); + + // races + JPanel racePanel = new JPanel(new GridLayout(0, 2)); + raceList = new JList(); + raceList.addListSelectionListener(this); + JScrollPane raceScroller = new JScrollPane(raceList); + raceScroller.setBorder(new TitledBorder("Races")); + racePanel.add(raceScroller); + raceEditPanel = new JPanel(); + raceEditPanel.setBorder(new TitledBorder("Edit")); + raceBox = new JCheckBox("Playable"); + raceBox.addActionListener(this); + raceEditPanel.add(raceBox); + racePanel.add(raceEditPanel); + + // position + JPanel mapPanel = new JPanel(); + mapPanel.setBorder(new EmptyBorder(20, 20, 20, 20)); + GroupLayout layout = new GroupLayout(mapPanel); + mapPanel.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel mapLabel = new JLabel("Map: "); + JLabel zoneLabel = new JLabel("Zone: "); + JLabel xLabel = new JLabel("x-coordinate: "); + JLabel yLabel = new JLabel("y-coordinate: "); + mapBox = new JComboBox(); + mapBox.addItemListener(this); + xField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + yField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + zoneBox = new JComboBox(); + JLabel mapHelpLabel = HelpLabels.getStartMapHelpLabel(); + JLabel zoneHelpLabel = HelpLabels.getStartZoneLabel(); + JLabel xHelpLabel = HelpLabels.getStartXLabel(); + JLabel yHelpLabel = HelpLabels.getStartYLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(mapLabel) + .addComponent(mapBox) + .addComponent(mapHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(zoneLabel) + .addComponent(zoneBox) + .addComponent(zoneHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(xLabel) + .addComponent(xField) + .addComponent(xHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(yLabel) + .addComponent(yField) + .addComponent(yHelpLabel)) + .addGap(10)); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(mapLabel) + .addComponent(zoneLabel) + .addComponent(xLabel) + .addComponent(yLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + mapBox, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(zoneBox) + .addComponent(xField) + .addComponent(yField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(mapHelpLabel) + .addComponent(zoneHelpLabel) + .addComponent(xHelpLabel) + .addComponent(yHelpLabel))); + + // starting items + JPanel itemPanel = new JPanel(new BorderLayout()); + itemListModel = new DefaultListModel(); + itemList = new JList(itemListModel); + itemList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + itemPanel.add(new JScrollPane(itemList)); + + // starting spells + JPanel spellPanel = new JPanel(new BorderLayout()); + spellListModel = new DefaultListModel(); + spellList = new JList(spellListModel); + spellList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + spellPanel.add(new JScrollPane(spellList)); + + tabs.add(racePanel, "Playable races"); + tabs.add(mapPanel, "Starting position"); + tabs.add(itemPanel, "Starting items"); + tabs.add(spellPanel, "Starting spells"); + + JPanel buttons = new JPanel(); + content.add(buttons, BorderLayout.PAGE_END); + JButton ok = new JButton("Ok"); + ok.addActionListener(this); + JButton apply = new JButton("Apply"); + apply.addActionListener(this); + JButton cancel = new JButton("Cancel"); + cancel.addActionListener(this); + buttons.add(ok); + + itemList.addMouseListener(this); + spellList.addMouseListener(this); + buttons.add(cancel); + buttons.add(apply); + } + + public void show() { + DataStore store = dataStore; + RMod mod = store.getActive(); + List playableRaces = new ArrayList(); + // if species does not exist, automatically remove it + for (String race : mod.getList("races")) { + if (dataStore.getResourceManager().getResource(race) instanceof RCreature) { + playableRaces.add((RCreature) dataStore.getResourceManager().getResource(race)); + } else { + mod.ccRaces.remove(race); + } + } + itemListModel.clear(); + // if item does not exist, automatically remove it + for (String item : mod.getList("items")) { + if (dataStore.getResourceManager().getResource(item) instanceof RItem) { + itemListModel.addElement((RItem) dataStore.getResourceManager().getResource(item)); + } else { + mod.ccRaces.remove(item); + } + } + spellListModel.clear(); + // if spell does not exist, automatically remove it + for (String spell : mod.getList("spells")) { + if (dataStore.getResourceManager().getResource(spell, "magic") != null) { + spellListModel.addElement( + (RSpell) dataStore.getResourceManager().getResource(spell, "magic")); + } else { + mod.ccRaces.remove(spell); + } + } + + races = new HashMap(); + for (RCreature rc : dataStore.getResourceManager().getResources(RCreature.class)) { + // only humanoids or goblins + if (rc.type == Type.humanoid || rc.type == Type.goblin) { + races.put(rc, playableRaces.contains(rc)); + } + } + raceList.setListData(races.keySet().toArray(new RCreature[0])); + + for (RMap map : dataStore.getResourceManager().getResources(RMap.class)) { + if (map.theme == null) { // do not allow random maps + mapBox.addItem(map); + } + } + RMap map = (RMap) dataStore.getResourceManager().getResource(mod.get("map"), "maps"); + mapBox.setSelectedItem(map); + for (RZone zone : map.zones.values()) { + if (zone.theme == null) { // do not allow random zones + zoneBox.addItem(zone); + } + } + zoneBox.setSelectedItem(map.getZone(Integer.parseInt(mod.get("z")))); + xField.setValue(Integer.parseInt(mod.get("x"))); + yField.setValue(Integer.parseInt(mod.get("y"))); + + ArrayList temp = new ArrayList(); + for (RSpell spell : dataStore.getResourceManager().getResources(RSpell.class)) { + if (spell.type == SpellType.SPELL) { + temp.add(spell.id); + } + } + spells = temp.toArray(new String[temp.size()]); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void saveAll() { + RMod mod = dataStore.getActive(); + if (mapBox.getSelectedItem() != null) { + RMap map = (RMap) mapBox.getSelectedItem(); + mod.set("map", map.id); + RZone zone = (RZone) zoneBox.getSelectedItem(); + mod.set("z", Integer.toString(map.getZone(zone))); + mod.set("x", xField.getText()); + mod.set("y", yField.getText()); + } else { + JOptionPane.showMessageDialog(frame, "No start map selected!"); + } + + mod.ccRaces.clear(); + for (RCreature rc : races.keySet()) { + if (races.get(rc)) { + mod.ccRaces.add(rc.id); + } + } + mod.ccItems.clear(); + for (Enumeration e = itemListModel.elements(); e.hasMoreElements(); ) { + RItem ri = e.nextElement(); + mod.ccItems.add(ri.id); + } + mod.ccSpells.clear(); + for (Enumeration e = spellListModel.elements(); e.hasMoreElements(); ) { + RSpell rs = e.nextElement(); + mod.ccSpells.add(rs.id); + } + } + + public void actionPerformed(ActionEvent e) { + if ("Playable".equals(e.getActionCommand())) { + races.put(currentRace, raceBox.isSelected()); + } else if ("Ok".equals(e.getActionCommand())) { + saveAll(); + frame.dispose(); + } else if ("Cancel".equals(e.getActionCommand())) { + frame.dispose(); + } else if ("Apply".equals(e.getActionCommand())) { + saveAll(); + } + } + + public void mouseExited(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mousePressed(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + if (e.getComponent() == spellList) { + JPopupMenu menu = new JPopupMenu(); + menu.add(new SpellListAction("Add spell")); + menu.add(new SpellListAction("Delete spell")); + menu.show(e.getComponent(), e.getX(), e.getY()); + spellList.setSelectedIndex(spellList.locationToIndex(e.getPoint())); + } else if (e.getComponent() == itemList) { + JPopupMenu menu = new JPopupMenu(); + menu.add(new ItemListAction("Add item")); + menu.add(new ItemListAction("Delete item")); + menu.show(e.getComponent(), e.getX(), e.getY()); + itemList.setSelectedIndex(itemList.locationToIndex(e.getPoint())); + } + } + } + + public void valueChanged(ListSelectionEvent e) { + // apparently two events are fired on selection + if (e.getValueIsAdjusting()) { + currentRace = raceList.getSelectedValue(); + raceBox.setSelected(races.get(currentRace)); + raceEditPanel.setBorder(new TitledBorder(currentRace.id)); + } + } + + public void itemStateChanged(ItemEvent e) { + if (mapBox.equals(e.getSource())) { + // load zones + zoneBox.setModel(new DefaultComboBoxModel()); + RMap map = (RMap) mapBox.getSelectedItem(); + if (map != null) { + for (RZone zone : map.zones.values()) { + if (zone.theme == null) { // do not allow random zones + zoneBox.addItem(zone); + } + } + } + frame.pack(); + } + } + + @SuppressWarnings("serial") + private class SpellListAction extends AbstractAction { + public SpellListAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add spell")) { + RSpell rs = + (RSpell) + JOptionPane.showInputDialog( + neon.editor.Editor.getFrame(), + "Add spell:", + "Add spell", + JOptionPane.PLAIN_MESSAGE, + null, + spells, + 0); + if (rs != null) { + spellListModel.addElement(rs); + } + } else if (e.getActionCommand().equals("Delete spell")) { + spellListModel.remove(spellList.getSelectedIndex()); + } + } + } + + @SuppressWarnings("serial") + private class ItemListAction extends AbstractAction { + public ItemListAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add item")) { + Object[] items = dataStore.getResourceManager().getResources(RItem.class).toArray(); + RItem ri = + (RItem) + JOptionPane.showInputDialog( + neon.editor.Editor.getFrame(), + "Add item:", + "Add item", + JOptionPane.PLAIN_MESSAGE, + null, + items, + 0); + if (ri != null) { + itemListModel.addElement(ri); + } + } else if (e.getActionCommand().equals("Delete item")) { + itemListModel.remove(itemList.getSelectedIndex()); + } + } + } +} diff --git a/src/main/java/neon/editor/DataStore.java b/src/main/java/neon/editor/DataStore.java index dc227a0..c8b9e00 100644 --- a/src/main/java/neon/editor/DataStore.java +++ b/src/main/java/neon/editor/DataStore.java @@ -22,7 +22,6 @@ import com.google.common.collect.Multimap; import java.io.File; import java.util.*; - import lombok.Getter; import neon.editor.resources.RFaction; import neon.editor.resources.RMap; @@ -35,25 +34,23 @@ import org.jdom2.Element; public class DataStore { - @Getter - private final HashMap scripts = new HashMap(); - @Getter - private final Multimap events = ArrayListMultimap.create(); + @Getter private final HashMap scripts = new HashMap(); + @Getter private final Multimap events = ArrayListMultimap.create(); private final HashMap mods = new HashMap(); - private final ResourceManager resourceManager; - private final FileSystem fileSystem; - @Getter - private RMod active; + @Getter private final ResourceManager resourceManager; + @Getter private final FileSystem fileSystem; + @Getter private RMod active; public DataStore(ResourceManager resourceManager, FileSystem fileSystem) { - this.resourceManager = resourceManager; - this.fileSystem = fileSystem; + this.resourceManager = resourceManager; + this.fileSystem = fileSystem; } - public RMod getMod(String id) { + + public RMod getMod(String id) { return mods.get(id); } - /** + /** * Loads all data from a mod. * *

NOTE (Phase 6 - Minimal Migration): Currently uses JDOM constructors for resource loading. @@ -95,7 +92,7 @@ public void loadData(String root, boolean active, boolean extension) { private void loadEvents(RMod mod, String... file) { try { for (Element event : - fileSystem.getFile(new XMLTranslator(), file).getRootElement().getChildren()) { + fileSystem.getFile(new XMLTranslator(), file).getRootElement().getChildren()) { events.put(event.getAttributeValue("script"), event.getAttributeValue("tick")); } } catch (NullPointerException e) { @@ -157,7 +154,8 @@ private void loadMaps(RMod mod, String... file) { s = s.substring(s.lastIndexOf(File.separator) + 1); path[file.length] = s; Element map = fileSystem.getFile(new XMLTranslator(), path).getRootElement(); - resourceManager.addResource(new RMap(s.replace(".xml", ""), map,resourceManager, mod.get("id")), "maps"); + resourceManager.addResource( + new RMap(s.replace(".xml", ""), map, this, mod.get("id")), "maps"); } } catch (NullPointerException e) { } @@ -184,15 +182,16 @@ private void loadMagic(RMod mod, String... path) { try { Document doc = fileSystem.getFile(new XMLTranslator(), path); for (Element e : doc.getRootElement().getChildren()) { - switch (e.getName()) { - case "sign" -> resourceManager.addResource(new RSign(e, mod.get("id")), "magic"); - case "tattoo" -> resourceManager.addResource(new RTattoo(e, mod.get("id")), "magic"); - case "recipe" -> resourceManager.addResource(new RRecipe(e, mod.get("id")), "magic"); - case "list" -> resourceManager.addResource(new LSpell(e, mod.get("id")), "magic"); - case "power" -> resourceManager.addResource(new RSpell.Power(e, mod.get("id")), "magic"); - case "enchant" -> resourceManager.addResource(new RSpell.Enchantment(e, mod.get("id")), "magic"); - default -> resourceManager.addResource(new RSpell(e, mod.get("id")), "magic"); - } + switch (e.getName()) { + case "sign" -> resourceManager.addResource(new RSign(e, mod.get("id")), "magic"); + case "tattoo" -> resourceManager.addResource(new RTattoo(e, mod.get("id")), "magic"); + case "recipe" -> resourceManager.addResource(new RRecipe(e, mod.get("id")), "magic"); + case "list" -> resourceManager.addResource(new LSpell(e, mod.get("id")), "magic"); + case "power" -> resourceManager.addResource(new RSpell.Power(e, mod.get("id")), "magic"); + case "enchant" -> + resourceManager.addResource(new RSpell.Enchantment(e, mod.get("id")), "magic"); + default -> resourceManager.addResource(new RSpell(e, mod.get("id")), "magic"); + } } } catch (NullPointerException e) { } @@ -202,12 +201,12 @@ private void loadCreatures(RMod mod, String... path) { try { Document doc = fileSystem.getFile(new XMLTranslator(), path); for (Element e : doc.getRootElement().getChildren()) { - switch (e.getName()) { - case "list" -> resourceManager.addResource(new LCreature(e, mod.get("id"))); - case "npc" -> resourceManager.addResource(new RPerson(e, mod.get("id"))); - case "group" -> {} - default -> resourceManager.addResource(new RCreature(e, mod.get("id"))); - } + switch (e.getName()) { + case "list" -> resourceManager.addResource(new LCreature(e, mod.get("id"))); + case "npc" -> resourceManager.addResource(new RPerson(e, mod.get("id"))); + case "group" -> {} + default -> resourceManager.addResource(new RCreature(e, mod.get("id"))); + } } } catch (NullPointerException e) { e.printStackTrace(); @@ -238,17 +237,17 @@ private void loadItems(RMod mod, String... path) { try { Document doc = fileSystem.getFile(new XMLTranslator(), path); for (Element e : doc.getRootElement().getChildren()) { - switch (e.getName()) { - case "list" -> resourceManager.addResource(new LItem(e, mod.get("id"))); - case "book", "scroll" -> resourceManager.addResource(new RItem.Text(e, mod.get("id"))); - case "armor", "clothing" -> resourceManager.addResource(new RClothing(e, mod.get("id"))); - case "weapon" -> resourceManager.addResource(new RWeapon(e, mod.get("id"))); - case "craft" -> resourceManager.addResource(new RCraft(e, mod.get("id"))); - case "door" -> resourceManager.addResource(new RItem.Door(e, mod.get("id"))); - case "potion" -> resourceManager.addResource(new RItem.Potion(e, mod.get("id"))); - case "container" -> resourceManager.addResource(new RItem.Container(e, mod.get("id"))); - default -> resourceManager.addResource(new RItem(e, mod.get("id"))); - } + switch (e.getName()) { + case "list" -> resourceManager.addResource(new LItem(e, mod.get("id"))); + case "book", "scroll" -> resourceManager.addResource(new RItem.Text(e, mod.get("id"))); + case "armor", "clothing" -> resourceManager.addResource(new RClothing(e, mod.get("id"))); + case "weapon" -> resourceManager.addResource(new RWeapon(e, mod.get("id"))); + case "craft" -> resourceManager.addResource(new RCraft(e, mod.get("id"))); + case "door" -> resourceManager.addResource(new RItem.Door(e, mod.get("id"))); + case "potion" -> resourceManager.addResource(new RItem.Potion(e, mod.get("id"))); + case "container" -> resourceManager.addResource(new RItem.Container(e, mod.get("id"))); + default -> resourceManager.addResource(new RItem(e, mod.get("id"))); + } } } catch (NullPointerException e) { } @@ -258,11 +257,12 @@ private void loadThemes(RMod mod, String... path) { try { Document doc = fileSystem.getFile(new XMLTranslator(), path); for (Element e : doc.getRootElement().getChildren()) { - switch (e.getName()) { - case "dungeon" -> resourceManager.addResource(new RDungeonTheme(e, mod.get("id")), "theme"); - case "region" -> resourceManager.addResource(new RRegionTheme(e, mod.get("id")), "theme"); - case "zone" -> resourceManager.addResource(new RZoneTheme(e, mod.get("id")), "theme"); - } + switch (e.getName()) { + case "dungeon" -> + resourceManager.addResource(new RDungeonTheme(e, mod.get("id")), "theme"); + case "region" -> resourceManager.addResource(new RRegionTheme(e, mod.get("id")), "theme"); + case "zone" -> resourceManager.addResource(new RZoneTheme(e, mod.get("id")), "theme"); + } } } catch (NullPointerException e) { } diff --git a/src/main/java/neon/editor/Editor.java b/src/main/java/neon/editor/Editor.java index fdf66db..e545f79 100644 --- a/src/main/java/neon/editor/Editor.java +++ b/src/main/java/neon/editor/Editor.java @@ -1,647 +1,644 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor; - -import java.awt.*; -import java.awt.event.*; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Scanner; -import java.util.jar.JarFile; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import javax.swing.tree.*; -import neon.editor.help.HelpLabels; -import neon.editor.maps.*; -import neon.editor.resources.*; -import neon.resources.*; -import neon.resources.quest.RQuest; -import neon.systems.files.*; -import neon.ui.HelpWindow; - -// TODO: use mbassador for events -public class Editor implements Runnable, ActionListener { - public static JCheckBoxMenuItem tShow, tEdit, oShow, oEdit; - private final FileSystem files; - private final ResourceManager resources; - private static JFrame frame; - private static DataStore store; - private static JPanel toolPanel; - private static StatusBar status; - - protected MapEditor mapEditor; - private JTabbedPane mapTabbedPane; - private JMenuBar menuBar; - private JMenuItem pack, unpack, newMain, newExt, load, save, export, calculate; - private JMenu make, edit, tools; - private JPanel terrainPanel, objectPanel, resourcePanel; - private JTree objectTree, resourceTree; - private ModFiler filer; - private JList terrainList; - private DefaultListModel terrainListModel; - private InfoEditor infoEditor; - private CCEditor ccEditor; - private ScriptEditor scriptEditor; - private EventEditor eventEditor; - - public static void main(String[] args) throws IOException { - try { // set directly here to avoid problems - javax.swing.UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException e) { - e.printStackTrace(); - } - Editor editor = new Editor(); - javax.swing.SwingUtilities.invokeLater(editor); - } - - public Editor() throws IOException { - // main window - frame = new JFrame("Neon Editor"); - frame.getContentPane().setLayout(new BorderLayout()); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setPreferredSize(new Dimension(1280, 800)); - - // stuff - files = new FileSystem(); - resources = new ResourceManager(); - store = new DataStore(resources,files); - - // menu bar - menuBar = new JMenuBar(); - JMenu file = new JMenu("File"); - make = new JMenu("New"); - newMain = new JMenuItem("Master module..."); - newExt = new JMenuItem("Extension module..."); - load = new JMenuItem("Load..."); - save = new JMenuItem("Save"); - JMenuItem quit = new JMenuItem("Exit"); - newMain.setActionCommand("newMain"); - newExt.setActionCommand("newExt"); - save.setActionCommand("save"); - load.setActionCommand("load"); - quit.setActionCommand("quit"); - newMain.addActionListener(this); - newExt.addActionListener(this); - quit.addActionListener(this); - filer = new ModFiler(frame, files, store, this); - save.addActionListener(this); - load.addActionListener(this); - save.setEnabled(false); - make.add(newMain); - make.add(newExt); - file.add(make); - file.add(load); - file.addSeparator(); - file.add(save); - file.addSeparator(); - file.add(quit); - edit = new JMenu("Edit"); - edit.setEnabled(false); - JMenuItem script = new JMenuItem("Scripts..."); - JMenuItem events = new JMenuItem("Events..."); - JMenuItem cc = new JMenuItem("Character creation..."); - JMenuItem game = new JMenuItem("Game info..."); - script.setActionCommand("script"); - cc.setActionCommand("cc"); - game.setActionCommand("game"); - events.setActionCommand("events"); - script.addActionListener(this); - cc.addActionListener(this); - game.addActionListener(this); - events.addActionListener(this); - edit.add(script); - edit.add(events); - edit.add(cc); - edit.add(game); - JMenu view = new JMenu("View"); - tShow = new JCheckBoxMenuItem("Show terrain"); - oShow = new JCheckBoxMenuItem("Show objects"); - tEdit = new JCheckBoxMenuItem("Edit terrain"); - oEdit = new JCheckBoxMenuItem("Edit objects"); - tShow.setSelected(true); - oShow.setSelected(true); - tEdit.setSelected(true); - oEdit.setSelected(true); - view.add(tShow); - view.add(oShow); - view.addSeparator(); - view.add(tEdit); - view.add(oEdit); - tools = new JMenu("Tools"); - tools.setEnabled(false); - unpack = new JMenuItem("Unpack mod..."); - unpack.setActionCommand("unpack"); - unpack.addActionListener(this); - pack = new JMenuItem("Pack mod..."); - pack.setActionCommand("pack"); - pack.addActionListener(this); - tools.add(unpack); - tools.add(pack); - tools.addSeparator(); - export = new JMenuItem("Export SVG..."); - export.setActionCommand("svg"); - export.addActionListener(this); - calculate = new JMenuItem("Challenge calculator..."); - calculate.setActionCommand("calculate"); - calculate.addActionListener(this); - tools.add(export); - tools.add(calculate); - JMenu help = new JMenu("Help"); - JMenuItem introGuide = new JMenuItem("Getting started..."); - introGuide.setActionCommand("intro"); - introGuide.addActionListener(this); - help.add(introGuide); - JMenuItem scriptGuide = new JMenuItem("Scripting guide..."); - scriptGuide.setActionCommand("scripting"); - scriptGuide.addActionListener(this); - help.add(scriptGuide); - JMenuItem mapGuide = new JMenuItem("Map editing..."); - mapGuide.setActionCommand("mapping"); - mapGuide.addActionListener(this); - help.add(mapGuide); - JMenuItem resGuide = new JMenuItem("Resource editing..."); - resGuide.setActionCommand("resources"); - resGuide.addActionListener(this); - help.add(resGuide); - menuBar.add(file); - menuBar.add(edit); - menuBar.add(view); - menuBar.add(tools); - menuBar.add(help); - frame.setJMenuBar(menuBar); - - toolPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - frame.add(toolPanel, BorderLayout.PAGE_START); - - // objects - objectTree = new JTree(); - objectTree.setRootVisible(false); - objectTree.setShowsRootHandles(true); - resourceTree = new JTree(); - resourceTree.setRootVisible(false); - resourceTree.setShowsRootHandles(true); - - // panels with maps - mapTabbedPane = new JTabbedPane(); - JPanel mapPanel = new JPanel(new BorderLayout()); - mapEditor = new MapEditor(mapTabbedPane, mapPanel,resources); - - // panel with objects and terrain - JTabbedPane editPanel = new JTabbedPane(); - objectPanel = new JPanel(new BorderLayout()); - objectPanel.setBorder(new TitledBorder("Objects")); - editPanel.add(objectPanel, "Objects"); - terrainPanel = new JPanel(new BorderLayout()); - terrainPanel.setBorder(new TitledBorder("Terrain")); - editPanel.add(terrainPanel, "Terrain"); - resourcePanel = new JPanel(new BorderLayout()); - resourcePanel.setBorder(new TitledBorder("Resources")); - editPanel.add(resourcePanel, "Resources"); - - // fiddling with JSplitPanes to get three columns - JSplitPane bigSplitPane = new JSplitPane(); - JSplitPane smallSplitPane = new JSplitPane(); - smallSplitPane.setLeftComponent(mapPanel); - smallSplitPane.setRightComponent(mapTabbedPane); - bigSplitPane.setLeftComponent(smallSplitPane); - bigSplitPane.setRightComponent(editPanel); - - // this could be better - smallSplitPane.setDividerLocation(200); - bigSplitPane.setDividerLocation(1000); - frame.add(bigSplitPane, BorderLayout.CENTER); - - // status bar - status = new StatusBar(); - frame.add(status, BorderLayout.SOUTH); - } - - public void run() { - frame.pack(); - frame.setLocationRelativeTo(null); - frame.setVisible(true); - } - - public static DataStore getStore() { - return store; - } - - public static JFrame getFrame() { - return frame; - } - - private void createMain() { - JFileChooser chooser = new JFileChooser(new File("neon.ini.xml")); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - chooser.setDialogTitle("Choose module directory"); - if (chooser.showDialog(frame, "Choose") == JFileChooser.APPROVE_OPTION) { - // create mod - createMod(chooser.getSelectedFile()); - // enable editing - enableEditing(true); - frame.pack(); - } - } - - private void createMod(File file) { - // path here is the name of the dir, only files knows the full path - String path = file.getName(); // this also becomes the mod id - try { - files.mount(file.getPath()); - // generate directories - File objects = new File(file, "objects"); - objects.mkdir(); - File maps = new File(file, "maps"); - maps.mkdir(); - File quests = new File(file, "quests"); - quests.mkdir(); - File themes = new File(file, "themes"); - themes.mkdir(); - - // load ensures that all resources etc. are initialized - store.loadData(path, true, false); - mapEditor.loadMaps(resources.getResources(RMap.class), path); - } catch (IOException e) { - JOptionPane.showMessageDialog(frame, "Invalid mod directory: " + file + "."); - } - } - - protected void enableEditing(boolean unpacked) { - // enable menu items - pack.setEnabled(unpacked); - unpack.setEnabled(!unpacked); - make.setEnabled(false); - tools.setEnabled(true); - edit.setEnabled(true); - load.setEnabled(false); - save.setEnabled(true); - - // prepare lists - initObjects(); - initResources(); - initTerrain(); - } - - private void createExtension() { - JFileChooser chooser = new JFileChooser(new File("neon.ini.xml")); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - chooser.setDialogTitle("Choose master module"); - if (chooser.showDialog(frame, "Master") == JFileChooser.APPROVE_OPTION) { - File master = chooser.getSelectedFile(); - chooser.setDialogTitle("Choose extension directory"); - if (chooser.showDialog(frame, "Extension") == JFileChooser.APPROVE_OPTION) { - // load master - filer.load(master, false); - // create extension - createMod(chooser.getSelectedFile()); - enableEditing(true); - frame.pack(); - } - } - } - - public static void addToolBar(JToolBar bar) { - toolPanel.add(bar); - } - - public static StatusBar getStatusBar() { - return status; - } - - private void initTerrain() { - terrainListModel = new DefaultListModel(); - for (RTerrain rt : resources.getResources(RTerrain.class)) { - terrainListModel.addElement(rt); - } - terrainList = new JList(terrainListModel); - terrainList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - TerrainListener listener = new TerrainListener(mapEditor, terrainList); - terrainList.addListSelectionListener(listener); - terrainList.addMouseListener(listener); - terrainPanel.add(new JScrollPane(terrainList)); - } - - private void initResources() { - DefaultMutableTreeNode top = new DefaultMutableTreeNode("Resources"); - - // crafts - ResourceNode craftNode = new ResourceNode("Crafting", ResourceNode.ResourceType.CRAFT); - for (RCraft craft : resources.getResources(RCraft.class)) { - craftNode.add(new ResourceNode(craft, ResourceNode.ResourceType.CRAFT)); - } - top.add(craftNode); - - // factions - ResourceNode factionNode = new ResourceNode("Factions", ResourceNode.ResourceType.FACTION); - for (RFaction faction : resources.getResources(RFaction.class)) { - factionNode.add(new ResourceNode(faction, ResourceNode.ResourceType.FACTION)); - } - top.add(factionNode); - - // region themes - ResourceNode regionNode = new ResourceNode("Region themes", ResourceNode.ResourceType.REGION); - for (RRegionTheme region : resources.getResources(RRegionTheme.class)) { - regionNode.add(new ResourceNode(region, ResourceNode.ResourceType.REGION)); - } - top.add(regionNode); - - // zone themes - ResourceNode zoneNode = new ResourceNode("Zone themes", ResourceNode.ResourceType.ZONE); - for (RZoneTheme zone : resources.getResources(RZoneTheme.class)) { - zoneNode.add(new ResourceNode(zone, ResourceNode.ResourceType.ZONE)); - } - top.add(zoneNode); - - // dungeon themes - ResourceNode dungeonNode = - new ResourceNode("Dungeon themes", ResourceNode.ResourceType.DUNGEON); - for (RDungeonTheme dungeon : resources.getResources(RDungeonTheme.class)) { - dungeonNode.add(new ResourceNode(dungeon, ResourceNode.ResourceType.DUNGEON)); - } - top.add(dungeonNode); - - // quests - ResourceNode questNode = new ResourceNode("Quests", ResourceNode.ResourceType.QUEST); - for (RQuest quest : resources.getResources(RQuest.class)) { - questNode.add(new ResourceNode(quest, ResourceNode.ResourceType.QUEST)); - } - top.add(questNode); - - // alchemy - ResourceNode alchemyNode = new ResourceNode("Alchemy", ResourceNode.ResourceType.RECIPE); - for (RRecipe rr : resources.getResources(RRecipe.class)) { - alchemyNode.add(new ResourceNode(rr, ResourceNode.ResourceType.RECIPE)); - } - top.add(alchemyNode); - - // tattoos - ResourceNode tattooNode = new ResourceNode("Tattoos", ResourceNode.ResourceType.TATTOO); - for (RTattoo rt : resources.getResources(RTattoo.class)) { - tattooNode.add(new ResourceNode(rt, ResourceNode.ResourceType.TATTOO)); - } - top.add(tattooNode); - - // spells - ResourceNode spellNode = new ResourceNode("Spells", ResourceNode.ResourceType.SPELL); - ResourceNode powerNode = new ResourceNode("Powers", ResourceNode.ResourceType.POWER); - ResourceNode curseNode = new ResourceNode("Curses", ResourceNode.ResourceType.CURSE); - ResourceNode poisonNode = new ResourceNode("Poison", ResourceNode.ResourceType.POISON); - ResourceNode enchantNode = - new ResourceNode("Enchantments", ResourceNode.ResourceType.ENCHANTMENT); - ResourceNode diseaseNode = new ResourceNode("Diseases", ResourceNode.ResourceType.DISEASE); - ResourceNode levelNode = - new ResourceNode("Leveled spells", ResourceNode.ResourceType.LEVEL_SPELL); - for (RSpell rs : resources.getResources(RSpell.class)) { - if (rs instanceof LSpell) { - levelNode.add(new ResourceNode(rs, ResourceNode.ResourceType.LEVEL_SPELL)); - } else { - switch (rs.type) { - case CURSE: - curseNode.add(new ResourceNode(rs, ResourceNode.ResourceType.CURSE)); - break; - case DISEASE: - diseaseNode.add(new ResourceNode(rs, ResourceNode.ResourceType.DISEASE)); - break; - case ENCHANT: - enchantNode.add(new ResourceNode(rs, ResourceNode.ResourceType.ENCHANTMENT)); - break; - case POISON: - poisonNode.add(new ResourceNode(rs, ResourceNode.ResourceType.POISON)); - break; - case POWER: - powerNode.add(new ResourceNode(rs, ResourceNode.ResourceType.POWER)); - break; - case SPELL: - spellNode.add(new ResourceNode(rs, ResourceNode.ResourceType.SPELL)); - break; - } - } - } - top.add(spellNode); - top.add(powerNode); - top.add(curseNode); - top.add(poisonNode); - top.add(enchantNode); - top.add(diseaseNode); - top.add(levelNode); - - // signs - ResourceNode signNode = new ResourceNode("Birth signs", ResourceNode.ResourceType.SIGN); - for (RSign rs : resources.getResources(RSign.class)) { - signNode.add(new ResourceNode(rs, ResourceNode.ResourceType.SIGN)); - } - top.add(signNode); - - resourceTree.setModel(new DefaultTreeModel(top)); - resourceTree.addMouseListener(new ResourceTreeListener(resourceTree, frame)); - resourcePanel.add(new JScrollPane(resourceTree)); - } - - private void initObjects() { - DefaultMutableTreeNode top = new DefaultMutableTreeNode("Objects"); - - // creatures; - ObjectNode creatureNode = new ObjectNode("Creatures", ObjectNode.ObjectType.CREATURE); - ObjectNode levelCreatureNode = - new ObjectNode("Leveled creatures", ObjectNode.ObjectType.LEVEL_CREATURE); - for (RCreature rc : resources.getResources(RCreature.class)) { - if (rc instanceof LCreature) { - levelCreatureNode.add(new ObjectNode(rc, ObjectNode.ObjectType.LEVEL_CREATURE)); - } else { - creatureNode.add(new ObjectNode(rc, ObjectNode.ObjectType.CREATURE)); - } - } - top.add(creatureNode); - top.add(levelCreatureNode); - - // NPCs - ObjectNode npcNode = new ObjectNode("NPCs", ObjectNode.ObjectType.NPC); - for (RPerson rp : resources.getResources(RPerson.class)) { - npcNode.add(new ObjectNode(rp, ObjectNode.ObjectType.NPC)); - } - top.add(npcNode); - - // items - ObjectNode itemNode = new ObjectNode("Items", ObjectNode.ObjectType.ITEM); - ObjectNode weaponNode = new ObjectNode("Weapons", ObjectNode.ObjectType.WEAPON); - ObjectNode clothingNode = new ObjectNode("Clothing", ObjectNode.ObjectType.CLOTHING); - ObjectNode armorNode = new ObjectNode("Armor", ObjectNode.ObjectType.ARMOR); - ObjectNode lightNode = new ObjectNode("Light", ObjectNode.ObjectType.LIGHT); - ObjectNode doorNode = new ObjectNode("Doors", ObjectNode.ObjectType.DOOR); - ObjectNode containerNode = new ObjectNode("Containers", ObjectNode.ObjectType.CONTAINER); - ObjectNode potionNode = new ObjectNode("Potions", ObjectNode.ObjectType.POTION); - ObjectNode scrollNode = new ObjectNode("Scrolls", ObjectNode.ObjectType.SCROLL); - ObjectNode bookNode = new ObjectNode("Books", ObjectNode.ObjectType.BOOK); - ObjectNode coinNode = new ObjectNode("Money", ObjectNode.ObjectType.MONEY); - ObjectNode foodNode = new ObjectNode("Food", ObjectNode.ObjectType.FOOD); - ObjectNode levelItemNode = new ObjectNode("Leveled items", ObjectNode.ObjectType.LEVEL_ITEM); - for (RItem ri : resources.getResources(RItem.class)) { - if (ri instanceof LItem) { - levelItemNode.add(new ObjectNode(ri, ObjectNode.ObjectType.LEVEL_ITEM)); - } else { - switch (ri.type) { - case armor: - armorNode.add(new ObjectNode(ri, ObjectNode.ObjectType.ARMOR)); - break; - case book: - bookNode.add(new ObjectNode(ri, ObjectNode.ObjectType.BOOK)); - break; - case clothing: - clothingNode.add(new ObjectNode(ri, ObjectNode.ObjectType.CLOTHING)); - break; - case coin: - coinNode.add(new ObjectNode(ri, ObjectNode.ObjectType.MONEY)); - break; - case container: - containerNode.add(new ObjectNode(ri, ObjectNode.ObjectType.CONTAINER)); - break; - case door: - doorNode.add(new ObjectNode(ri, ObjectNode.ObjectType.DOOR)); - break; - case food: - foodNode.add(new ObjectNode(ri, ObjectNode.ObjectType.FOOD)); - break; - case light: - lightNode.add(new ObjectNode(ri, ObjectNode.ObjectType.LIGHT)); - break; - case potion: - potionNode.add(new ObjectNode(ri, ObjectNode.ObjectType.POTION)); - break; - case scroll: - scrollNode.add(new ObjectNode(ri, ObjectNode.ObjectType.SCROLL)); - break; - case weapon: - weaponNode.add(new ObjectNode(ri, ObjectNode.ObjectType.WEAPON)); - break; - default: - itemNode.add(new ObjectNode(ri, ObjectNode.ObjectType.ITEM)); - } - } - } - top.add(itemNode); - top.add(weaponNode); - top.add(clothingNode); - top.add(armorNode); - top.add(lightNode); - top.add(doorNode); - top.add(containerNode); - top.add(potionNode); - top.add(scrollNode); - top.add(bookNode); - top.add(coinNode); - top.add(foodNode); - top.add(levelItemNode); - - objectTree.setModel(new DefaultTreeModel(top)); - objectTree.addMouseListener(new ObjectTreeListener(objectTree, frame)); - objectPanel.add(new JScrollPane(objectTree)); - objectTree.setDragEnabled(true); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("save")) { - filer.save(); - } else if (e.getActionCommand().equals("load")) { - filer.loadMod(); - } else if (e.getActionCommand().equals("quit")) { - System.exit(0); - } else if (e.getActionCommand().equals("newMain")) { - createMain(); - } else if (e.getActionCommand().equals("newExt")) { - createExtension(); - } else if (e.getActionCommand().equals("script")) { - if (scriptEditor == null) { - scriptEditor = new ScriptEditor(frame); - } - scriptEditor.show(); - } else if (e.getActionCommand().equals("cc")) { - if (ccEditor == null) { - ccEditor = new CCEditor(frame); - } - ccEditor.show(); - } else if (e.getActionCommand().equals("game")) { - if (infoEditor == null) { - infoEditor = new InfoEditor(frame); - } - infoEditor.show(); - } else if (e.getActionCommand().equals("events")) { - if (eventEditor == null) { - eventEditor = new EventEditor(frame); - } - eventEditor.show(); - } else if (e.getActionCommand().equals("pack")) { - if (JOptionPane.showConfirmDialog( - frame, - "Do you wish to save the current data and pack it?", - "Pack mod", - JOptionPane.YES_NO_OPTION) - == 0) { - pack(); - } - } else if (e.getActionCommand().equals("unpack")) { - unpack(); - } else if (e.getActionCommand().equals("svg")) { - if ((EditablePane) mapTabbedPane.getSelectedComponent() != null) { - ZoneTreeNode node = ((EditablePane) mapTabbedPane.getSelectedComponent()).getNode(); - SVGExporter.exportToSVG(node, files, store); - } - } else if (e.getActionCommand().equals("calculate")) { - new ChallengeCalculator().show(); - } else if (e.getActionCommand().equals("scripting")) { - showHelp("scripting.html", "Scripting guide"); - } else if (e.getActionCommand().equals("intro")) { - showHelp("intro.html", "Getting started"); - } else if (e.getActionCommand().equals("mapping")) { - showHelp("maps.html", "Map editing"); - } else if (e.getActionCommand().equals("resources")) { - showHelp("resources.html", "Resource editing"); - } - } - - private void showHelp(String file, String title) { - InputStream input = HelpLabels.class.getResourceAsStream(file); - Scanner scanner = new Scanner(input, "UTF-8"); - String text = scanner.useDelimiter("\\A").next(); - scanner.close(); - new HelpWindow(frame).show(title, text); - } - - private void pack() { - filer.save(); - try { - JarFile jar = FileUtils.pack(store.getActive().getPath()[0], store.getActive().get("id")); - System.out.println("attributes: " + jar.getManifest().getMainAttributes()); - } catch (IOException e) { - JOptionPane.showMessageDialog(frame, "Packing failed"); - } - } - - private void unpack() { - FileUtils.unpack(store.getActive().getPath()[0]); - JOptionPane.showMessageDialog( - frame, - "Please restart the editor and load the unpacked mod.", - "Unpack mod", - JOptionPane.INFORMATION_MESSAGE); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2013 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor; + +import java.awt.*; +import java.awt.event.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Scanner; +import java.util.jar.JarFile; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.swing.tree.*; +import lombok.Getter; +import neon.editor.help.HelpLabels; +import neon.editor.maps.*; +import neon.editor.resources.*; +import neon.resources.*; +import neon.resources.quest.RQuest; +import neon.systems.files.*; +import neon.ui.HelpWindow; + +// TODO: use mbassador for events +public class Editor implements Runnable, ActionListener { + public static JCheckBoxMenuItem tShow, tEdit, oShow, oEdit; + @Getter private final FileSystem files; + @Getter private final ResourceManager resources; + @Getter private static JFrame frame; + @Getter private final DataStore store; + private static JPanel toolPanel; + private static StatusBar status; + + protected MapEditor mapEditor; + private JTabbedPane mapTabbedPane; + private JMenuBar menuBar; + private JMenuItem pack, unpack, newMain, newExt, load, save, export, calculate; + private JMenu make, edit, tools; + private JPanel terrainPanel, objectPanel, resourcePanel; + private JTree objectTree, resourceTree; + private ModFiler filer; + private JList terrainList; + private DefaultListModel terrainListModel; + private InfoEditor infoEditor; + private CCEditor ccEditor; + private ScriptEditor scriptEditor; + private EventEditor eventEditor; + + public static void main(String[] args) throws IOException { + try { // set directly here to avoid problems + javax.swing.UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException e) { + e.printStackTrace(); + } + Editor editor = new Editor(); + javax.swing.SwingUtilities.invokeLater(editor); + } + + public Editor() throws IOException { + // main window + frame = new JFrame("Neon Editor"); + frame.getContentPane().setLayout(new BorderLayout()); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setPreferredSize(new Dimension(1280, 800)); + + // stuff + files = new FileSystem(); + resources = new ResourceManager(); + store = new DataStore(resources, files); + + // menu bar + menuBar = new JMenuBar(); + JMenu file = new JMenu("File"); + make = new JMenu("New"); + newMain = new JMenuItem("Master module..."); + newExt = new JMenuItem("Extension module..."); + load = new JMenuItem("Load..."); + save = new JMenuItem("Save"); + JMenuItem quit = new JMenuItem("Exit"); + newMain.setActionCommand("newMain"); + newExt.setActionCommand("newExt"); + save.setActionCommand("save"); + load.setActionCommand("load"); + quit.setActionCommand("quit"); + newMain.addActionListener(this); + newExt.addActionListener(this); + quit.addActionListener(this); + filer = new ModFiler(frame, files, store, this); + save.addActionListener(this); + load.addActionListener(this); + save.setEnabled(false); + make.add(newMain); + make.add(newExt); + file.add(make); + file.add(load); + file.addSeparator(); + file.add(save); + file.addSeparator(); + file.add(quit); + edit = new JMenu("Edit"); + edit.setEnabled(false); + JMenuItem script = new JMenuItem("Scripts..."); + JMenuItem events = new JMenuItem("Events..."); + JMenuItem cc = new JMenuItem("Character creation..."); + JMenuItem game = new JMenuItem("Game info..."); + script.setActionCommand("script"); + cc.setActionCommand("cc"); + game.setActionCommand("game"); + events.setActionCommand("events"); + script.addActionListener(this); + cc.addActionListener(this); + game.addActionListener(this); + events.addActionListener(this); + edit.add(script); + edit.add(events); + edit.add(cc); + edit.add(game); + JMenu view = new JMenu("View"); + tShow = new JCheckBoxMenuItem("Show terrain"); + oShow = new JCheckBoxMenuItem("Show objects"); + tEdit = new JCheckBoxMenuItem("Edit terrain"); + oEdit = new JCheckBoxMenuItem("Edit objects"); + tShow.setSelected(true); + oShow.setSelected(true); + tEdit.setSelected(true); + oEdit.setSelected(true); + view.add(tShow); + view.add(oShow); + view.addSeparator(); + view.add(tEdit); + view.add(oEdit); + tools = new JMenu("Tools"); + tools.setEnabled(false); + unpack = new JMenuItem("Unpack mod..."); + unpack.setActionCommand("unpack"); + unpack.addActionListener(this); + pack = new JMenuItem("Pack mod..."); + pack.setActionCommand("pack"); + pack.addActionListener(this); + tools.add(unpack); + tools.add(pack); + tools.addSeparator(); + export = new JMenuItem("Export SVG..."); + export.setActionCommand("svg"); + export.addActionListener(this); + calculate = new JMenuItem("Challenge calculator..."); + calculate.setActionCommand("calculate"); + calculate.addActionListener(this); + tools.add(export); + tools.add(calculate); + JMenu help = new JMenu("Help"); + JMenuItem introGuide = new JMenuItem("Getting started..."); + introGuide.setActionCommand("intro"); + introGuide.addActionListener(this); + help.add(introGuide); + JMenuItem scriptGuide = new JMenuItem("Scripting guide..."); + scriptGuide.setActionCommand("scripting"); + scriptGuide.addActionListener(this); + help.add(scriptGuide); + JMenuItem mapGuide = new JMenuItem("Map editing..."); + mapGuide.setActionCommand("mapping"); + mapGuide.addActionListener(this); + help.add(mapGuide); + JMenuItem resGuide = new JMenuItem("Resource editing..."); + resGuide.setActionCommand("resources"); + resGuide.addActionListener(this); + help.add(resGuide); + menuBar.add(file); + menuBar.add(edit); + menuBar.add(view); + menuBar.add(tools); + menuBar.add(help); + frame.setJMenuBar(menuBar); + + toolPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + frame.add(toolPanel, BorderLayout.PAGE_START); + + // objects + objectTree = new JTree(); + objectTree.setRootVisible(false); + objectTree.setShowsRootHandles(true); + resourceTree = new JTree(); + resourceTree.setRootVisible(false); + resourceTree.setShowsRootHandles(true); + + // panels with maps + mapTabbedPane = new JTabbedPane(); + JPanel mapPanel = new JPanel(new BorderLayout()); + mapEditor = new MapEditor(mapTabbedPane, mapPanel, store); + + // panel with objects and terrain + JTabbedPane editPanel = new JTabbedPane(); + objectPanel = new JPanel(new BorderLayout()); + objectPanel.setBorder(new TitledBorder("Objects")); + editPanel.add(objectPanel, "Objects"); + terrainPanel = new JPanel(new BorderLayout()); + terrainPanel.setBorder(new TitledBorder("Terrain")); + editPanel.add(terrainPanel, "Terrain"); + resourcePanel = new JPanel(new BorderLayout()); + resourcePanel.setBorder(new TitledBorder("Resources")); + editPanel.add(resourcePanel, "Resources"); + + // fiddling with JSplitPanes to get three columns + JSplitPane bigSplitPane = new JSplitPane(); + JSplitPane smallSplitPane = new JSplitPane(); + smallSplitPane.setLeftComponent(mapPanel); + smallSplitPane.setRightComponent(mapTabbedPane); + bigSplitPane.setLeftComponent(smallSplitPane); + bigSplitPane.setRightComponent(editPanel); + + // this could be better + smallSplitPane.setDividerLocation(200); + bigSplitPane.setDividerLocation(1000); + frame.add(bigSplitPane, BorderLayout.CENTER); + + // status bar + status = new StatusBar(); + frame.add(status, BorderLayout.SOUTH); + } + + public void run() { + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private void createMain() { + JFileChooser chooser = new JFileChooser(new File("neon.ini.xml")); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setDialogTitle("Choose module directory"); + if (chooser.showDialog(frame, "Choose") == JFileChooser.APPROVE_OPTION) { + // create mod + createMod(chooser.getSelectedFile()); + // enable editing + enableEditing(true); + frame.pack(); + } + } + + private void createMod(File file) { + // path here is the name of the dir, only files knows the full path + String path = file.getName(); // this also becomes the mod id + try { + files.mount(file.getPath()); + // generate directories + File objects = new File(file, "objects"); + objects.mkdir(); + File maps = new File(file, "maps"); + maps.mkdir(); + File quests = new File(file, "quests"); + quests.mkdir(); + File themes = new File(file, "themes"); + themes.mkdir(); + + // load ensures that all resources etc. are initialized + store.loadData(path, true, false); + mapEditor.loadMaps(resources.getResources(RMap.class), path); + } catch (IOException e) { + JOptionPane.showMessageDialog(frame, "Invalid mod directory: " + file + "."); + } + } + + protected void enableEditing(boolean unpacked) { + // enable menu items + pack.setEnabled(unpacked); + unpack.setEnabled(!unpacked); + make.setEnabled(false); + tools.setEnabled(true); + edit.setEnabled(true); + load.setEnabled(false); + save.setEnabled(true); + + // prepare lists + initObjects(); + initResources(); + initTerrain(); + } + + private void createExtension() { + JFileChooser chooser = new JFileChooser(new File("neon.ini.xml")); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setDialogTitle("Choose master module"); + if (chooser.showDialog(frame, "Master") == JFileChooser.APPROVE_OPTION) { + File master = chooser.getSelectedFile(); + chooser.setDialogTitle("Choose extension directory"); + if (chooser.showDialog(frame, "Extension") == JFileChooser.APPROVE_OPTION) { + // load master + filer.load(master, false); + // create extension + createMod(chooser.getSelectedFile()); + enableEditing(true); + frame.pack(); + } + } + } + + public static void addToolBar(JToolBar bar) { + toolPanel.add(bar); + } + + public static StatusBar getStatusBar() { + return status; + } + + private void initTerrain() { + terrainListModel = new DefaultListModel(); + for (RTerrain rt : resources.getResources(RTerrain.class)) { + terrainListModel.addElement(rt); + } + terrainList = new JList(terrainListModel); + terrainList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + TerrainListener listener = new TerrainListener(mapEditor, terrainList, store); + terrainList.addListSelectionListener(listener); + terrainList.addMouseListener(listener); + terrainPanel.add(new JScrollPane(terrainList)); + } + + private void initResources() { + DefaultMutableTreeNode top = new DefaultMutableTreeNode("Resources"); + + // crafts + ResourceNode craftNode = new ResourceNode("Crafting", ResourceNode.ResourceType.CRAFT, store); + for (RCraft craft : resources.getResources(RCraft.class)) { + craftNode.add(new ResourceNode(craft, ResourceNode.ResourceType.CRAFT, store)); + } + top.add(craftNode); + + // factions + ResourceNode factionNode = + new ResourceNode("Factions", ResourceNode.ResourceType.FACTION, store); + for (RFaction faction : resources.getResources(RFaction.class)) { + factionNode.add(new ResourceNode(faction, ResourceNode.ResourceType.FACTION, store)); + } + top.add(factionNode); + + // region themes + ResourceNode regionNode = + new ResourceNode("Region themes", ResourceNode.ResourceType.REGION, store); + for (RRegionTheme region : resources.getResources(RRegionTheme.class)) { + regionNode.add(new ResourceNode(region, ResourceNode.ResourceType.REGION, store)); + } + top.add(regionNode); + + // zone themes + ResourceNode zoneNode = new ResourceNode("Zone themes", ResourceNode.ResourceType.ZONE, store); + for (RZoneTheme zone : resources.getResources(RZoneTheme.class)) { + zoneNode.add(new ResourceNode(zone, ResourceNode.ResourceType.ZONE, store)); + } + top.add(zoneNode); + + // dungeon themes + ResourceNode dungeonNode = + new ResourceNode("Dungeon themes", ResourceNode.ResourceType.DUNGEON, store); + for (RDungeonTheme dungeon : resources.getResources(RDungeonTheme.class)) { + dungeonNode.add(new ResourceNode(dungeon, ResourceNode.ResourceType.DUNGEON, store)); + } + top.add(dungeonNode); + + // quests + ResourceNode questNode = new ResourceNode("Quests", ResourceNode.ResourceType.QUEST, store); + for (RQuest quest : resources.getResources(RQuest.class)) { + questNode.add(new ResourceNode(quest, ResourceNode.ResourceType.QUEST, store)); + } + top.add(questNode); + + // alchemy + ResourceNode alchemyNode = new ResourceNode("Alchemy", ResourceNode.ResourceType.RECIPE, store); + for (RRecipe rr : resources.getResources(RRecipe.class)) { + alchemyNode.add(new ResourceNode(rr, ResourceNode.ResourceType.RECIPE, store)); + } + top.add(alchemyNode); + + // tattoos + ResourceNode tattooNode = new ResourceNode("Tattoos", ResourceNode.ResourceType.TATTOO, store); + for (RTattoo rt : resources.getResources(RTattoo.class)) { + tattooNode.add(new ResourceNode(rt, ResourceNode.ResourceType.TATTOO, store)); + } + top.add(tattooNode); + + // spells + ResourceNode spellNode = new ResourceNode("Spells", ResourceNode.ResourceType.SPELL, store); + ResourceNode powerNode = new ResourceNode("Powers", ResourceNode.ResourceType.POWER, store); + ResourceNode curseNode = new ResourceNode("Curses", ResourceNode.ResourceType.CURSE, store); + ResourceNode poisonNode = new ResourceNode("Poison", ResourceNode.ResourceType.POISON, store); + ResourceNode enchantNode = + new ResourceNode("Enchantments", ResourceNode.ResourceType.ENCHANTMENT, store); + ResourceNode diseaseNode = + new ResourceNode("Diseases", ResourceNode.ResourceType.DISEASE, store); + ResourceNode levelNode = + new ResourceNode("Leveled spells", ResourceNode.ResourceType.LEVEL_SPELL, store); + for (RSpell rs : resources.getResources(RSpell.class)) { + if (rs instanceof LSpell) { + levelNode.add(new ResourceNode(rs, ResourceNode.ResourceType.LEVEL_SPELL, store)); + } else { + switch (rs.type) { + case CURSE: + curseNode.add(new ResourceNode(rs, ResourceNode.ResourceType.CURSE, store)); + break; + case DISEASE: + diseaseNode.add(new ResourceNode(rs, ResourceNode.ResourceType.DISEASE, store)); + break; + case ENCHANT: + enchantNode.add(new ResourceNode(rs, ResourceNode.ResourceType.ENCHANTMENT, store)); + break; + case POISON: + poisonNode.add(new ResourceNode(rs, ResourceNode.ResourceType.POISON, store)); + break; + case POWER: + powerNode.add(new ResourceNode(rs, ResourceNode.ResourceType.POWER, store)); + break; + case SPELL: + spellNode.add(new ResourceNode(rs, ResourceNode.ResourceType.SPELL, store)); + break; + } + } + } + top.add(spellNode); + top.add(powerNode); + top.add(curseNode); + top.add(poisonNode); + top.add(enchantNode); + top.add(diseaseNode); + top.add(levelNode); + + // signs + ResourceNode signNode = new ResourceNode("Birth signs", ResourceNode.ResourceType.SIGN, store); + for (RSign rs : resources.getResources(RSign.class)) { + signNode.add(new ResourceNode(rs, ResourceNode.ResourceType.SIGN, store)); + } + top.add(signNode); + + resourceTree.setModel(new DefaultTreeModel(top)); + resourceTree.addMouseListener(new ResourceTreeListener(resourceTree, frame, store)); + resourcePanel.add(new JScrollPane(resourceTree)); + } + + private void initObjects() { + DefaultMutableTreeNode top = new DefaultMutableTreeNode("Objects"); + + // creatures; + ObjectNode creatureNode = new ObjectNode("Creatures", ObjectNode.ObjectType.CREATURE, store); + ObjectNode levelCreatureNode = + new ObjectNode("Leveled creatures", ObjectNode.ObjectType.LEVEL_CREATURE, store); + for (RCreature rc : resources.getResources(RCreature.class)) { + if (rc instanceof LCreature) { + levelCreatureNode.add(new ObjectNode(rc, ObjectNode.ObjectType.LEVEL_CREATURE, store)); + } else { + creatureNode.add(new ObjectNode(rc, ObjectNode.ObjectType.CREATURE, store)); + } + } + top.add(creatureNode); + top.add(levelCreatureNode); + + // NPCs + ObjectNode npcNode = new ObjectNode("NPCs", ObjectNode.ObjectType.NPC, store); + for (RPerson rp : resources.getResources(RPerson.class)) { + npcNode.add(new ObjectNode(rp, ObjectNode.ObjectType.NPC, store)); + } + top.add(npcNode); + + // items + ObjectNode itemNode = new ObjectNode("Items", ObjectNode.ObjectType.ITEM, store); + ObjectNode weaponNode = new ObjectNode("Weapons", ObjectNode.ObjectType.WEAPON, store); + ObjectNode clothingNode = new ObjectNode("Clothing", ObjectNode.ObjectType.CLOTHING, store); + ObjectNode armorNode = new ObjectNode("Armor", ObjectNode.ObjectType.ARMOR, store); + ObjectNode lightNode = new ObjectNode("Light", ObjectNode.ObjectType.LIGHT, store); + ObjectNode doorNode = new ObjectNode("Doors", ObjectNode.ObjectType.DOOR, store); + ObjectNode containerNode = new ObjectNode("Containers", ObjectNode.ObjectType.CONTAINER, store); + ObjectNode potionNode = new ObjectNode("Potions", ObjectNode.ObjectType.POTION, store); + ObjectNode scrollNode = new ObjectNode("Scrolls", ObjectNode.ObjectType.SCROLL, store); + ObjectNode bookNode = new ObjectNode("Books", ObjectNode.ObjectType.BOOK, store); + ObjectNode coinNode = new ObjectNode("Money", ObjectNode.ObjectType.MONEY, store); + ObjectNode foodNode = new ObjectNode("Food", ObjectNode.ObjectType.FOOD, store); + ObjectNode levelItemNode = + new ObjectNode("Leveled items", ObjectNode.ObjectType.LEVEL_ITEM, store); + for (RItem ri : resources.getResources(RItem.class)) { + if (ri instanceof LItem) { + levelItemNode.add(new ObjectNode(ri, ObjectNode.ObjectType.LEVEL_ITEM, store)); + } else { + switch (ri.type) { + case armor: + armorNode.add(new ObjectNode(ri, ObjectNode.ObjectType.ARMOR, store)); + break; + case book: + bookNode.add(new ObjectNode(ri, ObjectNode.ObjectType.BOOK, store)); + break; + case clothing: + clothingNode.add(new ObjectNode(ri, ObjectNode.ObjectType.CLOTHING, store)); + break; + case coin: + coinNode.add(new ObjectNode(ri, ObjectNode.ObjectType.MONEY, store)); + break; + case container: + containerNode.add(new ObjectNode(ri, ObjectNode.ObjectType.CONTAINER, store)); + break; + case door: + doorNode.add(new ObjectNode(ri, ObjectNode.ObjectType.DOOR, store)); + break; + case food: + foodNode.add(new ObjectNode(ri, ObjectNode.ObjectType.FOOD, store)); + break; + case light: + lightNode.add(new ObjectNode(ri, ObjectNode.ObjectType.LIGHT, store)); + break; + case potion: + potionNode.add(new ObjectNode(ri, ObjectNode.ObjectType.POTION, store)); + break; + case scroll: + scrollNode.add(new ObjectNode(ri, ObjectNode.ObjectType.SCROLL, store)); + break; + case weapon: + weaponNode.add(new ObjectNode(ri, ObjectNode.ObjectType.WEAPON, store)); + break; + default: + itemNode.add(new ObjectNode(ri, ObjectNode.ObjectType.ITEM, store)); + } + } + } + top.add(itemNode); + top.add(weaponNode); + top.add(clothingNode); + top.add(armorNode); + top.add(lightNode); + top.add(doorNode); + top.add(containerNode); + top.add(potionNode); + top.add(scrollNode); + top.add(bookNode); + top.add(coinNode); + top.add(foodNode); + top.add(levelItemNode); + + objectTree.setModel(new DefaultTreeModel(top)); + objectTree.addMouseListener(new ObjectTreeListener(objectTree, frame, store)); + objectPanel.add(new JScrollPane(objectTree)); + objectTree.setDragEnabled(true); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("save")) { + filer.save(); + } else if (e.getActionCommand().equals("load")) { + filer.loadMod(); + } else if (e.getActionCommand().equals("quit")) { + System.exit(0); + } else if (e.getActionCommand().equals("newMain")) { + createMain(); + } else if (e.getActionCommand().equals("newExt")) { + createExtension(); + } else if (e.getActionCommand().equals("script")) { + if (scriptEditor == null) { + scriptEditor = new ScriptEditor(frame, store); + } + scriptEditor.show(); + } else if (e.getActionCommand().equals("cc")) { + if (ccEditor == null) { + ccEditor = new CCEditor(frame, store); + } + ccEditor.show(); + } else if (e.getActionCommand().equals("game")) { + if (infoEditor == null) { + infoEditor = new InfoEditor(frame, store); + } + infoEditor.show(); + } else if (e.getActionCommand().equals("events")) { + if (eventEditor == null) { + eventEditor = new EventEditor(frame, store); + } + eventEditor.show(); + } else if (e.getActionCommand().equals("pack")) { + if (JOptionPane.showConfirmDialog( + frame, + "Do you wish to save the current data and pack it?", + "Pack mod", + JOptionPane.YES_NO_OPTION) + == 0) { + pack(); + } + } else if (e.getActionCommand().equals("unpack")) { + unpack(); + } else if (e.getActionCommand().equals("svg")) { + if ((EditablePane) mapTabbedPane.getSelectedComponent() != null) { + ZoneTreeNode node = ((EditablePane) mapTabbedPane.getSelectedComponent()).getNode(); + SVGExporter.exportToSVG(node, files, store); + } + } else if (e.getActionCommand().equals("calculate")) { + new ChallengeCalculator().show(); + } else if (e.getActionCommand().equals("scripting")) { + showHelp("scripting.html", "Scripting guide"); + } else if (e.getActionCommand().equals("intro")) { + showHelp("intro.html", "Getting started"); + } else if (e.getActionCommand().equals("mapping")) { + showHelp("maps.html", "Map editing"); + } else if (e.getActionCommand().equals("resources")) { + showHelp("resources.html", "Resource editing"); + } + } + + private void showHelp(String file, String title) { + InputStream input = HelpLabels.class.getResourceAsStream(file); + Scanner scanner = new Scanner(input, "UTF-8"); + String text = scanner.useDelimiter("\\A").next(); + scanner.close(); + new HelpWindow(frame).show(title, text); + } + + private void pack() { + filer.save(); + try { + JarFile jar = FileUtils.pack(store.getActive().getPath()[0], store.getActive().get("id")); + System.out.println("attributes: " + jar.getManifest().getMainAttributes()); + } catch (IOException e) { + JOptionPane.showMessageDialog(frame, "Packing failed"); + } + } + + private void unpack() { + FileUtils.unpack(store.getActive().getPath()[0]); + JOptionPane.showMessageDialog( + frame, + "Please restart the editor and load the unpacked mod.", + "Unpack mod", + JOptionPane.INFORMATION_MESSAGE); + } +} diff --git a/src/main/java/neon/editor/EventEditor.java b/src/main/java/neon/editor/EventEditor.java index 4842b49..89f156f 100644 --- a/src/main/java/neon/editor/EventEditor.java +++ b/src/main/java/neon/editor/EventEditor.java @@ -1,196 +1,198 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor; - -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Multimap; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; - -public class EventEditor implements ListSelectionListener, ActionListener, MouseListener { - private JDialog frame; - private Multimap events; - private JList times; - private JList list; - private DefaultListModel model; - private DefaultListModel stampModel; - private String[] scripts; - - public EventEditor(JFrame parent) { - frame = new JDialog(parent, "Event Editor"); - frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame.setPreferredSize(new Dimension(480, 300)); - - model = new DefaultListModel(); - list = new JList(model); - list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - list.addMouseListener(this); - list.addListSelectionListener(this); - JScrollPane listScroller = new JScrollPane(list); - listScroller.setBorder(new TitledBorder("Events")); - - stampModel = new DefaultListModel(); - times = new JList(stampModel); - times.addMouseListener(this); - JScrollPane textScroller = new JScrollPane(times); - textScroller.setBorder(new TitledBorder("Timestamps")); - - JPanel content = new JPanel(new BorderLayout()); - content.add(listScroller, BorderLayout.LINE_START); - content.add(textScroller, BorderLayout.CENTER); - frame.setContentPane(content); - - JPanel buttons = new JPanel(); - content.add(buttons, BorderLayout.PAGE_END); - JButton ok = new JButton("Ok"); - ok.addActionListener(this); - JButton cancel = new JButton("Cancel"); - cancel.addActionListener(this); - JButton apply = new JButton("Apply"); - apply.addActionListener(this); - buttons.add(ok); - buttons.add(cancel); - buttons.add(apply); - } - - public void show() { - model.clear(); - scripts = Editor.getStore().getScripts().keySet().toArray(new String[0]); - events = ArrayListMultimap.create(); - for (String event : Editor.getStore().getEvents().keySet()) { - events.putAll(event, Editor.getStore().getEvents().get(event)); - model.addElement(event); - } - frame.pack(); - frame.setLocationRelativeTo(null); - frame.setVisible(true); - } - - public void valueChanged(ListSelectionEvent e) { - // blijkbaar worden er twee events gefired bij selectie - if (e.getValueIsAdjusting()) { - stampModel.clear(); - for (String s : events.get(list.getSelectedValue().toString())) { - stampModel.addElement(s); - } - } - } - - private void save() { - Editor.getStore().getEvents().clear(); - for (String event : events.keySet()) { - Editor.getStore().getEvents().putAll(event, events.get(event)); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Cancel")) { - frame.dispose(); - } else if (e.getActionCommand().equals("Apply")) { - save(); - } else if (e.getActionCommand().equals("Ok")) { - save(); - frame.dispose(); - } - } - - public void mousePressed(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseExited(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - if (e.getSource().equals(list)) { - JPopupMenu menu = new JPopupMenu(); - menu.add(new ClickAction("Add event")); - menu.add(new ClickAction("Remove event")); - menu.show(e.getComponent(), e.getX(), e.getY()); - list.setSelectedIndex(list.locationToIndex(new Point(e.getX(), e.getY()))); - } else if (e.getSource().equals(times)) { - JPopupMenu menu = new JPopupMenu(); - menu.add(new ClickAction("Add timestamp")); - menu.add(new ClickAction("Remove timestamp")); - menu.show(e.getComponent(), e.getX(), e.getY()); - times.setSelectedIndex(times.locationToIndex(new Point(e.getX(), e.getY()))); - } - } - } - - @SuppressWarnings("serial") - public class ClickAction extends AbstractAction { - public ClickAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add event")) { - String s = - (String) - JOptionPane.showInputDialog( - frame, - "Select event:", - "New event", - JOptionPane.PLAIN_MESSAGE, - null, - scripts, - 0); - if ((s != null) && (s.length() > 0)) { - model.addElement(s); - events.put(s, ""); - list.setSelectedValue(s, true); - } - } else if (e.getActionCommand().equals("Remove event")) { - try { - if (list.getSelectedIndex() >= 0) { - int index = list.getSelectedIndex(); - events.removeAll(list.getSelectedValue().toString()); - model.remove(index); - } - } catch (ArrayIndexOutOfBoundsException a) { - } - } else if (e.getActionCommand().equals("Add timestamp")) { - String s = - (String) - JOptionPane.showInputDialog( - frame, "Timestamp:", "Add timestamp", JOptionPane.QUESTION_MESSAGE); - if (s.matches("\\d*:?\\d*:?\\d*")) { // X:Y:Z - stampModel.addElement(s); - events.put(list.getSelectedValue().toString(), s); - times.setSelectedValue(s, true); - } - } else if (e.getActionCommand().equals("Remove timestamp")) { - try { - if (times.getSelectedIndex() >= 0) { - int index = times.getSelectedIndex(); - events.remove(list.getSelectedValue().toString(), times.getSelectedValue().toString()); - stampModel.remove(index); - } - } catch (ArrayIndexOutOfBoundsException a) { - } - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; + +public class EventEditor implements ListSelectionListener, ActionListener, MouseListener { + private JDialog frame; + private final DataStore dataStore; + private Multimap events; + private JList times; + private JList list; + private DefaultListModel model; + private DefaultListModel stampModel; + private String[] scripts; + + public EventEditor(JFrame parent, DataStore dataStore) { + frame = new JDialog(parent, "Event Editor"); + this.dataStore = dataStore; + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setPreferredSize(new Dimension(480, 300)); + + model = new DefaultListModel(); + list = new JList(model); + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + list.addMouseListener(this); + list.addListSelectionListener(this); + JScrollPane listScroller = new JScrollPane(list); + listScroller.setBorder(new TitledBorder("Events")); + + stampModel = new DefaultListModel(); + times = new JList(stampModel); + times.addMouseListener(this); + JScrollPane textScroller = new JScrollPane(times); + textScroller.setBorder(new TitledBorder("Timestamps")); + + JPanel content = new JPanel(new BorderLayout()); + content.add(listScroller, BorderLayout.LINE_START); + content.add(textScroller, BorderLayout.CENTER); + frame.setContentPane(content); + + JPanel buttons = new JPanel(); + content.add(buttons, BorderLayout.PAGE_END); + JButton ok = new JButton("Ok"); + ok.addActionListener(this); + JButton cancel = new JButton("Cancel"); + cancel.addActionListener(this); + JButton apply = new JButton("Apply"); + apply.addActionListener(this); + buttons.add(ok); + buttons.add(cancel); + buttons.add(apply); + } + + public void show() { + model.clear(); + scripts = dataStore.getScripts().keySet().toArray(new String[0]); + events = ArrayListMultimap.create(); + for (String event : dataStore.getEvents().keySet()) { + events.putAll(event, dataStore.getEvents().get(event)); + model.addElement(event); + } + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public void valueChanged(ListSelectionEvent e) { + // blijkbaar worden er twee events gefired bij selectie + if (e.getValueIsAdjusting()) { + stampModel.clear(); + for (String s : events.get(list.getSelectedValue().toString())) { + stampModel.addElement(s); + } + } + } + + private void save() { + dataStore.getEvents().clear(); + for (String event : events.keySet()) { + dataStore.getEvents().putAll(event, events.get(event)); + } + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Cancel")) { + frame.dispose(); + } else if (e.getActionCommand().equals("Apply")) { + save(); + } else if (e.getActionCommand().equals("Ok")) { + save(); + frame.dispose(); + } + } + + public void mousePressed(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseExited(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + if (e.getSource().equals(list)) { + JPopupMenu menu = new JPopupMenu(); + menu.add(new ClickAction("Add event")); + menu.add(new ClickAction("Remove event")); + menu.show(e.getComponent(), e.getX(), e.getY()); + list.setSelectedIndex(list.locationToIndex(new Point(e.getX(), e.getY()))); + } else if (e.getSource().equals(times)) { + JPopupMenu menu = new JPopupMenu(); + menu.add(new ClickAction("Add timestamp")); + menu.add(new ClickAction("Remove timestamp")); + menu.show(e.getComponent(), e.getX(), e.getY()); + times.setSelectedIndex(times.locationToIndex(new Point(e.getX(), e.getY()))); + } + } + } + + @SuppressWarnings("serial") + public class ClickAction extends AbstractAction { + public ClickAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add event")) { + String s = + (String) + JOptionPane.showInputDialog( + frame, + "Select event:", + "New event", + JOptionPane.PLAIN_MESSAGE, + null, + scripts, + 0); + if ((s != null) && (s.length() > 0)) { + model.addElement(s); + events.put(s, ""); + list.setSelectedValue(s, true); + } + } else if (e.getActionCommand().equals("Remove event")) { + try { + if (list.getSelectedIndex() >= 0) { + int index = list.getSelectedIndex(); + events.removeAll(list.getSelectedValue().toString()); + model.remove(index); + } + } catch (ArrayIndexOutOfBoundsException a) { + } + } else if (e.getActionCommand().equals("Add timestamp")) { + String s = + (String) + JOptionPane.showInputDialog( + frame, "Timestamp:", "Add timestamp", JOptionPane.QUESTION_MESSAGE); + if (s.matches("\\d*:?\\d*:?\\d*")) { // X:Y:Z + stampModel.addElement(s); + events.put(list.getSelectedValue().toString(), s); + times.setSelectedValue(s, true); + } + } else if (e.getActionCommand().equals("Remove timestamp")) { + try { + if (times.getSelectedIndex() >= 0) { + int index = times.getSelectedIndex(); + events.remove(list.getSelectedValue().toString(), times.getSelectedValue().toString()); + stampModel.remove(index); + } + } catch (ArrayIndexOutOfBoundsException a) { + } + } + } + } +} diff --git a/src/main/java/neon/editor/InfoEditor.java b/src/main/java/neon/editor/InfoEditor.java index 6537e2c..efa8ee4 100644 --- a/src/main/java/neon/editor/InfoEditor.java +++ b/src/main/java/neon/editor/InfoEditor.java @@ -26,11 +26,15 @@ import neon.resources.RMod; public class InfoEditor implements ActionListener { - private JDialog frame; - private JTextField titleField, bigField, smallField; + private final JDialog frame; + private final JTextField titleField; + private final JTextField bigField; + private final JTextField smallField; + private final DataStore dataStore; - public InfoEditor(JFrame parent) { + public InfoEditor(JFrame parent, DataStore dataStore) { frame = new JDialog(parent, "Game Info Editor"); + this.dataStore = dataStore; JPanel content = new JPanel(); content.setLayout(new BoxLayout(content, BoxLayout.PAGE_AXIS)); frame.setContentPane(content); @@ -117,7 +121,7 @@ public InfoEditor(JFrame parent) { public void show() { // assume that data is always valid... - RMod data = Editor.getStore().getActive(); + RMod data = dataStore.getActive(); titleField.setText(data.get("title")); if (data.get("big") != null) { bigField.setText(data.get("big")); @@ -131,7 +135,7 @@ public void show() { } private void save() { - RMod data = Editor.getStore().getActive(); + RMod data = dataStore.getActive(); // big may not be the same as small if (!bigField.getText().equals(smallField.getText())) { // big not null or "€" @@ -144,7 +148,7 @@ private void save() { } } // title not null or "", unless for extension - if (!Editor.getStore().getActive().isExtension() + if (!dataStore.getActive().isExtension() || !(titleField.getText() == null && titleField.getText().isEmpty())) { data.set("title", titleField.getText()); } diff --git a/src/main/java/neon/editor/ModCellRenderer.java b/src/main/java/neon/editor/ModCellRenderer.java index 0532bf1..e4cf49e 100644 --- a/src/main/java/neon/editor/ModCellRenderer.java +++ b/src/main/java/neon/editor/ModCellRenderer.java @@ -27,6 +27,12 @@ @SuppressWarnings("serial") public class ModCellRenderer extends JLabel implements ListCellRenderer { + private final DataStore dataStore; + + public ModCellRenderer(DataStore dataStore) { + this.dataStore = dataStore; + } + /** * Returns this renderer with the right properties (color, font, background color). If the cell * does not contain a resource from the currently active mod, the text is rendered in italics. @@ -46,7 +52,7 @@ public Component getListCellRendererComponent( boolean cellHasFocus) { setOpaque(true); String text = value.toString(); - if (value.getPath()[0].equals(Editor.getStore().getActive().get("id"))) { + if (value.getPath()[0].equals(dataStore.getActive().get("id"))) { setText(text); } else { setText("" + text + ""); diff --git a/src/main/java/neon/editor/ModFiler.java b/src/main/java/neon/editor/ModFiler.java index e99ee1e..88da14a 100644 --- a/src/main/java/neon/editor/ModFiler.java +++ b/src/main/java/neon/editor/ModFiler.java @@ -53,15 +53,15 @@ import org.jdom2.input.SAXBuilder; public class ModFiler { - private FileSystem files; - private DataStore store; - private Editor editor; - private JFrame frame; + private final FileSystem files; + private final DataStore dataStore; + private final Editor editor; + private final JFrame frame; - public ModFiler(JFrame frame, FileSystem files, DataStore store, Editor editor) { + public ModFiler(JFrame frame, FileSystem files, DataStore dataStore, Editor editor) { this.frame = frame; this.files = files; - this.store = store; + this.dataStore = dataStore; this.editor = editor; } @@ -102,7 +102,7 @@ void load(File file, boolean active) { files.mount(mod.getText()); Document d = files.getFile(new XMLTranslator(), mod.getText(), "main.xml"); if (d.getRootElement().getAttributeValue("id").equals(id)) { - store.loadData(mod.getText(), false, false); + dataStore.loadData(mod.getText(), false, false); } else { files.removePath(mod.getText()); } @@ -112,8 +112,8 @@ void load(File file, boolean active) { } frame.setTitle("Neon Editor: " + path); - store.loadData(path, active, isExtension(path)); - editor.mapEditor.loadMaps(Editor.resources.getResources(RMap.class), path); + dataStore.loadData(path, active, isExtension(path)); + editor.mapEditor.loadMaps(dataStore.getResourceManager().getResources(RMap.class), path); editor.enableEditing(file.isDirectory()); frame.pack(); } @@ -123,56 +123,69 @@ void load(File file, boolean active) { } public void save() { - JacksonXmlBuilder builder = new JacksonXmlBuilder(store); - RMod active = store.getActive(); - saveFile(new Document(store.getActive().getMainElement()), "main.xml"); - saveFile(new Document(store.getActive().getCCElement()), "cc.xml"); + JacksonXmlBuilder builder = new JacksonXmlBuilder(dataStore); + RMod active = dataStore.getActive(); + saveFile(new Document(dataStore.getActive().getMainElement()), "main.xml"); + saveFile(new Document(dataStore.getActive().getCCElement()), "cc.xml"); saveFile( - builder.getResourceDoc(Editor.resources.getResources(RItem.class), "items", active), + builder.getResourceDoc( + dataStore.getResourceManager().getResources(RItem.class), "items", active), "objects", "items.xml"); saveFile( - builder.getListDoc(Editor.resources.getResources(RFaction.class), "factions", active), + builder.getListDoc( + dataStore.getResourceManager().getResources(RFaction.class), "factions", active), "factions.xml"); saveFile( - builder.getListDoc(Editor.resources.getResources(RRecipe.class), "recipes", active), + builder.getListDoc( + dataStore.getResourceManager().getResources(RRecipe.class), "recipes", active), "objects", "alchemy.xml"); saveFile(builder.getEventsDoc(), "events.xml"); saveFile( - builder.getListDoc(Editor.resources.getResources(RPerson.class), "people", active), + builder.getListDoc( + dataStore.getResourceManager().getResources(RPerson.class), "people", active), "objects", "npc.xml"); saveFile( - builder.getResourceDoc(Editor.resources.getResources(RCreature.class), "monsters", active), + builder.getResourceDoc( + dataStore.getResourceManager().getResources(RCreature.class), "monsters", active), "objects", "monsters.xml"); saveFile( - builder.getResourceDoc(Editor.resources.getResources(RSpell.class), "spells", active), + builder.getResourceDoc( + dataStore.getResourceManager().getResources(RSpell.class), "spells", active), "spells.xml"); saveFile( - builder.getListDoc(Editor.resources.getResources(RTerrain.class), "terrain", active), + builder.getListDoc( + dataStore.getResourceManager().getResources(RTerrain.class), "terrain", active), "terrain.xml"); saveFile( - builder.getListDoc(Editor.resources.getResources(RCraft.class), "items", active), + builder.getListDoc( + dataStore.getResourceManager().getResources(RCraft.class), "items", active), "objects", "crafting.xml"); saveFile( - builder.getListDoc(Editor.resources.getResources(RSign.class), "signs", active), + builder.getListDoc( + dataStore.getResourceManager().getResources(RSign.class), "signs", active), "signs.xml"); saveFile( - builder.getListDoc(Editor.resources.getResources(RTattoo.class), "tattoos", active), + builder.getListDoc( + dataStore.getResourceManager().getResources(RTattoo.class), "tattoos", active), "tattoos.xml"); saveFile( - builder.getListDoc(Editor.resources.getResources(RZoneTheme.class), "themes", active), + builder.getListDoc( + dataStore.getResourceManager().getResources(RZoneTheme.class), "themes", active), "themes", "zones.xml"); saveFile( - builder.getListDoc(Editor.resources.getResources(RDungeonTheme.class), "themes", active), + builder.getListDoc( + dataStore.getResourceManager().getResources(RDungeonTheme.class), "themes", active), "themes", "dungeons.xml"); saveFile( - builder.getListDoc(Editor.resources.getResources(RRegionTheme.class), "themes", active), + builder.getListDoc( + dataStore.getResourceManager().getResources(RRegionTheme.class), "themes", active), "themes", "regions.xml"); saveMaps(); @@ -189,10 +202,10 @@ public void save() { */ private void saveMaps() { // Delete maps that no longer exist - for (String name : files.listFiles(store.getActive().getPath()[0], "maps")) { + for (String name : files.listFiles(dataStore.getActive().getPath()[0], "maps")) { String map = name.substring(name.lastIndexOf(File.separator) + 1, name.length() - 4); // -4 for ".xml" - if (Editor.resources.getResource(map, "maps") == null) { + if (dataStore.getResourceManager().getResource(map, "maps") == null) { files.delete(name); } } @@ -220,27 +233,27 @@ private void saveMaps() { } private void saveQuests() { - for (String name : files.listFiles(store.getActive().getPath()[0], "quests")) { + for (String name : files.listFiles(dataStore.getActive().getPath()[0], "quests")) { String quest = name.substring(name.lastIndexOf(File.separator) + 1, name.length() - 4); // -4 for ".xml" - if (Editor.resources.getResource(quest, "quest") == null) { + if (dataStore.getResourceManager().getResource(quest, "quest") == null) { files.delete(name); } } - for (RQuest quest : Editor.resources.getResources(RQuest.class)) { + for (RQuest quest : dataStore.getResourceManager().getResources(RQuest.class)) { saveFile(new Document(quest.toElement()), "quests", quest.id + ".xml"); } } private void saveScripts() { - for (String name : files.listFiles(store.getActive().getPath()[0], "scripts")) { + for (String name : files.listFiles(dataStore.getActive().getPath()[0], "scripts")) { String script = name.substring(name.lastIndexOf(File.separator) + 1, name.length() - 3); // -3 for ".js" - if (!store.getScripts().containsKey(script)) { + if (!dataStore.getScripts().containsKey(script)) { files.delete(name); } } - for (RScript script : store.getScripts().values()) { + for (RScript script : dataStore.getScripts().values()) { saveFile(script.script, "scripts", script.id + ".js"); } } @@ -248,14 +261,14 @@ private void saveScripts() { private void saveFile(String text, String... file) { String[] fullPath = new String[file.length + 1]; System.arraycopy(file, 0, fullPath, 1, file.length); - fullPath[0] = store.getActive().getPath()[0]; + fullPath[0] = dataStore.getActive().getPath()[0]; files.saveFile(text, new StringTranslator(), fullPath); } private void saveFile(Document doc, String... file) { String[] fullPath = new String[file.length + 1]; System.arraycopy(file, 0, fullPath, 1, file.length); - fullPath[0] = store.getActive().getPath()[0]; + fullPath[0] = dataStore.getActive().getPath()[0]; files.saveFile(doc, new XMLTranslator(), fullPath); } diff --git a/src/main/java/neon/editor/NewObjectDialog.java b/src/main/java/neon/editor/NewObjectDialog.java index 8325a4c..d0be5d0 100644 --- a/src/main/java/neon/editor/NewObjectDialog.java +++ b/src/main/java/neon/editor/NewObjectDialog.java @@ -28,6 +28,11 @@ public class NewObjectDialog implements ActionListener { private JDialog dialog; private boolean cancelled; private String namespace = null; + private final DataStore dataStore; + + public NewObjectDialog(DataStore dataStore) { + this.dataStore = dataStore; + } public Properties showInputDialog(JFrame frame, String message, String namespace) { this.namespace = namespace; @@ -81,9 +86,9 @@ public void actionPerformed(ActionEvent e) { public boolean exists(String id) { if (namespace == null) { - return Editor.resources.getResource(id) != null; + return dataStore.getResourceManager().getResource(id) != null; } else { - return Editor.resources.getResource(id, namespace) != null; + return dataStore.getResourceManager().getResource(id, namespace) != null; } } diff --git a/src/main/java/neon/editor/ObjectNode.java b/src/main/java/neon/editor/ObjectNode.java index 034233b..13860b5 100644 --- a/src/main/java/neon/editor/ObjectNode.java +++ b/src/main/java/neon/editor/ObjectNode.java @@ -24,31 +24,27 @@ import java.util.Vector; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.MutableTreeNode; +import lombok.Getter; import neon.resources.RData; @SuppressWarnings("serial") public class ObjectNode extends DefaultMutableTreeNode { private static NodeComparator nodeComparator = new NodeComparator(); - private RData resource; - private ObjectType type; + @Getter private RData resource; + @Getter private ObjectType type; private String name; + private final DataStore dataStore; - public ObjectNode(RData r, ObjectType t) { + public ObjectNode(RData r, ObjectType t, DataStore dataStore) { resource = r; type = t; + this.dataStore = dataStore; } - public ObjectNode(String name, ObjectType t) { + public ObjectNode(String name, ObjectType t, DataStore dataStore) { this.name = name; type = t; - } - - public RData getResource() { - return resource; - } - - public ObjectType getType() { - return type; + this.dataStore = dataStore; } public String toString() { @@ -57,7 +53,7 @@ public String toString() { } String id = resource.id; // leaf node - if (!resource.getPath()[0].equals(Editor.getStore().getActive().get("id"))) { + if (!resource.getPath()[0].equals(dataStore.getActive().get("id"))) { // niet-actieve data is cursief weergegeven return "" + id + ""; } else { diff --git a/src/main/java/neon/editor/ObjectTransferHandler.java b/src/main/java/neon/editor/ObjectTransferHandler.java index 5f5177b..7988423 100644 --- a/src/main/java/neon/editor/ObjectTransferHandler.java +++ b/src/main/java/neon/editor/ObjectTransferHandler.java @@ -32,12 +32,14 @@ @SuppressWarnings("serial") public class ObjectTransferHandler extends TransferHandler { - private RZone zone; - private EditablePane pane; + private final RZone zone; + private final EditablePane pane; + private final DataStore dataStore; public ObjectTransferHandler(RZone zone, EditablePane pane) { this.zone = zone; this.pane = pane; + this.dataStore = zone.getDataStore(); } public boolean canImport(TransferHandler.TransferSupport ts) { @@ -49,9 +51,9 @@ public boolean importData(TransferHandler.TransferSupport ts) { String id = ts.getTransferable().getTransferData(DataFlavor.stringFlavor).toString(); String type = "item"; - if (Editor.resources.getResource(id) instanceof RItem) { + if (dataStore.getResourceManager().getResource(id) instanceof RItem) { System.out.println(id); - RItem item = (RItem) Editor.resources.getResource(id); + RItem item = (RItem) dataStore.getResourceManager().getResource(id); if (item instanceof RItem.Door) { type = "door"; } else if (item.type == Type.container) { @@ -73,7 +75,7 @@ public boolean importData(TransferHandler.TransferSupport ts) { e.setAttribute("id", id); e.setAttribute("uid", Integer.toString(zone.map.createUID(e))); - Instance instance = RZone.getInstance(e, zone); + Instance instance = zone.getInstance(e, zone); zone.getScene().addElement(instance, instance.getBounds(), instance.z); UndoAction undo = new UndoAction.Drop(instance, zone.getScene()); diff --git a/src/main/java/neon/editor/ObjectTreeListener.java b/src/main/java/neon/editor/ObjectTreeListener.java index c62f14c..a6bc806 100644 --- a/src/main/java/neon/editor/ObjectTreeListener.java +++ b/src/main/java/neon/editor/ObjectTreeListener.java @@ -1,240 +1,242 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor; - -import java.awt.event.*; -import javax.swing.*; -import javax.swing.tree.*; -import neon.editor.editors.ArmorEditor; -import neon.editor.editors.BookEditor; -import neon.editor.editors.ClothingEditor; -import neon.editor.editors.ContainerEditor; -import neon.editor.editors.CreatureEditor; -import neon.editor.editors.DoorEditor; -import neon.editor.editors.FoodEditor; -import neon.editor.editors.ItemEditor; -import neon.editor.editors.LevelCreatureEditor; -import neon.editor.editors.LevelItemEditor; -import neon.editor.editors.LightEditor; -import neon.editor.editors.MoneyEditor; -import neon.editor.editors.NPCEditor; -import neon.editor.editors.ObjectEditor; -import neon.editor.editors.PotionEditor; -import neon.editor.editors.ScrollEditor; -import neon.editor.editors.WeaponEditor; -import neon.resources.*; -import neon.resources.RItem.Type; - -public class ObjectTreeListener implements MouseListener { - private JTree tree; - private JFrame frame; - private DefaultTreeModel model; - - public ObjectTreeListener(JTree objectTree, JFrame frame) { - this.frame = frame; - tree = objectTree; - model = (DefaultTreeModel) tree.getModel(); - } - - public void mouseExited(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mousePressed(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON1) { - if (e.getClickCount() == 2) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); - if (tree.getSelectionPath() != null && node.getLevel() == 2) { - launchEditor((ObjectNode) node); - } - } - } - } - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - JPopupMenu menu = new JPopupMenu(); - tree.setSelectionRow(tree.getRowForLocation(e.getX(), e.getY())); - ObjectNode node = (ObjectNode) tree.getLastSelectedPathComponent(); - if (tree.getSelectionPath() != null && node.getLevel() == 2) { - menu.add(new ClickAction("Delete object", node.getType())); - menu.add(new ClickAction("Edit object", node.getType())); - menu.add(new ClickAction("New " + node.getType().toString().toLowerCase(), node.getType())); - menu.show(e.getComponent(), e.getX(), e.getY()); - } else if (tree.getSelectionPath() != null && node.getLevel() == 1) { - menu.add(new ClickAction("New " + node.getType().toString().toLowerCase(), node.getType())); - menu.show(e.getComponent(), e.getX(), e.getY()); - } - } - } - - private void launchEditor(ObjectNode node) { - ObjectEditor editor; - switch (node.getType()) { - case LEVEL_CREATURE: - editor = new LevelCreatureEditor(frame, (LCreature) node.getResource()); - break; - case BOOK: - editor = new BookEditor(frame, (RItem.Text) node.getResource()); - break; - case ARMOR: - editor = new ArmorEditor(frame, (RClothing) node.getResource()); - break; - case CLOTHING: - editor = new ClothingEditor(frame, (RClothing) node.getResource()); - break; - case CONTAINER: - editor = new ContainerEditor(frame, (RItem.Container) node.getResource()); - break; - case DOOR: - editor = new DoorEditor(frame, (RItem.Door) node.getResource()); - break; - case ITEM: - editor = new ItemEditor(frame, (RItem) node.getResource()); - break; - case LIGHT: - editor = new LightEditor(frame, (RItem) node.getResource()); - break; - case MONEY: - editor = new MoneyEditor(frame, (RItem) node.getResource()); - break; - case NPC: - editor = new NPCEditor(frame, (RPerson) node.getResource()); - break; - case POTION: - editor = new PotionEditor(frame, (RItem) node.getResource()); - break; - case SCROLL: - editor = new ScrollEditor(frame, (RItem.Text) node.getResource()); - break; - case LEVEL_ITEM: - editor = new LevelItemEditor(frame, (LItem) node.getResource()); - break; - case WEAPON: - editor = new WeaponEditor(frame, (RWeapon) node.getResource()); - break; - case FOOD: - editor = new FoodEditor(frame, (RItem) node.getResource()); - break; - default: - editor = new CreatureEditor(frame, (RCreature) node.getResource()); - break; - } - editor.show(); - } - - @SuppressWarnings("serial") - public class ClickAction extends AbstractAction { - private ObjectNode.ObjectType type; - - public ClickAction(String name, ObjectNode.ObjectType type) { - super(name); - this.type = type; - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("New " + type.toString().toLowerCase())) { - NewObjectDialog.Properties props = - new NewObjectDialog() - .showInputDialog(frame, "Create new " + type.toString().toLowerCase()); - if (!props.cancelled()) { - RData object; - // create item and add to dataStore - switch (type) { - case CREATURE: - object = new RCreature(props.getID(), Editor.getStore().getActive().get("id")); - break; - case LEVEL_CREATURE: - object = new LCreature(props.getID(), Editor.getStore().getActive().get("id")); - break; - case NPC: - object = new RPerson(props.getID(), Editor.getStore().getActive().get("id")); - break; - case BOOK: - case SCROLL: - object = - new RItem.Text( - props.getID(), - Type.valueOf(type.toString().toLowerCase()), - Editor.getStore().getActive().get("id")); - break; - case DOOR: - object = - new RItem.Door( - props.getID(), - Type.valueOf(type.toString().toLowerCase()), - Editor.getStore().getActive().get("id")); - break; - case WEAPON: - object = - new RWeapon( - props.getID(), - Type.valueOf(type.toString().toLowerCase()), - Editor.getStore().getActive().get("id")); - break; - case CLOTHING: - case ARMOR: - object = - new RClothing( - props.getID(), - Type.valueOf(type.toString().toLowerCase()), - Editor.getStore().getActive().get("id")); - break; - case LEVEL_ITEM: - object = new LItem(props.getID(), Editor.getStore().getActive().get("id")); - break; - default: - object = - new RItem( - props.getID(), - Type.valueOf(type.toString().toLowerCase()), - Editor.getStore().getActive().get("id")); - break; - } - - // push node to the correct place in tree - Editor.resources.addResource(object); - ObjectNode node = new ObjectNode(object, type); - DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); - for (int i = 0; i < root.getChildCount(); i++) { - ObjectNode parent = (ObjectNode) root.getChildAt(i); - if (parent.getType() == type) { - parent.add(node); - tree.updateUI(); // otherwise the tree doesn't update after adding - Object[] nodes = {root, parent, node}; - TreePath path = new TreePath(nodes); - tree.scrollPathToVisible(path); - tree.setSelectionPath(path); - } - } - launchEditor(node); - } - } else if (e.getActionCommand().equals("Edit object")) { - launchEditor((ObjectNode) tree.getLastSelectedPathComponent()); - } else if (e.getActionCommand().equals("Delete object")) { - // remove from tree and datastore - ObjectNode node = (ObjectNode) tree.getLastSelectedPathComponent(); - model.removeNodeFromParent(node); - Editor.resources.removeResource(node.getResource()); - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2013 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor; + +import java.awt.event.*; +import javax.swing.*; +import javax.swing.tree.*; +import neon.editor.editors.ArmorEditor; +import neon.editor.editors.BookEditor; +import neon.editor.editors.ClothingEditor; +import neon.editor.editors.ContainerEditor; +import neon.editor.editors.CreatureEditor; +import neon.editor.editors.DoorEditor; +import neon.editor.editors.FoodEditor; +import neon.editor.editors.ItemEditor; +import neon.editor.editors.LevelCreatureEditor; +import neon.editor.editors.LevelItemEditor; +import neon.editor.editors.LightEditor; +import neon.editor.editors.MoneyEditor; +import neon.editor.editors.NPCEditor; +import neon.editor.editors.ObjectEditor; +import neon.editor.editors.PotionEditor; +import neon.editor.editors.ScrollEditor; +import neon.editor.editors.WeaponEditor; +import neon.resources.*; +import neon.resources.RItem.Type; + +public class ObjectTreeListener implements MouseListener { + private final JTree tree; + private final JFrame frame; + private final DefaultTreeModel model; + private final DataStore dataStore; + + public ObjectTreeListener(JTree objectTree, JFrame frame, DataStore dataStore) { + this.frame = frame; + tree = objectTree; + this.dataStore = dataStore; + model = (DefaultTreeModel) tree.getModel(); + } + + public void mouseExited(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mousePressed(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + if (e.getClickCount() == 2) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); + if (tree.getSelectionPath() != null && node.getLevel() == 2) { + launchEditor((ObjectNode) node); + } + } + } + } + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + JPopupMenu menu = new JPopupMenu(); + tree.setSelectionRow(tree.getRowForLocation(e.getX(), e.getY())); + ObjectNode node = (ObjectNode) tree.getLastSelectedPathComponent(); + if (tree.getSelectionPath() != null && node.getLevel() == 2) { + menu.add(new ClickAction("Delete object", node.getType())); + menu.add(new ClickAction("Edit object", node.getType())); + menu.add(new ClickAction("New " + node.getType().toString().toLowerCase(), node.getType())); + menu.show(e.getComponent(), e.getX(), e.getY()); + } else if (tree.getSelectionPath() != null && node.getLevel() == 1) { + menu.add(new ClickAction("New " + node.getType().toString().toLowerCase(), node.getType())); + menu.show(e.getComponent(), e.getX(), e.getY()); + } + } + } + + private void launchEditor(ObjectNode node) { + ObjectEditor editor; + switch (node.getType()) { + case LEVEL_CREATURE: + editor = new LevelCreatureEditor(frame, (LCreature) node.getResource(), dataStore); + break; + case BOOK: + editor = new BookEditor(frame, (RItem.Text) node.getResource(), dataStore); + break; + case ARMOR: + editor = new ArmorEditor(frame, (RClothing) node.getResource(), dataStore); + break; + case CLOTHING: + editor = new ClothingEditor(frame, (RClothing) node.getResource(), dataStore); + break; + case CONTAINER: + editor = new ContainerEditor(frame, (RItem.Container) node.getResource(), dataStore); + break; + case DOOR: + editor = new DoorEditor(frame, (RItem.Door) node.getResource(), dataStore); + break; + case ITEM: + editor = new ItemEditor(frame, (RItem) node.getResource(), dataStore); + break; + case LIGHT: + editor = new LightEditor(frame, (RItem) node.getResource(), dataStore); + break; + case MONEY: + editor = new MoneyEditor(frame, (RItem) node.getResource(), dataStore); + break; + case NPC: + editor = new NPCEditor(frame, (RPerson) node.getResource(), dataStore); + break; + case POTION: + editor = new PotionEditor(frame, (RItem) node.getResource(), dataStore); + break; + case SCROLL: + editor = new ScrollEditor(frame, (RItem.Text) node.getResource(), dataStore); + break; + case LEVEL_ITEM: + editor = new LevelItemEditor(frame, (LItem) node.getResource(), dataStore); + break; + case WEAPON: + editor = new WeaponEditor(frame, (RWeapon) node.getResource(), dataStore); + break; + case FOOD: + editor = new FoodEditor(frame, (RItem) node.getResource(), dataStore); + break; + default: + editor = new CreatureEditor(frame, (RCreature) node.getResource(), dataStore); + break; + } + editor.show(); + } + + @SuppressWarnings("serial") + public class ClickAction extends AbstractAction { + private final ObjectNode.ObjectType type; + + public ClickAction(String name, ObjectNode.ObjectType type) { + super(name); + this.type = type; + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("New " + type.toString().toLowerCase())) { + NewObjectDialog.Properties props = + new NewObjectDialog(dataStore) + .showInputDialog(frame, "Create new " + type.toString().toLowerCase()); + if (!props.cancelled()) { + RData object; + // create item and add to dataStore + switch (type) { + case CREATURE: + object = new RCreature(props.getID(), dataStore.getActive().get("id")); + break; + case LEVEL_CREATURE: + object = new LCreature(props.getID(), dataStore.getActive().get("id")); + break; + case NPC: + object = new RPerson(props.getID(), dataStore.getActive().get("id")); + break; + case BOOK: + case SCROLL: + object = + new RItem.Text( + props.getID(), + Type.valueOf(type.toString().toLowerCase()), + dataStore.getActive().get("id")); + break; + case DOOR: + object = + new RItem.Door( + props.getID(), + Type.valueOf(type.toString().toLowerCase()), + dataStore.getActive().get("id")); + break; + case WEAPON: + object = + new RWeapon( + props.getID(), + Type.valueOf(type.toString().toLowerCase()), + dataStore.getActive().get("id")); + break; + case CLOTHING: + case ARMOR: + object = + new RClothing( + props.getID(), + Type.valueOf(type.toString().toLowerCase()), + dataStore.getActive().get("id")); + break; + case LEVEL_ITEM: + object = new LItem(props.getID(), dataStore.getActive().get("id")); + break; + default: + object = + new RItem( + props.getID(), + Type.valueOf(type.toString().toLowerCase()), + dataStore.getActive().get("id")); + break; + } + + // push node to the correct place in tree + dataStore.getResourceManager().addResource(object); + ObjectNode node = new ObjectNode(object, type, dataStore); + DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); + for (int i = 0; i < root.getChildCount(); i++) { + ObjectNode parent = (ObjectNode) root.getChildAt(i); + if (parent.getType() == type) { + parent.add(node); + tree.updateUI(); // otherwise the tree doesn't update after adding + Object[] nodes = {root, parent, node}; + TreePath path = new TreePath(nodes); + tree.scrollPathToVisible(path); + tree.setSelectionPath(path); + } + } + launchEditor(node); + } + } else if (e.getActionCommand().equals("Edit object")) { + launchEditor((ObjectNode) tree.getLastSelectedPathComponent()); + } else if (e.getActionCommand().equals("Delete object")) { + // remove from tree and datastore + ObjectNode node = (ObjectNode) tree.getLastSelectedPathComponent(); + model.removeNodeFromParent(node); + dataStore.getResourceManager().removeResource(node.getResource()); + } + } + } +} diff --git a/src/main/java/neon/editor/ResourceAction.java b/src/main/java/neon/editor/ResourceAction.java index dbd1685..054e918 100644 --- a/src/main/java/neon/editor/ResourceAction.java +++ b/src/main/java/neon/editor/ResourceAction.java @@ -48,22 +48,25 @@ public class ResourceAction extends AbstractAction { private JTree tree; private DefaultTreeModel model; private ResourceTreeListener listener; + private final DataStore dataStore; - public ResourceAction(String name, ResourceType type, ResourceTreeListener listener) { + public ResourceAction( + String name, ResourceType type, ResourceTreeListener listener, DataStore dataStore) { super(name); this.type = type; this.listener = listener; tree = listener.getTree(); + this.dataStore = dataStore; ; model = (DefaultTreeModel) tree.getModel(); } public void actionPerformed(ActionEvent e) { - String mod = Editor.getStore().getActive().get("id"); + String mod = dataStore.getActive().get("id"); RData object = null; if (e.getActionCommand().startsWith("New")) { NewObjectDialog.Properties props = - new NewObjectDialog() + new NewObjectDialog(dataStore) .showInputDialog( Editor.getFrame(), "Create new " + type.toString().toLowerCase(), @@ -71,7 +74,8 @@ public void actionPerformed(ActionEvent e) { if (!props.cancelled()) { switch (type) { case RECIPE: - Collection potions = Editor.resources.getResources(RItem.Potion.class); + Collection potions = + dataStore.getResourceManager().getResources(RItem.Potion.class); if (!potions.isEmpty()) { // check if potions have already been created RItem potion = (RItem) @@ -85,14 +89,14 @@ public void actionPerformed(ActionEvent e) { 0); if (potion != null) { object = new RRecipe(props.getID(), potion, mod); - Editor.resources.addResource((RRecipe) object, "magic"); + dataStore.getResourceManager().addResource((RRecipe) object, "magic"); } } else { JOptionPane.showMessageDialog(Editor.getFrame(), "No potions defined!"); } break; case CRAFT: - Collection items = Editor.resources.getResources(RItem.class); + Collection items = dataStore.getResourceManager().getResources(RItem.class); if (!items.isEmpty()) { // check if items have already been created RItem craft = (RItem) @@ -106,7 +110,7 @@ public void actionPerformed(ActionEvent e) { 0); if (craft != null) { object = new RCraft(props.getID(), craft, mod); - Editor.resources.addResource((RCraft) object); + dataStore.getResourceManager().addResource((RCraft) object); } } else { JOptionPane.showMessageDialog(Editor.getFrame(), "No items defined!"); @@ -114,68 +118,68 @@ public void actionPerformed(ActionEvent e) { break; case FACTION: object = new RFaction(props.getID(), mod); - Editor.resources.addResource(object, "faction"); + dataStore.getResourceManager().addResource(object, "faction"); break; case REGION: object = new RRegionTheme(props.getID(), mod); - Editor.resources.addResource(object, "theme"); + dataStore.getResourceManager().addResource(object, "theme"); break; case ZONE: object = new RZoneTheme(props.getID(), mod); - Editor.resources.addResource(object, "theme"); + dataStore.getResourceManager().addResource(object, "theme"); break; case DUNGEON: object = new RDungeonTheme(props.getID(), mod); - Editor.resources.addResource(object, "theme"); + dataStore.getResourceManager().addResource(object, "theme"); break; case QUEST: object = new RQuest(props.getID(), mod); - Editor.resources.addResource(object, "quest"); + dataStore.getResourceManager().addResource(object, "quest"); break; case CURSE: object = new RSpell(props.getID(), SpellType.CURSE, mod); - Editor.resources.addResource(object, "magic"); + dataStore.getResourceManager().addResource(object, "magic"); break; case DISEASE: object = new RSpell(props.getID(), SpellType.DISEASE, mod); - Editor.resources.addResource(object, "magic"); + dataStore.getResourceManager().addResource(object, "magic"); break; case ENCHANTMENT: object = new RSpell.Enchantment(props.getID(), mod); - Editor.resources.addResource(object, "magic"); + dataStore.getResourceManager().addResource(object, "magic"); break; case LEVEL_SPELL: object = new LSpell(props.getID(), mod); - Editor.resources.addResource(object, "magic"); + dataStore.getResourceManager().addResource(object, "magic"); break; case POISON: object = new RSpell(props.getID(), SpellType.POISON, mod); - Editor.resources.addResource(object, "magic"); + dataStore.getResourceManager().addResource(object, "magic"); break; case POWER: object = new RSpell.Power(props.getID(), mod); - Editor.resources.addResource(object, "magic"); + dataStore.getResourceManager().addResource(object, "magic"); break; case SIGN: object = new RSign(props.getID(), mod); - Editor.resources.addResource(object, "magic"); + dataStore.getResourceManager().addResource(object, "magic"); break; case SPELL: object = new RSpell(props.getID(), SpellType.SPELL, mod); - Editor.resources.addResource(object, "magic"); + dataStore.getResourceManager().addResource(object, "magic"); break; case TATTOO: object = new RTattoo(props.getID(), mod); - Editor.resources.addResource(object, "magic"); + dataStore.getResourceManager().addResource(object, "magic"); break; default: object = new RSpell(props.getID(), SpellType.SPELL, mod); - Editor.resources.addResource(object, "magic"); + dataStore.getResourceManager().addResource(object, "magic"); break; } // push node to the correct place in tree - ResourceNode node = new ResourceNode(object, type); + ResourceNode node = new ResourceNode(object, type, dataStore); DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); listener.launchEditor(node); for (int i = 0; i < root.getChildCount(); i++) { @@ -196,7 +200,7 @@ public void actionPerformed(ActionEvent e) { // remove from tree and datastore ResourceNode node = (ResourceNode) tree.getLastSelectedPathComponent(); model.removeNodeFromParent(node); - Editor.resources.removeResource(node.getResource()); + dataStore.getResourceManager().removeResource(node.getResource()); } } } diff --git a/src/main/java/neon/editor/ResourceNode.java b/src/main/java/neon/editor/ResourceNode.java index ff6c844..61b1d57 100644 --- a/src/main/java/neon/editor/ResourceNode.java +++ b/src/main/java/neon/editor/ResourceNode.java @@ -34,15 +34,18 @@ public class ResourceNode extends DefaultMutableTreeNode { private RData resource; private ResourceType type; private String name; + private final DataStore dataStore; - public ResourceNode(RData r, ResourceType t) { + public ResourceNode(RData r, ResourceType t, DataStore dataStore) { resource = r; type = t; + this.dataStore = dataStore; } - public ResourceNode(String name, ResourceType t) { + public ResourceNode(String name, ResourceType t, DataStore dataStore) { this.name = name; type = t; + this.dataStore = dataStore; } public RData getResource() { @@ -63,7 +66,7 @@ public String toString() { id = resource.name; } - if (!resource.getPath()[0].equals(Editor.getStore().getActive().get("id"))) { + if (!resource.getPath()[0].equals(dataStore.getActive().get("id"))) { // niet-actieve data is cursief weergegeven return "" + id + ""; } else { diff --git a/src/main/java/neon/editor/ResourceTreeListener.java b/src/main/java/neon/editor/ResourceTreeListener.java index 1967521..1dc3100 100644 --- a/src/main/java/neon/editor/ResourceTreeListener.java +++ b/src/main/java/neon/editor/ResourceTreeListener.java @@ -1,146 +1,148 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor; - -import java.awt.event.*; -import javax.swing.*; -import javax.swing.tree.*; -import neon.editor.editors.AfflictionEditor; -import neon.editor.editors.AlchemyEditor; -import neon.editor.editors.CraftingEditor; -import neon.editor.editors.DungeonThemeEditor; -import neon.editor.editors.EnchantmentEditor; -import neon.editor.editors.FactionEditor; -import neon.editor.editors.LevelSpellEditor; -import neon.editor.editors.PoisonEditor; -import neon.editor.editors.PowerEditor; -import neon.editor.editors.QuestEditor; -import neon.editor.editors.RegionThemeEditor; -import neon.editor.editors.SignEditor; -import neon.editor.editors.SpellEditor; -import neon.editor.editors.TattooEditor; -import neon.editor.editors.ZoneThemeEditor; -import neon.editor.resources.RFaction; -import neon.resources.*; -import neon.resources.quest.RQuest; - -public class ResourceTreeListener implements MouseListener { - private JTree tree; - private JFrame frame; - - public ResourceTreeListener(JTree resourceTree, JFrame parent) { - tree = resourceTree; - frame = parent; - } - - protected JTree getTree() { - return tree; - } - - protected void launchEditor(ResourceNode node) { - switch (node.getType()) { - case CRAFT: - new CraftingEditor(frame, (RCraft) node.getResource()).show(); - break; - case FACTION: - new FactionEditor(frame, (RFaction) node.getResource()).show(); - break; - case DUNGEON: - new DungeonThemeEditor(frame, (RDungeonTheme) node.getResource()).show(); - break; - case ZONE: - new ZoneThemeEditor(frame, (RZoneTheme) node.getResource()).show(); - break; - case REGION: - new RegionThemeEditor(frame, (RRegionTheme) node.getResource()).show(); - break; - case QUEST: - new QuestEditor(frame, (RQuest) node.getResource()).show(); - break; - case CURSE: - new AfflictionEditor(frame, (RSpell) node.getResource()).show(); - break; - case DISEASE: - new AfflictionEditor(frame, (RSpell) node.getResource()).show(); - break; - case ENCHANTMENT: - new EnchantmentEditor(frame, (RSpell.Enchantment) node.getResource()).show(); - break; - case LEVEL_SPELL: - new LevelSpellEditor(frame, (LSpell) node.getResource()).show(); - break; - case POISON: - new PoisonEditor(frame, (RSpell) node.getResource()).show(); - break; - case POWER: - new PowerEditor(frame, (RSpell.Power) node.getResource()).show(); - break; - case SIGN: - new SignEditor(frame, (RSign) node.getResource()).show(); - break; - case RECIPE: - new AlchemyEditor(frame, (RRecipe) node.getResource()).show(); - break; - case TATTOO: - new TattooEditor(frame, (RTattoo) node.getResource()).show(); - break; - default: - new SpellEditor(frame, (RSpell) node.getResource()).show(); - break; - } - } - - public void mouseExited(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mousePressed(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON1) { - if (e.getClickCount() == 2) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); - if (tree.getSelectionPath() != null && node.getLevel() == 2) { - launchEditor((ResourceNode) node); - } - } - } - } - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - JPopupMenu menu = new JPopupMenu(); - tree.setSelectionRow(tree.getRowForLocation(e.getX(), e.getY())); - ResourceNode node = (ResourceNode) tree.getLastSelectedPathComponent(); - if (tree.getSelectionPath() != null && node.getLevel() == 2) { - menu.add(new ResourceAction("Delete resource", node.getType(), this)); - menu.add(new ResourceAction("Edit resource", node.getType(), this)); - menu.add( - new ResourceAction( - "New " + node.getType().toString().toLowerCase(), node.getType(), this)); - menu.show(e.getComponent(), e.getX(), e.getY()); - } else if (tree.getSelectionPath() != null && node.getLevel() == 1) { - menu.add( - new ResourceAction( - "New " + node.getType().toString().toLowerCase(), node.getType(), this)); - menu.show(e.getComponent(), e.getX(), e.getY()); - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor; + +import java.awt.event.*; +import javax.swing.*; +import javax.swing.tree.*; +import neon.editor.editors.AfflictionEditor; +import neon.editor.editors.AlchemyEditor; +import neon.editor.editors.CraftingEditor; +import neon.editor.editors.DungeonThemeEditor; +import neon.editor.editors.EnchantmentEditor; +import neon.editor.editors.FactionEditor; +import neon.editor.editors.LevelSpellEditor; +import neon.editor.editors.PoisonEditor; +import neon.editor.editors.PowerEditor; +import neon.editor.editors.QuestEditor; +import neon.editor.editors.RegionThemeEditor; +import neon.editor.editors.SignEditor; +import neon.editor.editors.SpellEditor; +import neon.editor.editors.TattooEditor; +import neon.editor.editors.ZoneThemeEditor; +import neon.editor.resources.RFaction; +import neon.resources.*; +import neon.resources.quest.RQuest; + +public class ResourceTreeListener implements MouseListener { + private JTree tree; + private JFrame frame; + private final DataStore dataStore; + + public ResourceTreeListener(JTree resourceTree, JFrame parent, DataStore dataStore) { + tree = resourceTree; + frame = parent; + this.dataStore = dataStore; + } + + protected JTree getTree() { + return tree; + } + + protected void launchEditor(ResourceNode node) { + switch (node.getType()) { + case CRAFT: + new CraftingEditor(frame, (RCraft) node.getResource(), dataStore).show(); + break; + case FACTION: + new FactionEditor(frame, (RFaction) node.getResource(), dataStore).show(); + break; + case DUNGEON: + new DungeonThemeEditor(frame, (RDungeonTheme) node.getResource(), dataStore).show(); + break; + case ZONE: + new ZoneThemeEditor(frame, (RZoneTheme) node.getResource(), dataStore).show(); + break; + case REGION: + new RegionThemeEditor(frame, (RRegionTheme) node.getResource(), dataStore).show(); + break; + case QUEST: + new QuestEditor(frame, (RQuest) node.getResource(), dataStore).show(); + break; + case CURSE: + new AfflictionEditor(frame, (RSpell) node.getResource(), dataStore).show(); + break; + case DISEASE: + new AfflictionEditor(frame, (RSpell) node.getResource(), dataStore).show(); + break; + case ENCHANTMENT: + new EnchantmentEditor(frame, (RSpell.Enchantment) node.getResource(), dataStore).show(); + break; + case LEVEL_SPELL: + new LevelSpellEditor(frame, (LSpell) node.getResource(), dataStore).show(); + break; + case POISON: + new PoisonEditor(frame, (RSpell) node.getResource(), dataStore).show(); + break; + case POWER: + new PowerEditor(frame, (RSpell.Power) node.getResource(), dataStore).show(); + break; + case SIGN: + new SignEditor(frame, (RSign) node.getResource(), dataStore).show(); + break; + case RECIPE: + new AlchemyEditor(frame, (RRecipe) node.getResource(), dataStore).show(); + break; + case TATTOO: + new TattooEditor(frame, (RTattoo) node.getResource(), dataStore).show(); + break; + default: + new SpellEditor(frame, (RSpell) node.getResource(), dataStore).show(); + break; + } + } + + public void mouseExited(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mousePressed(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + if (e.getClickCount() == 2) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); + if (tree.getSelectionPath() != null && node.getLevel() == 2) { + launchEditor((ResourceNode) node); + } + } + } + } + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + JPopupMenu menu = new JPopupMenu(); + tree.setSelectionRow(tree.getRowForLocation(e.getX(), e.getY())); + ResourceNode node = (ResourceNode) tree.getLastSelectedPathComponent(); + if (tree.getSelectionPath() != null && node.getLevel() == 2) { + menu.add(new ResourceAction("Delete resource", node.getType(), this, dataStore)); + menu.add(new ResourceAction("Edit resource", node.getType(), this, dataStore)); + menu.add( + new ResourceAction( + "New " + node.getType().toString().toLowerCase(), node.getType(), this, dataStore)); + menu.show(e.getComponent(), e.getX(), e.getY()); + } else if (tree.getSelectionPath() != null && node.getLevel() == 1) { + menu.add( + new ResourceAction( + "New " + node.getType().toString().toLowerCase(), node.getType(), this, dataStore)); + menu.show(e.getComponent(), e.getX(), e.getY()); + } + } + } +} diff --git a/src/main/java/neon/editor/ScriptEditor.java b/src/main/java/neon/editor/ScriptEditor.java index 2bf6479..e0bd806 100644 --- a/src/main/java/neon/editor/ScriptEditor.java +++ b/src/main/java/neon/editor/ScriptEditor.java @@ -1,168 +1,170 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor; - -import java.awt.*; -import java.awt.event.*; -import java.util.*; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import neon.resources.RScript; - -public class ScriptEditor implements ListSelectionListener, ActionListener, MouseListener { - private JDialog frame; - private JTextArea text; - private JList list; - private DefaultListModel model; - - public ScriptEditor(JFrame parent) { - frame = new JDialog(parent, "Script Editor"); - frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame.setPreferredSize(new Dimension(480, 300)); - - model = new DefaultListModel(); - list = new JList(model); - list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - list.addListSelectionListener(this); - list.setCellRenderer(new ModCellRenderer()); - JScrollPane listScroller = new JScrollPane(list); - listScroller.setBorder(new TitledBorder("Scripts")); - - text = new JTextArea(); - JScrollPane textScroller = new JScrollPane(text); - textScroller.setBorder(new TitledBorder("Edit script")); - - JPanel content = new JPanel(new BorderLayout()); - content.add(listScroller, BorderLayout.LINE_START); - content.add(textScroller, BorderLayout.CENTER); - frame.setContentPane(content); - - JPanel buttons = new JPanel(); - content.add(buttons, BorderLayout.PAGE_END); - JButton ok = new JButton("Ok"); - ok.addActionListener(this); - JButton cancel = new JButton("Cancel"); - cancel.addActionListener(this); - JButton apply = new JButton("Apply"); - apply.addActionListener(this); - buttons.add(ok); - list.addMouseListener(this); - buttons.add(cancel); - buttons.add(apply); - } - - public void show() { - model.clear(); - for (RScript script : Editor.getStore().getScripts().values()) { - model.addElement(new RScript(script)); - } - frame.pack(); - frame.setLocationRelativeTo(null); - frame.setVisible(true); - } - - public void valueChanged(ListSelectionEvent e) { - // blijkbaar worden er twee events gefired bij selectie - if (e.getValueIsAdjusting()) { - if (list.isSelectedIndex(e.getFirstIndex()) && !list.isSelectedIndex(e.getLastIndex())) { - model.elementAt(e.getLastIndex()).script = text.getText(); - } else if (list.isSelectedIndex(e.getLastIndex()) - && !list.isSelectedIndex(e.getFirstIndex())) { - model.elementAt(e.getFirstIndex()).script = text.getText(); - } - text.setText(list.getSelectedValue().script); - } - } - - private void save() { - HashMap temp = new HashMap(Editor.getStore().getScripts()); - Editor.getStore().getScripts().clear(); - for (Enumeration rs = model.elements(); rs.hasMoreElements(); ) { - RScript script = rs.nextElement(); - if (!equals(script, temp.get(script.id))) { // script gewijzigd, dan naar active mod - script.setPath(Editor.getStore().getActive().get("id")); - } - Editor.getStore().getScripts().put(script.id, script); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Cancel")) { - frame.dispose(); - } else if (e.getActionCommand().equals("Apply")) { - save(); - } else if (e.getActionCommand().equals("Ok")) { - save(); - frame.dispose(); - } - } - - public boolean equals(RScript one, RScript two) { - return one.id.equals(two.id) && one.script.equals(two.script); - } - - public void mousePressed(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseExited(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - JPopupMenu menu = new JPopupMenu(); - menu.add(new ClickAction("New script")); - menu.add(new ClickAction("Delete script")); - menu.show(e.getComponent(), e.getX(), e.getY()); - list.setSelectedIndex(list.locationToIndex(new Point(e.getX(), e.getY()))); - } - } - - @SuppressWarnings("serial") - public class ClickAction extends AbstractAction { - public ClickAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("New script")) { - String s = - (String) - JOptionPane.showInputDialog( - frame, "Script name:", "New script", JOptionPane.QUESTION_MESSAGE); - if ((s != null) && (s.length() > 0)) { - RScript script = new RScript(s, Editor.getStore().getActive().get("id")); - model.addElement(script); - list.setSelectedValue(script, true); - text.setText(""); - } - } else if (e.getActionCommand().equals("Delete script")) { - try { - if (list.getSelectedIndex() >= 0) { - int index = list.getSelectedIndex(); - model.remove(index); - } - } catch (ArrayIndexOutOfBoundsException a) { - } - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; +import neon.resources.RScript; + +public class ScriptEditor implements ListSelectionListener, ActionListener, MouseListener { + private JDialog frame; + private final DataStore dataStore; + private JTextArea text; + private JList list; + private DefaultListModel model; + + public ScriptEditor(JFrame parent, DataStore dataStore) { + frame = new JDialog(parent, "Script Editor"); + this.dataStore = dataStore; + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setPreferredSize(new Dimension(480, 300)); + + model = new DefaultListModel(); + list = new JList(model); + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + list.addListSelectionListener(this); + list.setCellRenderer(new ModCellRenderer(dataStore)); + JScrollPane listScroller = new JScrollPane(list); + listScroller.setBorder(new TitledBorder("Scripts")); + + text = new JTextArea(); + JScrollPane textScroller = new JScrollPane(text); + textScroller.setBorder(new TitledBorder("Edit script")); + + JPanel content = new JPanel(new BorderLayout()); + content.add(listScroller, BorderLayout.LINE_START); + content.add(textScroller, BorderLayout.CENTER); + frame.setContentPane(content); + + JPanel buttons = new JPanel(); + content.add(buttons, BorderLayout.PAGE_END); + JButton ok = new JButton("Ok"); + ok.addActionListener(this); + JButton cancel = new JButton("Cancel"); + cancel.addActionListener(this); + JButton apply = new JButton("Apply"); + apply.addActionListener(this); + buttons.add(ok); + list.addMouseListener(this); + buttons.add(cancel); + buttons.add(apply); + } + + public void show() { + model.clear(); + for (RScript script : dataStore.getScripts().values()) { + model.addElement(new RScript(script)); + } + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public void valueChanged(ListSelectionEvent e) { + // blijkbaar worden er twee events gefired bij selectie + if (e.getValueIsAdjusting()) { + if (list.isSelectedIndex(e.getFirstIndex()) && !list.isSelectedIndex(e.getLastIndex())) { + model.elementAt(e.getLastIndex()).script = text.getText(); + } else if (list.isSelectedIndex(e.getLastIndex()) + && !list.isSelectedIndex(e.getFirstIndex())) { + model.elementAt(e.getFirstIndex()).script = text.getText(); + } + text.setText(list.getSelectedValue().script); + } + } + + private void save() { + HashMap temp = new HashMap(dataStore.getScripts()); + dataStore.getScripts().clear(); + for (Enumeration rs = model.elements(); rs.hasMoreElements(); ) { + RScript script = rs.nextElement(); + if (!equals(script, temp.get(script.id))) { // script gewijzigd, dan naar active mod + script.setPath(dataStore.getActive().get("id")); + } + dataStore.getScripts().put(script.id, script); + } + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Cancel")) { + frame.dispose(); + } else if (e.getActionCommand().equals("Apply")) { + save(); + } else if (e.getActionCommand().equals("Ok")) { + save(); + frame.dispose(); + } + } + + public boolean equals(RScript one, RScript two) { + return one.id.equals(two.id) && one.script.equals(two.script); + } + + public void mousePressed(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseExited(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + JPopupMenu menu = new JPopupMenu(); + menu.add(new ClickAction("New script")); + menu.add(new ClickAction("Delete script")); + menu.show(e.getComponent(), e.getX(), e.getY()); + list.setSelectedIndex(list.locationToIndex(new Point(e.getX(), e.getY()))); + } + } + + @SuppressWarnings("serial") + public class ClickAction extends AbstractAction { + public ClickAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("New script")) { + String s = + (String) + JOptionPane.showInputDialog( + frame, "Script name:", "New script", JOptionPane.QUESTION_MESSAGE); + if ((s != null) && (s.length() > 0)) { + RScript script = new RScript(s, dataStore.getActive().get("id")); + model.addElement(script); + list.setSelectedValue(script, true); + text.setText(""); + } + } else if (e.getActionCommand().equals("Delete script")) { + try { + if (list.getSelectedIndex() >= 0) { + int index = list.getSelectedIndex(); + model.remove(index); + } + } catch (ArrayIndexOutOfBoundsException a) { + } + } + } + } +} diff --git a/src/main/java/neon/editor/editors/AfflictionEditor.java b/src/main/java/neon/editor/editors/AfflictionEditor.java index c658c27..f24d526 100644 --- a/src/main/java/neon/editor/editors/AfflictionEditor.java +++ b/src/main/java/neon/editor/editors/AfflictionEditor.java @@ -1,134 +1,136 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.magic.Effect; -import neon.resources.RSpell; - -public class AfflictionEditor extends ObjectEditor implements ActionListener { - private JTextField nameField; - private JFormattedTextField sizeField; - private JComboBox effectBox; - private JTextArea scriptArea; - private RSpell data; - - public AfflictionEditor(JFrame parent, RSpell data) { - super(parent, "Affliction: " + data.id); - this.data = data; - - JPanel props = new JPanel(); - GroupLayout layout = new GroupLayout(props); - props.setLayout(layout); - layout.setAutoCreateGaps(true); - props.setBorder(new TitledBorder("Properties")); - - JLabel nameLabel = new JLabel("Name: "); - JLabel effectLabel = new JLabel("Effect: "); - JLabel sizeLabel = new JLabel("Magnitude: "); - nameField = new JTextField(15); - effectBox = new JComboBox(Effect.values()); - effectBox.addActionListener(this); - sizeField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel effectHelpLabel = HelpLabels.getEffectHelpLabel(); - JLabel sizeHelpLabel = HelpLabels.getSpellSizeHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(effectLabel) - .addComponent(effectBox) - .addComponent(effectHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(sizeLabel) - .addComponent(sizeField) - .addComponent(sizeHelpLabel)) - .addGap(10)); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(effectLabel) - .addComponent(sizeLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(effectBox) - .addComponent(sizeField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(effectHelpLabel) - .addComponent(sizeHelpLabel))); - frame.add(props, BorderLayout.PAGE_START); - - scriptArea = new JTextArea(6, 0); - scriptArea.setDisabledTextColor(Color.red); - JScrollPane scriptScroller = new JScrollPane(scriptArea); - scriptScroller.setBorder(new TitledBorder("Script")); - frame.add(scriptScroller, BorderLayout.CENTER); - } - - protected void load() { - nameField.setText(data.name); - effectBox.setSelectedItem(data.effect); - sizeField.setValue(data.size); - scriptArea.setText(data.script); - scriptArea.setEditable(data.effect == Effect.SCRIPTED); - } - - protected void save() { - data.name = nameField.getText(); - data.size = Integer.parseInt(sizeField.getText()); - data.effect = effectBox.getItemAt(effectBox.getSelectedIndex()); - data.script = scriptArea.getText(); - data.setPath(Editor.getStore().getActive().get("id")); - } - - public void actionPerformed(ActionEvent e) { - scriptArea.setEditable(effectBox.getSelectedItem() == Effect.SCRIPTED); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.magic.Effect; +import neon.resources.RSpell; + +public class AfflictionEditor extends ObjectEditor implements ActionListener { + private JTextField nameField; + private JFormattedTextField sizeField; + private JComboBox effectBox; + private JTextArea scriptArea; + private RSpell data; + private final DataStore dataStore; + + public AfflictionEditor(JFrame parent, RSpell data, DataStore dataStore) { + super(parent, "Affliction: " + data.id); + this.data = data; + this.dataStore = dataStore; + + JPanel props = new JPanel(); + GroupLayout layout = new GroupLayout(props); + props.setLayout(layout); + layout.setAutoCreateGaps(true); + props.setBorder(new TitledBorder("Properties")); + + JLabel nameLabel = new JLabel("Name: "); + JLabel effectLabel = new JLabel("Effect: "); + JLabel sizeLabel = new JLabel("Magnitude: "); + nameField = new JTextField(15); + effectBox = new JComboBox(Effect.values()); + effectBox.addActionListener(this); + sizeField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel effectHelpLabel = HelpLabels.getEffectHelpLabel(); + JLabel sizeHelpLabel = HelpLabels.getSpellSizeHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(effectLabel) + .addComponent(effectBox) + .addComponent(effectHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(sizeLabel) + .addComponent(sizeField) + .addComponent(sizeHelpLabel)) + .addGap(10)); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(effectLabel) + .addComponent(sizeLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(effectBox) + .addComponent(sizeField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(effectHelpLabel) + .addComponent(sizeHelpLabel))); + frame.add(props, BorderLayout.PAGE_START); + + scriptArea = new JTextArea(6, 0); + scriptArea.setDisabledTextColor(Color.red); + JScrollPane scriptScroller = new JScrollPane(scriptArea); + scriptScroller.setBorder(new TitledBorder("Script")); + frame.add(scriptScroller, BorderLayout.CENTER); + } + + protected void load() { + nameField.setText(data.name); + effectBox.setSelectedItem(data.effect); + sizeField.setValue(data.size); + scriptArea.setText(data.script); + scriptArea.setEditable(data.effect == Effect.SCRIPTED); + } + + protected void save() { + data.name = nameField.getText(); + data.size = Integer.parseInt(sizeField.getText()); + data.effect = effectBox.getItemAt(effectBox.getSelectedIndex()); + data.script = scriptArea.getText(); + data.setPath(dataStore.getActive().get("id")); + } + + public void actionPerformed(ActionEvent e) { + scriptArea.setEditable(effectBox.getSelectedItem() == Effect.SCRIPTED); + } +} diff --git a/src/main/java/neon/editor/editors/AlchemyEditor.java b/src/main/java/neon/editor/editors/AlchemyEditor.java index 805371d..d42788c 100644 --- a/src/main/java/neon/editor/editors/AlchemyEditor.java +++ b/src/main/java/neon/editor/editors/AlchemyEditor.java @@ -1,129 +1,131 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.awt.event.*; -import java.util.*; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.resources.RItem; -import neon.resources.RRecipe; - -@SuppressWarnings("serial") -public class AlchemyEditor extends ObjectEditor implements MouseListener { - private JList contentList; - private DefaultListModel contentModel; - private RRecipe recipe; - private JFormattedTextField costField; - - public AlchemyEditor(JFrame parent, RRecipe recipe) { - super(parent, "Recipe: " + recipe.id); - this.recipe = recipe; - - contentModel = new DefaultListModel(); - contentList = new JList(contentModel); - contentList.addMouseListener(this); - JScrollPane textScroller = new JScrollPane(contentList); - textScroller.setBorder(new TitledBorder("Ingredients")); - frame.add(textScroller, BorderLayout.CENTER); - - JLabel costLabel = new JLabel("Cost: "); - costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - costField.setColumns(10); - JLabel costHelpLabel = HelpLabels.getAlchemyCostHelpLabel(); - - JPanel costPanel = new JPanel(); - costPanel.setBorder(new TitledBorder("Properties")); - costPanel.add(costLabel); - costPanel.add(costField); - costPanel.add(costHelpLabel); - frame.add(costPanel, BorderLayout.PAGE_START); - } - - protected void load() { - contentModel.clear(); - costField.setValue(recipe.cost); - for (String id : recipe.ingredients) { - RItem ri = (RItem) Editor.resources.getResource(id); - contentModel.addElement(ri); - } - } - - protected void save() { - recipe.ingredients.clear(); - recipe.cost = (int) costField.getValue(); - for (Enumeration items = contentModel.elements(); items.hasMoreElements(); ) { - recipe.ingredients.add(items.nextElement().id); - } - } - - public void mousePressed(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseExited(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - JPopupMenu menu = new JPopupMenu(); - menu.add(new ClickAction("Add ingredient")); - menu.add(new ClickAction("Remove ingredient")); - menu.show(e.getComponent(), e.getX(), e.getY()); - contentList.setSelectedIndex(contentList.locationToIndex(new Point(e.getX(), e.getY()))); - } - } - - public class ClickAction extends AbstractAction { - public ClickAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add ingredient")) { - Object[] items = Editor.resources.getResources(RItem.class).toArray(); - RItem ingredient = - (RItem) - JOptionPane.showInputDialog( - frame, - "Add ingredient:", - "Add ingredient", - JOptionPane.PLAIN_MESSAGE, - null, - items, - 0); - if (ingredient != null) { - contentModel.addElement(ingredient); - } - } else if (e.getActionCommand().equals("Remove ingredient")) { - try { - if (contentList.getSelectedIndex() >= 0) { - contentModel.remove(contentList.getSelectedIndex()); - } - } catch (ArrayIndexOutOfBoundsException a) { - } - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2013 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.resources.RItem; +import neon.resources.RRecipe; + +@SuppressWarnings("serial") +public class AlchemyEditor extends ObjectEditor implements MouseListener { + private JList contentList; + private DefaultListModel contentModel; + private RRecipe recipe; + private JFormattedTextField costField; + private final DataStore dataStore; + + public AlchemyEditor(JFrame parent, RRecipe recipe, DataStore dataStore) { + super(parent, "Recipe: " + recipe.id); + this.recipe = recipe; + this.dataStore = dataStore; + + contentModel = new DefaultListModel(); + contentList = new JList(contentModel); + contentList.addMouseListener(this); + JScrollPane textScroller = new JScrollPane(contentList); + textScroller.setBorder(new TitledBorder("Ingredients")); + frame.add(textScroller, BorderLayout.CENTER); + + JLabel costLabel = new JLabel("Cost: "); + costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + costField.setColumns(10); + JLabel costHelpLabel = HelpLabels.getAlchemyCostHelpLabel(); + + JPanel costPanel = new JPanel(); + costPanel.setBorder(new TitledBorder("Properties")); + costPanel.add(costLabel); + costPanel.add(costField); + costPanel.add(costHelpLabel); + frame.add(costPanel, BorderLayout.PAGE_START); + } + + protected void load() { + contentModel.clear(); + costField.setValue(recipe.cost); + for (String id : recipe.ingredients) { + RItem ri = (RItem) dataStore.getResourceManager().getResource(id); + contentModel.addElement(ri); + } + } + + protected void save() { + recipe.ingredients.clear(); + recipe.cost = (int) costField.getValue(); + for (Enumeration items = contentModel.elements(); items.hasMoreElements(); ) { + recipe.ingredients.add(items.nextElement().id); + } + } + + public void mousePressed(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseExited(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + JPopupMenu menu = new JPopupMenu(); + menu.add(new ClickAction("Add ingredient")); + menu.add(new ClickAction("Remove ingredient")); + menu.show(e.getComponent(), e.getX(), e.getY()); + contentList.setSelectedIndex(contentList.locationToIndex(new Point(e.getX(), e.getY()))); + } + } + + public class ClickAction extends AbstractAction { + public ClickAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add ingredient")) { + Object[] items = dataStore.getResourceManager().getResources(RItem.class).toArray(); + RItem ingredient = + (RItem) + JOptionPane.showInputDialog( + frame, + "Add ingredient:", + "Add ingredient", + JOptionPane.PLAIN_MESSAGE, + null, + items, + 0); + if (ingredient != null) { + contentModel.addElement(ingredient); + } + } else if (e.getActionCommand().equals("Remove ingredient")) { + try { + if (contentList.getSelectedIndex() >= 0) { + contentModel.remove(contentList.getSelectedIndex()); + } + } catch (ArrayIndexOutOfBoundsException a) { + } + } + } + } +} diff --git a/src/main/java/neon/editor/editors/ArmorEditor.java b/src/main/java/neon/editor/editors/ArmorEditor.java index b6e21c3..486ea10 100644 --- a/src/main/java/neon/editor/editors/ArmorEditor.java +++ b/src/main/java/neon/editor/editors/ArmorEditor.java @@ -22,7 +22,9 @@ import java.util.Vector; import javax.swing.*; import javax.swing.border.TitledBorder; -import neon.editor.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.NeonFormat; import neon.editor.help.HelpLabels; import neon.entities.property.Slot; import neon.resources.RClothing; @@ -36,11 +38,14 @@ public class ArmorEditor extends ObjectEditor { private JComboBox slotBox; private JComboBox classBox; private RClothing data; + private final DataStore dataStore; + private final HelpLabels helpLabels; - public ArmorEditor(JFrame parent, RClothing data) { + public ArmorEditor(JFrame parent, RClothing data, DataStore dataStore) { super(parent, "Armor Editor: " + data.id); this.data = data; - + this.dataStore = dataStore; + this.helpLabels = new HelpLabels(dataStore); JPanel itemProps = new JPanel(); GroupLayout layout = new GroupLayout(itemProps); itemProps.setLayout(layout); @@ -68,7 +73,7 @@ public ArmorEditor(JFrame parent, RClothing data) { ratingField = new JFormattedTextField(NeonFormat.getIntegerInstance()); spellBox = new JComboBox(loadSpells()); JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCostHelpLabel(); + JLabel costHelpLabel = helpLabels.getCostHelpLabel(); JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); @@ -208,13 +213,14 @@ protected void save() { data.spell = spellBox.getSelectedItem().toString(); } - data.setPath(Editor.getStore().getActive().get("id")); + data.setPath(dataStore.getActive().get("id")); } private Vector loadSpells() { Vector spells = new Vector(); spells.add(null); - for (RSpell.Enchantment spell : Editor.resources.getResources(RSpell.Enchantment.class)) { + for (RSpell.Enchantment spell : + dataStore.getResourceManager().getResources(RSpell.Enchantment.class)) { if (spell.item.equals("clothing")) { spells.add(spell.id); } diff --git a/src/main/java/neon/editor/editors/BookEditor.java b/src/main/java/neon/editor/editors/BookEditor.java index 77c4049..319f05f 100644 --- a/src/main/java/neon/editor/editors/BookEditor.java +++ b/src/main/java/neon/editor/editors/BookEditor.java @@ -1,166 +1,169 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.ColorCellRenderer; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.resources.RItem; -import neon.util.ColorFactory; - -public class BookEditor extends ObjectEditor { - private JTextField nameField, textField; - private JFormattedTextField costField, weightField, charField; - private JComboBox colorBox; - private RItem.Text data; - - public BookEditor(JFrame parent, RItem.Text data) { - super(parent, "Book Editor: " + data.id); - this.data = data; - - JPanel itemProps = new JPanel(); - GroupLayout layout = new GroupLayout(itemProps); - itemProps.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel nameLabel = new JLabel("Name: "); - JLabel costLabel = new JLabel("Cost: "); - JLabel colorLabel = new JLabel("Color: "); - JLabel charLabel = new JLabel("Character: "); - JLabel weightLabel = new JLabel("Weight: "); - JLabel textLabel = new JLabel("Text: "); - nameField = new JTextField(15); - costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - colorBox = new JComboBox(ColorFactory.getColorNames()); - colorBox.setBackground(Color.black); - colorBox.setRenderer(new ColorCellRenderer()); - colorBox.addActionListener(new ColorListener(colorBox)); - charField = new JFormattedTextField(getMaskFormatter("*", 'X')); - weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); - textField = new JTextField(15); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCostHelpLabel(); - JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); - JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); - JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); - JLabel textHelpLabel = HelpLabels.getBookTextHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(costLabel) - .addComponent(costField) - .addComponent(costHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(colorLabel) - .addComponent(colorBox) - .addComponent(colorHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(charLabel) - .addComponent(charField) - .addComponent(charHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(weightLabel) - .addComponent(weightField) - .addComponent(weightHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(textLabel) - .addComponent(textField) - .addComponent(textHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(costLabel) - .addComponent(colorLabel) - .addComponent(charLabel) - .addComponent(weightLabel) - .addComponent(textLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(costField) - .addComponent(colorBox) - .addComponent(charField) - .addComponent(weightField) - .addComponent(textField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(costHelpLabel) - .addComponent(colorHelpLabel) - .addComponent(charHelpLabel) - .addComponent(weightHelpLabel) - .addComponent(textHelpLabel))); - - JScrollPane propScroller = new JScrollPane(itemProps); - propScroller.setBorder(new TitledBorder("Properties")); - frame.add(propScroller, BorderLayout.CENTER); - } - - protected void load() { - nameField.setText(data.name); - costField.setValue(data.cost); - colorBox.setSelectedItem(data.color); - charField.setValue(data.text); - weightField.setValue(data.weight); - textField.setText(data.content); - } - - protected void save() { - data.name = nameField.getText(); - data.cost = Integer.parseInt(costField.getText()); - data.color = colorBox.getSelectedItem().toString(); - data.text = charField.getText(); - data.weight = Float.parseFloat(weightField.getText()); - data.content = textField.getText(); - - data.setPath(Editor.getStore().getActive().get("id")); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.resources.RItem; +import neon.util.ColorFactory; + +public class BookEditor extends ObjectEditor { + private JTextField nameField, textField; + private JFormattedTextField costField, weightField, charField; + private JComboBox colorBox; + private RItem.Text data; + private final DataStore dataStore; + private final HelpLabels helpLabels; + + public BookEditor(JFrame parent, RItem.Text data, DataStore dataStore) { + super(parent, "Book Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + helpLabels = new HelpLabels(dataStore); + JPanel itemProps = new JPanel(); + GroupLayout layout = new GroupLayout(itemProps); + itemProps.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel nameLabel = new JLabel("Name: "); + JLabel costLabel = new JLabel("Cost: "); + JLabel colorLabel = new JLabel("Color: "); + JLabel charLabel = new JLabel("Character: "); + JLabel weightLabel = new JLabel("Weight: "); + JLabel textLabel = new JLabel("Text: "); + nameField = new JTextField(15); + costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + colorBox = new JComboBox(ColorFactory.getColorNames()); + colorBox.setBackground(Color.black); + colorBox.setRenderer(new ColorCellRenderer()); + colorBox.addActionListener(new ColorListener(colorBox)); + charField = new JFormattedTextField(getMaskFormatter("*", 'X')); + weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); + textField = new JTextField(15); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel costHelpLabel = helpLabels.getCostHelpLabel(); + JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); + JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); + JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); + JLabel textHelpLabel = HelpLabels.getBookTextHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(costLabel) + .addComponent(costField) + .addComponent(costHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(colorLabel) + .addComponent(colorBox) + .addComponent(colorHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(charLabel) + .addComponent(charField) + .addComponent(charHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(weightLabel) + .addComponent(weightField) + .addComponent(weightHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(textLabel) + .addComponent(textField) + .addComponent(textHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(costLabel) + .addComponent(colorLabel) + .addComponent(charLabel) + .addComponent(weightLabel) + .addComponent(textLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(costField) + .addComponent(colorBox) + .addComponent(charField) + .addComponent(weightField) + .addComponent(textField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(costHelpLabel) + .addComponent(colorHelpLabel) + .addComponent(charHelpLabel) + .addComponent(weightHelpLabel) + .addComponent(textHelpLabel))); + + JScrollPane propScroller = new JScrollPane(itemProps); + propScroller.setBorder(new TitledBorder("Properties")); + frame.add(propScroller, BorderLayout.CENTER); + } + + protected void load() { + nameField.setText(data.name); + costField.setValue(data.cost); + colorBox.setSelectedItem(data.color); + charField.setValue(data.text); + weightField.setValue(data.weight); + textField.setText(data.content); + } + + protected void save() { + data.name = nameField.getText(); + data.cost = Integer.parseInt(costField.getText()); + data.color = colorBox.getSelectedItem().toString(); + data.text = charField.getText(); + data.weight = Float.parseFloat(weightField.getText()); + data.content = textField.getText(); + + data.setPath(dataStore.getActive().get("id")); + } +} diff --git a/src/main/java/neon/editor/editors/ClothingEditor.java b/src/main/java/neon/editor/editors/ClothingEditor.java index 8be9aa6..1c762bb 100644 --- a/src/main/java/neon/editor/editors/ClothingEditor.java +++ b/src/main/java/neon/editor/editors/ClothingEditor.java @@ -1,207 +1,213 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.util.Vector; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.*; -import neon.editor.help.HelpLabels; -import neon.entities.property.Slot; -import neon.resources.RClothing; -import neon.resources.RSpell; -import neon.util.ColorFactory; - -public class ClothingEditor extends ObjectEditor { - private JTextField nameField; - private JFormattedTextField costField, weightField, charField; - private JComboBox colorBox, spellBox; - private JComboBox slotBox; - private RClothing data; - - public ClothingEditor(JFrame parent, RClothing data) { - super(parent, "Clothing Editor: " + data.id); - this.data = data; - - JPanel itemProps = new JPanel(); - GroupLayout layout = new GroupLayout(itemProps); - itemProps.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel nameLabel = new JLabel("Name: "); - JLabel costLabel = new JLabel("Cost: "); - JLabel colorLabel = new JLabel("Color: "); - JLabel charLabel = new JLabel("Character: "); - JLabel weightLabel = new JLabel("Weight: "); - JLabel slotLabel = new JLabel("Slot: "); - JLabel spellLabel = new JLabel("Enchantment: "); - nameField = new JTextField(15); - costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - colorBox = new JComboBox(ColorFactory.getColorNames()); - colorBox.setBackground(Color.black); - colorBox.setRenderer(new ColorCellRenderer()); - colorBox.addActionListener(new ColorListener(colorBox)); - charField = new JFormattedTextField(getMaskFormatter("*", 'X')); - weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); - slotBox = new JComboBox(loadSlots()); - spellBox = new JComboBox(loadSpells()); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCostHelpLabel(); - JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); - JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); - JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); - JLabel slotHelpLabel = HelpLabels.getClothingSlotHelpLabel(); - JLabel spellHelpLabel = HelpLabels.getClothingEnchantmentHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(costLabel) - .addComponent(costField) - .addComponent(costHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(colorLabel) - .addComponent(colorBox) - .addComponent(colorHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(charLabel) - .addComponent(charField) - .addComponent(charHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(weightLabel) - .addComponent(weightField) - .addComponent(weightHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(slotLabel) - .addComponent(slotBox) - .addComponent(slotHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(spellLabel) - .addComponent(spellBox) - .addComponent(spellHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(costLabel) - .addComponent(colorLabel) - .addComponent(charLabel) - .addComponent(weightLabel) - .addComponent(slotLabel) - .addComponent(spellLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(costField) - .addComponent(colorBox) - .addComponent(charField) - .addComponent(weightField) - .addComponent(slotBox) - .addComponent(spellBox)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(costHelpLabel) - .addComponent(colorHelpLabel) - .addComponent(charHelpLabel) - .addComponent(weightHelpLabel) - .addComponent(slotHelpLabel) - .addComponent(spellHelpLabel))); - JScrollPane propScroller = new JScrollPane(itemProps); - propScroller.setBorder(new TitledBorder("Properties")); - frame.add(propScroller, BorderLayout.CENTER); - } - - protected void load() { - nameField.setText(data.name); - costField.setValue(data.cost); - colorBox.setSelectedItem(data.color); - charField.setValue(data.text); - weightField.setValue(data.weight); - slotBox.setSelectedItem(data.slot); - spellBox.setSelectedItem(data.spell); - } - - protected void save() { - data.name = nameField.getText(); - data.cost = Integer.parseInt(costField.getText()); - data.color = colorBox.getSelectedItem().toString(); - data.text = charField.getText(); - data.weight = Float.parseFloat(weightField.getText()); - data.slot = slotBox.getItemAt(slotBox.getSelectedIndex()); - if (spellBox.getSelectedItem() != null) { - data.spell = spellBox.getSelectedItem().toString(); - } - - data.setPath(Editor.getStore().getActive().get("id")); - } - - private Vector loadSpells() { - Vector spells = new Vector(); - spells.add(null); - for (RSpell.Enchantment spell : Editor.resources.getResources(RSpell.Enchantment.class)) { - if (spell.item.equals("clothing")) { - spells.add(spell.id); - } - } - return spells; - } - - private Vector loadSlots() { - Vector slots = new Vector(); - slots.add(Slot.AMULET); - slots.add(Slot.RING); - slots.add(Slot.BELT); - slots.add(Slot.SHIRT); - slots.add(Slot.PANTS); - slots.add(Slot.CLOAK); - slots.add(Slot.SHOES); - slots.add(Slot.GLOVES); - return slots; - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.util.Vector; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.entities.property.Slot; +import neon.resources.RClothing; +import neon.resources.RSpell; +import neon.util.ColorFactory; + +public class ClothingEditor extends ObjectEditor { + private JTextField nameField; + private JFormattedTextField costField, weightField, charField; + private JComboBox colorBox, spellBox; + private JComboBox slotBox; + private RClothing data; + private final DataStore dataStore; + private final HelpLabels helpLabels; + + public ClothingEditor(JFrame parent, RClothing data, DataStore dataStore) { + super(parent, "Clothing Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + helpLabels = new HelpLabels(dataStore); + JPanel itemProps = new JPanel(); + GroupLayout layout = new GroupLayout(itemProps); + itemProps.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel nameLabel = new JLabel("Name: "); + JLabel costLabel = new JLabel("Cost: "); + JLabel colorLabel = new JLabel("Color: "); + JLabel charLabel = new JLabel("Character: "); + JLabel weightLabel = new JLabel("Weight: "); + JLabel slotLabel = new JLabel("Slot: "); + JLabel spellLabel = new JLabel("Enchantment: "); + nameField = new JTextField(15); + costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + colorBox = new JComboBox(ColorFactory.getColorNames()); + colorBox.setBackground(Color.black); + colorBox.setRenderer(new ColorCellRenderer()); + colorBox.addActionListener(new ColorListener(colorBox)); + charField = new JFormattedTextField(getMaskFormatter("*", 'X')); + weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); + slotBox = new JComboBox(loadSlots()); + spellBox = new JComboBox(loadSpells()); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel costHelpLabel = helpLabels.getCostHelpLabel(); + JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); + JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); + JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); + JLabel slotHelpLabel = HelpLabels.getClothingSlotHelpLabel(); + JLabel spellHelpLabel = HelpLabels.getClothingEnchantmentHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(costLabel) + .addComponent(costField) + .addComponent(costHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(colorLabel) + .addComponent(colorBox) + .addComponent(colorHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(charLabel) + .addComponent(charField) + .addComponent(charHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(weightLabel) + .addComponent(weightField) + .addComponent(weightHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(slotLabel) + .addComponent(slotBox) + .addComponent(slotHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(spellLabel) + .addComponent(spellBox) + .addComponent(spellHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(costLabel) + .addComponent(colorLabel) + .addComponent(charLabel) + .addComponent(weightLabel) + .addComponent(slotLabel) + .addComponent(spellLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(costField) + .addComponent(colorBox) + .addComponent(charField) + .addComponent(weightField) + .addComponent(slotBox) + .addComponent(spellBox)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(costHelpLabel) + .addComponent(colorHelpLabel) + .addComponent(charHelpLabel) + .addComponent(weightHelpLabel) + .addComponent(slotHelpLabel) + .addComponent(spellHelpLabel))); + JScrollPane propScroller = new JScrollPane(itemProps); + propScroller.setBorder(new TitledBorder("Properties")); + frame.add(propScroller, BorderLayout.CENTER); + } + + protected void load() { + nameField.setText(data.name); + costField.setValue(data.cost); + colorBox.setSelectedItem(data.color); + charField.setValue(data.text); + weightField.setValue(data.weight); + slotBox.setSelectedItem(data.slot); + spellBox.setSelectedItem(data.spell); + } + + protected void save() { + data.name = nameField.getText(); + data.cost = Integer.parseInt(costField.getText()); + data.color = colorBox.getSelectedItem().toString(); + data.text = charField.getText(); + data.weight = Float.parseFloat(weightField.getText()); + data.slot = slotBox.getItemAt(slotBox.getSelectedIndex()); + if (spellBox.getSelectedItem() != null) { + data.spell = spellBox.getSelectedItem().toString(); + } + + data.setPath(dataStore.getActive().get("id")); + } + + private Vector loadSpells() { + Vector spells = new Vector(); + spells.add(null); + for (RSpell.Enchantment spell : + dataStore.getResourceManager().getResources(RSpell.Enchantment.class)) { + if (spell.item.equals("clothing")) { + spells.add(spell.id); + } + } + return spells; + } + + private Vector loadSlots() { + Vector slots = new Vector(); + slots.add(Slot.AMULET); + slots.add(Slot.RING); + slots.add(Slot.BELT); + slots.add(Slot.SHIRT); + slots.add(Slot.PANTS); + slots.add(Slot.CLOAK); + slots.add(Slot.SHOES); + slots.add(Slot.GLOVES); + return slots; + } +} diff --git a/src/main/java/neon/editor/editors/ContainerEditor.java b/src/main/java/neon/editor/editors/ContainerEditor.java index d84027b..030a56c 100644 --- a/src/main/java/neon/editor/editors/ContainerEditor.java +++ b/src/main/java/neon/editor/editors/ContainerEditor.java @@ -1,182 +1,183 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.awt.event.*; -import java.util.Enumeration; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.ColorCellRenderer; -import neon.editor.Editor; -import neon.editor.help.HelpLabels; -import neon.resources.RItem; -import neon.util.ColorFactory; - -public class ContainerEditor extends ObjectEditor implements MouseListener { - private JTextField nameField; - private JComboBox colorBox; - private JFormattedTextField charField; - private RItem.Container data; - private JList items; - private DefaultListModel model; - - public ContainerEditor(JFrame parent, RItem.Container data) { - super(parent, "Container Editor: " + data.id); - frame.setPreferredSize(new Dimension(400, 200)); - this.data = data; - - JPanel itemProps = new JPanel(); - GroupLayout layout = new GroupLayout(itemProps); - itemProps.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel nameLabel = new JLabel("Name: "); - JLabel colorLabel = new JLabel("Color: "); - JLabel charLabel = new JLabel("Character: "); - nameField = new JTextField(15); - colorBox = new JComboBox(ColorFactory.getColorNames()); - colorBox.setBackground(Color.black); - colorBox.setRenderer(new ColorCellRenderer()); - colorBox.addActionListener(new ColorListener(colorBox)); - charField = new JFormattedTextField(getMaskFormatter("*", 'X')); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); - JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(colorLabel) - .addComponent(colorBox) - .addComponent(colorHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(charLabel) - .addComponent(charField) - .addComponent(charHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(colorLabel) - .addComponent(charLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(colorBox) - .addComponent(charField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(colorHelpLabel) - .addComponent(charHelpLabel))); - - JScrollPane propScroller = new JScrollPane(itemProps); - propScroller.setBorder(new TitledBorder("Properties")); - frame.add(propScroller, BorderLayout.LINE_START); - - model = new DefaultListModel(); - items = new JList(model); - items.addMouseListener(this); - JScrollPane itemScroller = new JScrollPane(items); - itemScroller.setBorder(new TitledBorder("Contents")); - frame.add(itemScroller, BorderLayout.CENTER); - } - - protected void save() { - data.name = nameField.getText(); - data.color = colorBox.getSelectedItem().toString(); - data.text = charField.getText(); - - data.contents.clear(); - for (Enumeration e = model.elements(); e.hasMoreElements(); ) { - RItem ri = e.nextElement(); - data.contents.add(ri.id); - } - - data.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - nameField.setText(data.name); - colorBox.setSelectedItem(data.color); - charField.setValue(data.text); - for (String id : data.contents) { - model.addElement((RItem) Editor.resources.getResource(id)); - } - } - - public void mouseExited(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mousePressed(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - JPopupMenu menu = new JPopupMenu(); - menu.add(new ItemListAction("Add item")); - menu.add(new ItemListAction("Delete item")); - menu.show(e.getComponent(), e.getX(), e.getY()); - items.setSelectedIndex(items.locationToIndex(e.getPoint())); - } - } - - @SuppressWarnings("serial") - private class ItemListAction extends AbstractAction { - public ItemListAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add item")) { - Object[] items = Editor.resources.getResources(RItem.class).toArray(); - RItem ri = - (RItem) - JOptionPane.showInputDialog( - frame, "Add item:", "Add item", JOptionPane.PLAIN_MESSAGE, null, items, 0); - model.addElement(ri); - } else if (e.getActionCommand().equals("Delete item")) { - model.remove(items.getSelectedIndex()); - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.awt.event.*; +import java.util.Enumeration; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.help.HelpLabels; +import neon.resources.RItem; +import neon.util.ColorFactory; + +public class ContainerEditor extends ObjectEditor implements MouseListener { + private JTextField nameField; + private JComboBox colorBox; + private JFormattedTextField charField; + private RItem.Container data; + private final DataStore dataStore; + private JList items; + private DefaultListModel model; + + public ContainerEditor(JFrame parent, RItem.Container data, DataStore dataStore) { + super(parent, "Container Editor: " + data.id); + frame.setPreferredSize(new Dimension(400, 200)); + this.data = data; + this.dataStore = dataStore; + JPanel itemProps = new JPanel(); + GroupLayout layout = new GroupLayout(itemProps); + itemProps.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel nameLabel = new JLabel("Name: "); + JLabel colorLabel = new JLabel("Color: "); + JLabel charLabel = new JLabel("Character: "); + nameField = new JTextField(15); + colorBox = new JComboBox(ColorFactory.getColorNames()); + colorBox.setBackground(Color.black); + colorBox.setRenderer(new ColorCellRenderer()); + colorBox.addActionListener(new ColorListener(colorBox)); + charField = new JFormattedTextField(getMaskFormatter("*", 'X')); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); + JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(colorLabel) + .addComponent(colorBox) + .addComponent(colorHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(charLabel) + .addComponent(charField) + .addComponent(charHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(colorLabel) + .addComponent(charLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(colorBox) + .addComponent(charField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(colorHelpLabel) + .addComponent(charHelpLabel))); + + JScrollPane propScroller = new JScrollPane(itemProps); + propScroller.setBorder(new TitledBorder("Properties")); + frame.add(propScroller, BorderLayout.LINE_START); + + model = new DefaultListModel(); + items = new JList(model); + items.addMouseListener(this); + JScrollPane itemScroller = new JScrollPane(items); + itemScroller.setBorder(new TitledBorder("Contents")); + frame.add(itemScroller, BorderLayout.CENTER); + } + + protected void save() { + data.name = nameField.getText(); + data.color = colorBox.getSelectedItem().toString(); + data.text = charField.getText(); + + data.contents.clear(); + for (Enumeration e = model.elements(); e.hasMoreElements(); ) { + RItem ri = e.nextElement(); + data.contents.add(ri.id); + } + + data.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + nameField.setText(data.name); + colorBox.setSelectedItem(data.color); + charField.setValue(data.text); + for (String id : data.contents) { + model.addElement((RItem) dataStore.getResourceManager().getResource(id)); + } + } + + public void mouseExited(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mousePressed(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + JPopupMenu menu = new JPopupMenu(); + menu.add(new ItemListAction("Add item")); + menu.add(new ItemListAction("Delete item")); + menu.show(e.getComponent(), e.getX(), e.getY()); + items.setSelectedIndex(items.locationToIndex(e.getPoint())); + } + } + + @SuppressWarnings("serial") + private class ItemListAction extends AbstractAction { + public ItemListAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add item")) { + Object[] items = dataStore.getResourceManager().getResources(RItem.class).toArray(); + RItem ri = + (RItem) + JOptionPane.showInputDialog( + frame, "Add item:", "Add item", JOptionPane.PLAIN_MESSAGE, null, items, 0); + model.addElement(ri); + } else if (e.getActionCommand().equals("Delete item")) { + model.remove(items.getSelectedIndex()); + } + } + } +} diff --git a/src/main/java/neon/editor/editors/CraftingEditor.java b/src/main/java/neon/editor/editors/CraftingEditor.java index 900eb07..3a6addf 100644 --- a/src/main/java/neon/editor/editors/CraftingEditor.java +++ b/src/main/java/neon/editor/editors/CraftingEditor.java @@ -1,121 +1,124 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.BorderLayout; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.resources.RCraft; -import neon.resources.RItem; - -public class CraftingEditor extends ObjectEditor { - private RCraft craft; - private JComboBox rawBox; - private JFormattedTextField costField, amountField; - - public CraftingEditor(JFrame parent, RCraft data) { - super(parent, "Crafting Editor: " + data.id); - craft = data; - - JPanel props = new JPanel(); - GroupLayout layout = new GroupLayout(props); - props.setLayout(layout); - layout.setAutoCreateGaps(true); - props.setBorder(new TitledBorder("Properties")); - - JLabel rawLabel = new JLabel("Raw material: "); - JLabel amountLabel = new JLabel("Amount: "); - JLabel costLabel = new JLabel("Cost: "); - rawBox = new JComboBox(Editor.resources.getResources(RItem.class)); - amountField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - JLabel rawHelpLabel = HelpLabels.getRawHelpLabel(); - JLabel amountHelpLabel = HelpLabels.getAmountHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCraftingCostHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(rawLabel) - .addComponent(rawBox) - .addComponent(rawHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(amountLabel) - .addComponent(amountField) - .addComponent(amountHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(costLabel) - .addComponent(costField) - .addComponent(costHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(rawLabel) - .addComponent(amountLabel) - .addComponent(costLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - rawBox, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(amountField) - .addComponent(costField)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - rawHelpLabel, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(amountHelpLabel) - .addComponent(costHelpLabel))); - - frame.add(props, BorderLayout.CENTER); - } - - protected void load() { - RItem raw = (RItem) Editor.resources.getResource(craft.raw); - rawBox.setSelectedItem(raw); - amountField.setValue(craft.amount); - costField.setValue(craft.cost); - } - - protected void save() { - craft.raw = ((RItem) rawBox.getSelectedItem()).id; - craft.cost = Integer.parseInt(costField.getText()); - craft.amount = Integer.parseInt(amountField.getText()); - craft.setPath(Editor.getStore().getActive().get("id")); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.BorderLayout; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.resources.RCraft; +import neon.resources.RItem; + +public class CraftingEditor extends ObjectEditor { + private RCraft craft; + private JComboBox rawBox; + private JFormattedTextField costField, amountField; + private final DataStore dataStore; + private final HelpLabels helpLabels; + + public CraftingEditor(JFrame parent, RCraft data, DataStore dataStore) { + super(parent, "Crafting Editor: " + data.id); + craft = data; + this.dataStore = dataStore; + helpLabels = new HelpLabels(dataStore); + JPanel props = new JPanel(); + GroupLayout layout = new GroupLayout(props); + props.setLayout(layout); + layout.setAutoCreateGaps(true); + props.setBorder(new TitledBorder("Properties")); + + JLabel rawLabel = new JLabel("Raw material: "); + JLabel amountLabel = new JLabel("Amount: "); + JLabel costLabel = new JLabel("Cost: "); + rawBox = new JComboBox(dataStore.getResourceManager().getResources(RItem.class)); + amountField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + JLabel rawHelpLabel = HelpLabels.getRawHelpLabel(); + JLabel amountHelpLabel = HelpLabels.getAmountHelpLabel(); + JLabel costHelpLabel = helpLabels.getCraftingCostHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(rawLabel) + .addComponent(rawBox) + .addComponent(rawHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(amountLabel) + .addComponent(amountField) + .addComponent(amountHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(costLabel) + .addComponent(costField) + .addComponent(costHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(rawLabel) + .addComponent(amountLabel) + .addComponent(costLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + rawBox, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(amountField) + .addComponent(costField)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + rawHelpLabel, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(amountHelpLabel) + .addComponent(costHelpLabel))); + + frame.add(props, BorderLayout.CENTER); + } + + protected void load() { + RItem raw = (RItem) dataStore.getResourceManager().getResource(craft.raw); + rawBox.setSelectedItem(raw); + amountField.setValue(craft.amount); + costField.setValue(craft.cost); + } + + protected void save() { + craft.raw = ((RItem) rawBox.getSelectedItem()).id; + craft.cost = Integer.parseInt(costField.getText()); + craft.amount = Integer.parseInt(amountField.getText()); + craft.setPath(dataStore.getActive().get("id")); + } +} diff --git a/src/main/java/neon/editor/editors/CreatureEditor.java b/src/main/java/neon/editor/editors/CreatureEditor.java index 227886b..97b4c7f 100644 --- a/src/main/java/neon/editor/editors/CreatureEditor.java +++ b/src/main/java/neon/editor/editors/CreatureEditor.java @@ -23,7 +23,7 @@ import javax.swing.*; import javax.swing.border.*; import neon.editor.ColorCellRenderer; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.NeonFormat; import neon.editor.help.HelpLabels; import neon.entities.property.Habitat; @@ -45,10 +45,12 @@ public class CreatureEditor extends ObjectEditor { private JFormattedTextField strField, conField, dexField, intField, wisField, chaField; private JComboBox aiTypeBox; private JSpinner aggressionSpinner, confidenceSpinner; + private final DataStore dataStore; - public CreatureEditor(JFrame parent, RCreature rCreature) { + public CreatureEditor(JFrame parent, RCreature rCreature, DataStore dataStore) { super(parent, "Creature Editor: " + rCreature.id); this.data = rCreature; + this.dataStore = dataStore; // algemeen JPanel propPanel = new JPanel(); @@ -399,7 +401,7 @@ protected void save() { data.aiAggr = (Integer) aggressionSpinner.getValue(); data.aiConf = (Integer) confidenceSpinner.getValue(); - data.setPath(Editor.getStore().getActive().get("id")); + data.setPath(dataStore.getActive().get("id")); } protected void load() { diff --git a/src/main/java/neon/editor/editors/DoorEditor.java b/src/main/java/neon/editor/editors/DoorEditor.java index 8494556..d44c96b 100644 --- a/src/main/java/neon/editor/editors/DoorEditor.java +++ b/src/main/java/neon/editor/editors/DoorEditor.java @@ -1,160 +1,162 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.ColorCellRenderer; -import neon.editor.Editor; -import neon.editor.help.HelpLabels; -import neon.resources.RItem; -import neon.util.ColorFactory; - -public class DoorEditor extends ObjectEditor { - private JTextField nameField; - private JComboBox colorBox; - private JFormattedTextField openField; - private JFormattedTextField closedField; - private JFormattedTextField lockedField; - private RItem.Door data; - - public DoorEditor(JFrame parent, RItem.Door data) { - super(parent, "Door Editor: " + data.id); - this.data = data; - - JPanel itemProps = new JPanel(); - GroupLayout layout = new GroupLayout(itemProps); - itemProps.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel nameLabel = new JLabel("Name: "); - JLabel colorLabel = new JLabel("Color: "); - JLabel openLabel = new JLabel("Open character: "); - JLabel closedLabel = new JLabel("Closed character: "); - JLabel lockedLabel = new JLabel("Locked character: "); - nameField = new JTextField(15); - colorBox = new JComboBox(ColorFactory.getColorNames()); - colorBox.setBackground(Color.black); - colorBox.setRenderer(new ColorCellRenderer()); - colorBox.addActionListener(new ColorListener(colorBox)); - openField = new JFormattedTextField(getMaskFormatter("*", 'X')); - lockedField = new JFormattedTextField(getMaskFormatter("*", ' ')); - closedField = new JFormattedTextField(getMaskFormatter("*", ' ')); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); - JLabel openHelpLabel = HelpLabels.getCharHelpLabel(); - JLabel closedHelpLabel = HelpLabels.getClosedHelpLabel(); - JLabel lockedHelpLabel = HelpLabels.getLockedHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(colorLabel) - .addComponent(colorBox) - .addComponent(colorHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(openLabel) - .addComponent(openField) - .addComponent(openHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(closedLabel) - .addComponent(closedField) - .addComponent(closedHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(lockedLabel) - .addComponent(lockedField) - .addComponent(lockedHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(colorLabel) - .addComponent(openLabel) - .addComponent(closedLabel) - .addComponent(lockedLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(colorBox) - .addComponent(openField) - .addComponent(closedField) - .addComponent(lockedField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(colorHelpLabel) - .addComponent(openHelpLabel) - .addComponent(closedHelpLabel) - .addComponent(lockedHelpLabel))); - - JScrollPane propScroller = new JScrollPane(itemProps); - propScroller.setBorder(new TitledBorder("Properties")); - frame.add(propScroller, BorderLayout.CENTER); - } - - protected void load() { - nameField.setText(data.name); - colorBox.setSelectedItem(data.color); - openField.setValue(data.text); - if (!data.text.equals(data.closed)) { - closedField.setValue(data.closed); - } - if (!data.locked.equals(data.closed)) { - lockedField.setValue(data.locked); - } - } - - protected void save() { - data.name = nameField.getText(); - data.color = colorBox.getSelectedItem().toString(); - data.text = openField.getText(); - if (!openField.getText().equals(closedField.getText())) { - data.closed = closedField.getText(); - } - if (!lockedField.getText().equals(closedField.getText())) { - data.locked = lockedField.getText(); - } - data.setPath(Editor.getStore().getActive().get("id")); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.help.HelpLabels; +import neon.resources.RItem; +import neon.util.ColorFactory; + +public class DoorEditor extends ObjectEditor { + private JTextField nameField; + private JComboBox colorBox; + private JFormattedTextField openField; + private JFormattedTextField closedField; + private JFormattedTextField lockedField; + private RItem.Door data; + private final DataStore dataStore; + + public DoorEditor(JFrame parent, RItem.Door data, DataStore dataStore) { + super(parent, "Door Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + + JPanel itemProps = new JPanel(); + GroupLayout layout = new GroupLayout(itemProps); + itemProps.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel nameLabel = new JLabel("Name: "); + JLabel colorLabel = new JLabel("Color: "); + JLabel openLabel = new JLabel("Open character: "); + JLabel closedLabel = new JLabel("Closed character: "); + JLabel lockedLabel = new JLabel("Locked character: "); + nameField = new JTextField(15); + colorBox = new JComboBox(ColorFactory.getColorNames()); + colorBox.setBackground(Color.black); + colorBox.setRenderer(new ColorCellRenderer()); + colorBox.addActionListener(new ColorListener(colorBox)); + openField = new JFormattedTextField(getMaskFormatter("*", 'X')); + lockedField = new JFormattedTextField(getMaskFormatter("*", ' ')); + closedField = new JFormattedTextField(getMaskFormatter("*", ' ')); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); + JLabel openHelpLabel = HelpLabels.getCharHelpLabel(); + JLabel closedHelpLabel = HelpLabels.getClosedHelpLabel(); + JLabel lockedHelpLabel = HelpLabels.getLockedHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(colorLabel) + .addComponent(colorBox) + .addComponent(colorHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(openLabel) + .addComponent(openField) + .addComponent(openHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(closedLabel) + .addComponent(closedField) + .addComponent(closedHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(lockedLabel) + .addComponent(lockedField) + .addComponent(lockedHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(colorLabel) + .addComponent(openLabel) + .addComponent(closedLabel) + .addComponent(lockedLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(colorBox) + .addComponent(openField) + .addComponent(closedField) + .addComponent(lockedField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(colorHelpLabel) + .addComponent(openHelpLabel) + .addComponent(closedHelpLabel) + .addComponent(lockedHelpLabel))); + + JScrollPane propScroller = new JScrollPane(itemProps); + propScroller.setBorder(new TitledBorder("Properties")); + frame.add(propScroller, BorderLayout.CENTER); + } + + protected void load() { + nameField.setText(data.name); + colorBox.setSelectedItem(data.color); + openField.setValue(data.text); + if (!data.text.equals(data.closed)) { + closedField.setValue(data.closed); + } + if (!data.locked.equals(data.closed)) { + lockedField.setValue(data.locked); + } + } + + protected void save() { + data.name = nameField.getText(); + data.color = colorBox.getSelectedItem().toString(); + data.text = openField.getText(); + if (!openField.getText().equals(closedField.getText())) { + data.closed = closedField.getText(); + } + if (!lockedField.getText().equals(closedField.getText())) { + data.locked = lockedField.getText(); + } + data.setPath(dataStore.getActive().get("id")); + } +} diff --git a/src/main/java/neon/editor/editors/DungeonThemeEditor.java b/src/main/java/neon/editor/editors/DungeonThemeEditor.java index 4fe9b66..cb564fe 100644 --- a/src/main/java/neon/editor/editors/DungeonThemeEditor.java +++ b/src/main/java/neon/editor/editors/DungeonThemeEditor.java @@ -1,132 +1,134 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.resources.RDungeonTheme; - -public class DungeonThemeEditor extends ObjectEditor { - private JTextField zoneField; - private JFormattedTextField minField, maxField, branchField; - private RDungeonTheme theme; - - public DungeonThemeEditor(JFrame parent, RDungeonTheme theme) { - super(parent, "Dungeon theme: " + theme.id); - this.theme = theme; - - JPanel props = new JPanel(); - GroupLayout layout = new GroupLayout(props); - props.setLayout(layout); - layout.setAutoCreateGaps(true); - props.setBorder(new TitledBorder("Properties")); - zoneField = new JTextField(15); - minField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - maxField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - branchField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - JLabel zoneLabel = new JLabel("Zones: "); - JLabel minLabel = new JLabel("Min. zones: "); - JLabel maxLabel = new JLabel("Max. zones: "); - JLabel branchLabel = new JLabel("Branch factor: "); - JLabel zoneHelpLabel = HelpLabels.getZoneHelpLabel(); - JLabel minHelpLabel = HelpLabels.getMinZoneHelpLabel(); - JLabel maxHelpLabel = HelpLabels.getMaxZoneHelpLabel(); - JLabel branchHelpLabel = HelpLabels.getBranchHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(zoneLabel) - .addComponent(zoneField) - .addComponent(zoneHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(minLabel) - .addComponent(minField) - .addComponent(minHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(maxLabel) - .addComponent(maxField) - .addComponent(maxHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(branchLabel) - .addComponent(branchField) - .addComponent(branchHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(zoneLabel) - .addComponent(minLabel) - .addComponent(maxLabel) - .addComponent( - branchLabel, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - zoneField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(minField) - .addComponent(maxField) - .addComponent(branchField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(zoneHelpLabel) - .addComponent(minHelpLabel) - .addComponent(maxHelpLabel) - .addComponent(branchHelpLabel))); - frame.add(props, BorderLayout.CENTER); - } - - protected void save() { - theme.min = Integer.parseInt(minField.getText()); - theme.max = Integer.parseInt(maxField.getText()); - theme.branching = Integer.parseInt(branchField.getText()); - theme.zones = zoneField.getText(); - theme.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - zoneField.setText(theme.zones); - minField.setValue(theme.min); - maxField.setValue(theme.max); - branchField.setValue(theme.branching); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.resources.RDungeonTheme; + +public class DungeonThemeEditor extends ObjectEditor { + private JTextField zoneField; + private JFormattedTextField minField, maxField, branchField; + private RDungeonTheme theme; + private final DataStore dataStore; + + public DungeonThemeEditor(JFrame parent, RDungeonTheme theme, DataStore dataStore) { + super(parent, "Dungeon theme: " + theme.id); + this.theme = theme; + this.dataStore = dataStore; + + JPanel props = new JPanel(); + GroupLayout layout = new GroupLayout(props); + props.setLayout(layout); + layout.setAutoCreateGaps(true); + props.setBorder(new TitledBorder("Properties")); + zoneField = new JTextField(15); + minField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + maxField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + branchField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + JLabel zoneLabel = new JLabel("Zones: "); + JLabel minLabel = new JLabel("Min. zones: "); + JLabel maxLabel = new JLabel("Max. zones: "); + JLabel branchLabel = new JLabel("Branch factor: "); + JLabel zoneHelpLabel = HelpLabels.getZoneHelpLabel(); + JLabel minHelpLabel = HelpLabels.getMinZoneHelpLabel(); + JLabel maxHelpLabel = HelpLabels.getMaxZoneHelpLabel(); + JLabel branchHelpLabel = HelpLabels.getBranchHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(zoneLabel) + .addComponent(zoneField) + .addComponent(zoneHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(minLabel) + .addComponent(minField) + .addComponent(minHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(maxLabel) + .addComponent(maxField) + .addComponent(maxHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(branchLabel) + .addComponent(branchField) + .addComponent(branchHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(zoneLabel) + .addComponent(minLabel) + .addComponent(maxLabel) + .addComponent( + branchLabel, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + zoneField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(minField) + .addComponent(maxField) + .addComponent(branchField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(zoneHelpLabel) + .addComponent(minHelpLabel) + .addComponent(maxHelpLabel) + .addComponent(branchHelpLabel))); + frame.add(props, BorderLayout.CENTER); + } + + protected void save() { + theme.min = Integer.parseInt(minField.getText()); + theme.max = Integer.parseInt(maxField.getText()); + theme.branching = Integer.parseInt(branchField.getText()); + theme.zones = zoneField.getText(); + theme.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + zoneField.setText(theme.zones); + minField.setValue(theme.min); + maxField.setValue(theme.max); + branchField.setValue(theme.branching); + } +} diff --git a/src/main/java/neon/editor/editors/EnchantmentEditor.java b/src/main/java/neon/editor/editors/EnchantmentEditor.java index cc7cac3..1f0f5e3 100644 --- a/src/main/java/neon/editor/editors/EnchantmentEditor.java +++ b/src/main/java/neon/editor/editors/EnchantmentEditor.java @@ -1,194 +1,196 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.awt.event.*; -import java.util.Vector; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.magic.Effect; -import neon.resources.RSpell; - -public class EnchantmentEditor extends ObjectEditor implements ActionListener { - private JTextField nameField; - private JFormattedTextField areaField, sizeField, durationField; - private JComboBox effectBox; - private JComboBox itemBox; - private JTextArea scriptArea; - private RSpell.Enchantment data; - - public EnchantmentEditor(JFrame parent, RSpell.Enchantment data) { - super(parent, "Enchantment: " + data.id); - this.data = data; - - JPanel props = new JPanel(); - GroupLayout layout = new GroupLayout(props); - props.setLayout(layout); - layout.setAutoCreateGaps(true); - props.setBorder(new TitledBorder("Properties")); - - JLabel nameLabel = new JLabel("Name: "); - JLabel itemLabel = new JLabel("Item type: "); - JLabel effectLabel = new JLabel("Effect: "); - JLabel sizeLabel = new JLabel("Magnitude: "); - JLabel areaLabel = new JLabel("Radius: "); - JLabel durationLabel = new JLabel("Duration: "); - nameField = new JTextField(15); - itemBox = new JComboBox(getTypes()); - itemBox.addActionListener(this); - effectBox = new JComboBox(Effect.values()); - effectBox.addActionListener(this); - areaField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - sizeField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - durationField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - scriptArea = new JTextArea(); - scriptArea.setDisabledTextColor(Color.red); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel itemHelpLabel = HelpLabels.getItemHelpLabel(); - JLabel effectHelpLabel = HelpLabels.getEffectHelpLabel(); - JLabel sizeHelpLabel = HelpLabels.getSpellSizeHelpLabel(); - JLabel areaHelpLabel = HelpLabels.getSpellRadiusHelpLabel(); - JLabel durationHelpLabel = HelpLabels.getDurationHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(itemLabel) - .addComponent(itemBox) - .addComponent(itemHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(effectLabel) - .addComponent(effectBox) - .addComponent(effectHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(sizeLabel) - .addComponent(sizeField) - .addComponent(sizeHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(areaLabel) - .addComponent(areaField) - .addComponent(areaHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(durationLabel) - .addComponent(durationField) - .addComponent(durationHelpLabel)) - .addGap(10)); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(itemLabel) - .addComponent(effectLabel) - .addComponent(sizeLabel) - .addComponent(areaLabel) - .addComponent(durationLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameField) - .addComponent(itemBox) - .addComponent( - effectBox, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(sizeField) - .addComponent(areaField) - .addComponent(durationField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(itemHelpLabel) - .addComponent(effectHelpLabel) - .addComponent(sizeHelpLabel) - .addComponent(areaHelpLabel) - .addComponent(durationHelpLabel))); - frame.add(props, BorderLayout.PAGE_START); - - scriptArea = new JTextArea(6, 0); - scriptArea.setDisabledTextColor(Color.red); - JScrollPane scriptScroller = new JScrollPane(scriptArea); - scriptScroller.setBorder(new TitledBorder("Script")); - frame.add(scriptScroller, BorderLayout.CENTER); - } - - private Vector getTypes() { - Vector types = new Vector(); - types.add("clothing"); - types.add("trap"); - types.add("nutrition"); - types.add("weapon"); - return types; - } - - protected void load() { - nameField.setText(data.name); - itemBox.setSelectedItem(data.item); - effectBox.setSelectedItem(data.effect); - sizeField.setValue(data.size); - durationField.setValue(data.duration); - areaField.setValue(data.radius); - scriptArea.setText(data.script); - scriptArea.setEditable(data.effect == Effect.SCRIPTED); - } - - protected void save() { - data.name = nameField.getText(); - data.item = itemBox.getSelectedItem().toString(); - data.size = Integer.parseInt(sizeField.getText()); - data.radius = Integer.parseInt(areaField.getText()); - data.effect = effectBox.getItemAt(effectBox.getSelectedIndex()); - data.duration = Integer.parseInt(durationField.getText()); - data.script = scriptArea.getText(); - data.setPath(Editor.getStore().getActive().get("id")); - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource().equals(effectBox)) { - scriptArea.setEditable(effectBox.getSelectedItem() == Effect.SCRIPTED); - } else if (e.getSource().equals(itemBox)) { - - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.awt.event.*; +import java.util.Vector; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.magic.Effect; +import neon.resources.RSpell; + +public class EnchantmentEditor extends ObjectEditor implements ActionListener { + private JTextField nameField; + private JFormattedTextField areaField, sizeField, durationField; + private JComboBox effectBox; + private JComboBox itemBox; + private JTextArea scriptArea; + private RSpell.Enchantment data; + private final DataStore dataStore; + + public EnchantmentEditor(JFrame parent, RSpell.Enchantment data, DataStore dataStore) { + super(parent, "Enchantment: " + data.id); + this.data = data; + this.dataStore = dataStore; + + JPanel props = new JPanel(); + GroupLayout layout = new GroupLayout(props); + props.setLayout(layout); + layout.setAutoCreateGaps(true); + props.setBorder(new TitledBorder("Properties")); + + JLabel nameLabel = new JLabel("Name: "); + JLabel itemLabel = new JLabel("Item type: "); + JLabel effectLabel = new JLabel("Effect: "); + JLabel sizeLabel = new JLabel("Magnitude: "); + JLabel areaLabel = new JLabel("Radius: "); + JLabel durationLabel = new JLabel("Duration: "); + nameField = new JTextField(15); + itemBox = new JComboBox(getTypes()); + itemBox.addActionListener(this); + effectBox = new JComboBox(Effect.values()); + effectBox.addActionListener(this); + areaField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + sizeField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + durationField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + scriptArea = new JTextArea(); + scriptArea.setDisabledTextColor(Color.red); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel itemHelpLabel = HelpLabels.getItemHelpLabel(); + JLabel effectHelpLabel = HelpLabels.getEffectHelpLabel(); + JLabel sizeHelpLabel = HelpLabels.getSpellSizeHelpLabel(); + JLabel areaHelpLabel = HelpLabels.getSpellRadiusHelpLabel(); + JLabel durationHelpLabel = HelpLabels.getDurationHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(itemLabel) + .addComponent(itemBox) + .addComponent(itemHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(effectLabel) + .addComponent(effectBox) + .addComponent(effectHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(sizeLabel) + .addComponent(sizeField) + .addComponent(sizeHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(areaLabel) + .addComponent(areaField) + .addComponent(areaHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(durationLabel) + .addComponent(durationField) + .addComponent(durationHelpLabel)) + .addGap(10)); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(itemLabel) + .addComponent(effectLabel) + .addComponent(sizeLabel) + .addComponent(areaLabel) + .addComponent(durationLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameField) + .addComponent(itemBox) + .addComponent( + effectBox, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(sizeField) + .addComponent(areaField) + .addComponent(durationField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(itemHelpLabel) + .addComponent(effectHelpLabel) + .addComponent(sizeHelpLabel) + .addComponent(areaHelpLabel) + .addComponent(durationHelpLabel))); + frame.add(props, BorderLayout.PAGE_START); + + scriptArea = new JTextArea(6, 0); + scriptArea.setDisabledTextColor(Color.red); + JScrollPane scriptScroller = new JScrollPane(scriptArea); + scriptScroller.setBorder(new TitledBorder("Script")); + frame.add(scriptScroller, BorderLayout.CENTER); + } + + private Vector getTypes() { + Vector types = new Vector(); + types.add("clothing"); + types.add("trap"); + types.add("nutrition"); + types.add("weapon"); + return types; + } + + protected void load() { + nameField.setText(data.name); + itemBox.setSelectedItem(data.item); + effectBox.setSelectedItem(data.effect); + sizeField.setValue(data.size); + durationField.setValue(data.duration); + areaField.setValue(data.radius); + scriptArea.setText(data.script); + scriptArea.setEditable(data.effect == Effect.SCRIPTED); + } + + protected void save() { + data.name = nameField.getText(); + data.item = itemBox.getSelectedItem().toString(); + data.size = Integer.parseInt(sizeField.getText()); + data.radius = Integer.parseInt(areaField.getText()); + data.effect = effectBox.getItemAt(effectBox.getSelectedIndex()); + data.duration = Integer.parseInt(durationField.getText()); + data.script = scriptArea.getText(); + data.setPath(dataStore.getActive().get("id")); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource().equals(effectBox)) { + scriptArea.setEditable(effectBox.getSelectedItem() == Effect.SCRIPTED); + } else if (e.getSource().equals(itemBox)) { + + } + } +} diff --git a/src/main/java/neon/editor/editors/FactionEditor.java b/src/main/java/neon/editor/editors/FactionEditor.java index 0548d2b..e3e468c 100644 --- a/src/main/java/neon/editor/editors/FactionEditor.java +++ b/src/main/java/neon/editor/editors/FactionEditor.java @@ -1,53 +1,55 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.BorderLayout; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import neon.editor.Editor; -import neon.editor.help.HelpLabels; -import neon.editor.resources.RFaction; - -public class FactionEditor extends ObjectEditor { - private RFaction faction; - private JTextField nameField; - - public FactionEditor(JFrame parent, RFaction data) { - super(parent, "Faction Editor: " + data.id); - faction = data; - - JPanel props = new JPanel(); - props.add(new JLabel("Name: ")); - nameField = new JTextField(15); - props.add(nameField); - props.add(HelpLabels.getNameHelpLabel()); - props.setBorder(new TitledBorder("Properties")); - frame.add(props, BorderLayout.CENTER); - } - - protected void save() { - faction.name = nameField.getText(); - faction.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - nameField.setText(faction.name); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.BorderLayout; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import neon.editor.DataStore; +import neon.editor.help.HelpLabels; +import neon.editor.resources.RFaction; + +public class FactionEditor extends ObjectEditor { + private RFaction faction; + private JTextField nameField; + private final DataStore dataStore; + + public FactionEditor(JFrame parent, RFaction data, DataStore dataStore) { + super(parent, "Faction Editor: " + data.id); + faction = data; + this.dataStore = dataStore; + + JPanel props = new JPanel(); + props.add(new JLabel("Name: ")); + nameField = new JTextField(15); + props.add(nameField); + props.add(HelpLabels.getNameHelpLabel()); + props.setBorder(new TitledBorder("Properties")); + frame.add(props, BorderLayout.CENTER); + } + + protected void save() { + faction.name = nameField.getText(); + faction.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + nameField.setText(faction.name); + } +} diff --git a/src/main/java/neon/editor/editors/FoodEditor.java b/src/main/java/neon/editor/editors/FoodEditor.java index ce85bda..db05dd0 100644 --- a/src/main/java/neon/editor/editors/FoodEditor.java +++ b/src/main/java/neon/editor/editors/FoodEditor.java @@ -1,184 +1,190 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.text.ParseException; -import java.util.*; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.*; -import neon.editor.help.HelpLabels; -import neon.resources.RItem; -import neon.resources.RSpell; -import neon.util.ColorFactory; - -public class FoodEditor extends ObjectEditor { - private JTextField nameField; - private JFormattedTextField costField, weightField, charField; - private JComboBox colorBox, spellBox; - private RItem data; - - public FoodEditor(JFrame parent, RItem data) { - super(parent, "Scroll Editor: " + data.id); - this.data = data; - - JPanel itemProps = new JPanel(); - GroupLayout layout = new GroupLayout(itemProps); - itemProps.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel nameLabel = new JLabel("Name: "); - JLabel costLabel = new JLabel("Cost: "); - JLabel colorLabel = new JLabel("Color: "); - JLabel charLabel = new JLabel("Character: "); - JLabel weightLabel = new JLabel("Weight: "); - JLabel spellLabel = new JLabel("Spell: "); - nameField = new JTextField(15); - costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - colorBox = new JComboBox(ColorFactory.getColorNames()); - colorBox.setBackground(Color.black); - colorBox.setRenderer(new ColorCellRenderer()); - colorBox.addActionListener(new ColorListener(colorBox)); - charField = new JFormattedTextField(getMaskFormatter("*", 'X')); - weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); - spellBox = new JComboBox(loadSpells()); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCostHelpLabel(); - JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); - JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); - JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); - JLabel foodHelpLabel = HelpLabels.getFoodEffectHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(costLabel) - .addComponent(costField) - .addComponent(costHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(colorLabel) - .addComponent(colorBox) - .addComponent(colorHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(charLabel) - .addComponent(charField) - .addComponent(charHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(weightLabel) - .addComponent(weightField) - .addComponent(weightHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(spellLabel) - .addComponent(spellBox) - .addComponent(foodHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(costLabel) - .addComponent(colorLabel) - .addComponent(charLabel) - .addComponent(weightLabel) - .addComponent(spellLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(costField) - .addComponent(colorBox) - .addComponent(charField) - .addComponent(weightField) - .addComponent(spellBox)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(costHelpLabel) - .addComponent(colorHelpLabel) - .addComponent(charHelpLabel) - .addComponent(weightHelpLabel) - .addComponent(foodHelpLabel))); - - JScrollPane propScroller = new JScrollPane(itemProps); - propScroller.setBorder(new TitledBorder("Properties")); - frame.add(propScroller, BorderLayout.CENTER); - } - - protected void save() { - data.name = nameField.getText(); - try { - costField.commitEdit(); - data.cost = ((Long) costField.getValue()).intValue(); - } catch (ParseException e) { - data.cost = 0; - } - data.color = colorBox.getSelectedItem().toString(); - data.text = charField.getText(); - data.weight = Float.parseFloat(weightField.getText()); - if (spellBox.getSelectedItem() != null) { - data.spell = spellBox.getSelectedItem().toString(); - } - data.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - nameField.setText(data.name); - costField.setValue(data.cost); - colorBox.setSelectedItem(data.color); - charField.setValue(data.text); - weightField.setValue(data.weight); - spellBox.setSelectedItem(data.spell); - } - - private Vector loadSpells() { - Vector spells = new Vector(); - spells.add(null); - for (RSpell.Enchantment spell : Editor.resources.getResources(RSpell.Enchantment.class)) { - if (spell.item.equals("nutrition")) { - spells.add(spell.id); - } - } - return spells; - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.text.ParseException; +import java.util.*; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.resources.RItem; +import neon.resources.RSpell; +import neon.util.ColorFactory; + +public class FoodEditor extends ObjectEditor { + private JTextField nameField; + private JFormattedTextField costField, weightField, charField; + private JComboBox colorBox, spellBox; + private RItem data; + private final DataStore dataStore; + private final HelpLabels helpLabels; + + public FoodEditor(JFrame parent, RItem data, DataStore dataStore) { + super(parent, "Scroll Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + helpLabels = new HelpLabels(dataStore); + JPanel itemProps = new JPanel(); + GroupLayout layout = new GroupLayout(itemProps); + itemProps.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel nameLabel = new JLabel("Name: "); + JLabel costLabel = new JLabel("Cost: "); + JLabel colorLabel = new JLabel("Color: "); + JLabel charLabel = new JLabel("Character: "); + JLabel weightLabel = new JLabel("Weight: "); + JLabel spellLabel = new JLabel("Spell: "); + nameField = new JTextField(15); + costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + colorBox = new JComboBox(ColorFactory.getColorNames()); + colorBox.setBackground(Color.black); + colorBox.setRenderer(new ColorCellRenderer()); + colorBox.addActionListener(new ColorListener(colorBox)); + charField = new JFormattedTextField(getMaskFormatter("*", 'X')); + weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); + spellBox = new JComboBox(loadSpells()); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel costHelpLabel = helpLabels.getCostHelpLabel(); + JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); + JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); + JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); + JLabel foodHelpLabel = HelpLabels.getFoodEffectHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(costLabel) + .addComponent(costField) + .addComponent(costHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(colorLabel) + .addComponent(colorBox) + .addComponent(colorHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(charLabel) + .addComponent(charField) + .addComponent(charHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(weightLabel) + .addComponent(weightField) + .addComponent(weightHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(spellLabel) + .addComponent(spellBox) + .addComponent(foodHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(costLabel) + .addComponent(colorLabel) + .addComponent(charLabel) + .addComponent(weightLabel) + .addComponent(spellLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(costField) + .addComponent(colorBox) + .addComponent(charField) + .addComponent(weightField) + .addComponent(spellBox)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(costHelpLabel) + .addComponent(colorHelpLabel) + .addComponent(charHelpLabel) + .addComponent(weightHelpLabel) + .addComponent(foodHelpLabel))); + + JScrollPane propScroller = new JScrollPane(itemProps); + propScroller.setBorder(new TitledBorder("Properties")); + frame.add(propScroller, BorderLayout.CENTER); + } + + protected void save() { + data.name = nameField.getText(); + try { + costField.commitEdit(); + data.cost = ((Long) costField.getValue()).intValue(); + } catch (ParseException e) { + data.cost = 0; + } + data.color = colorBox.getSelectedItem().toString(); + data.text = charField.getText(); + data.weight = Float.parseFloat(weightField.getText()); + if (spellBox.getSelectedItem() != null) { + data.spell = spellBox.getSelectedItem().toString(); + } + data.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + nameField.setText(data.name); + costField.setValue(data.cost); + colorBox.setSelectedItem(data.color); + charField.setValue(data.text); + weightField.setValue(data.weight); + spellBox.setSelectedItem(data.spell); + } + + private Vector loadSpells() { + Vector spells = new Vector(); + spells.add(null); + for (RSpell.Enchantment spell : + dataStore.getResourceManager().getResources(RSpell.Enchantment.class)) { + if (spell.item.equals("nutrition")) { + spells.add(spell.id); + } + } + return spells; + } +} diff --git a/src/main/java/neon/editor/editors/ItemEditor.java b/src/main/java/neon/editor/editors/ItemEditor.java index 87ed694..3121eaa 100644 --- a/src/main/java/neon/editor/editors/ItemEditor.java +++ b/src/main/java/neon/editor/editors/ItemEditor.java @@ -22,7 +22,7 @@ import javax.swing.*; import javax.swing.border.*; import neon.editor.ColorCellRenderer; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.NeonFormat; import neon.editor.help.HelpLabels; import neon.resources.RItem; @@ -36,11 +36,14 @@ public class ItemEditor extends ObjectEditor { private JCheckBox aidBox, topBox, svgBox; private JFormattedTextField costField, weightField, charField; private RItem data; + private final DataStore dataStore; + private final HelpLabels helpLabels; - public ItemEditor(JFrame parent, RItem data) { + public ItemEditor(JFrame parent, RItem data, DataStore dataStore) { super(parent, "Item Editor: " + data.id); this.data = data; - + this.dataStore = dataStore; + helpLabels = new HelpLabels(dataStore); JPanel itemProps = new JPanel(); GroupLayout layout = new GroupLayout(itemProps); itemProps.setLayout(layout); @@ -66,7 +69,7 @@ public ItemEditor(JFrame parent, RItem data) { topBox = new JCheckBox(); svgBox = new JCheckBox(); JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCostHelpLabel(); + JLabel costHelpLabel = helpLabels.getCostHelpLabel(); JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); @@ -196,7 +199,7 @@ protected void save() { data.name = nameField.getText(); data.cost = Integer.parseInt(costField.getText()); data.weight = Float.parseFloat(weightField.getText()); - data.setPath(Editor.getStore().getActive().get("id")); + data.setPath(dataStore.getActive().get("id")); data.top = topBox.isSelected(); if (svgBox.isSelected()) { data.svg = svgArea.getText(); diff --git a/src/main/java/neon/editor/editors/LevelCreatureEditor.java b/src/main/java/neon/editor/editors/LevelCreatureEditor.java index 2240e9e..a95e769 100644 --- a/src/main/java/neon/editor/editors/LevelCreatureEditor.java +++ b/src/main/java/neon/editor/editors/LevelCreatureEditor.java @@ -1,139 +1,141 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012-2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.*; -import java.util.*; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import javax.swing.table.DefaultTableModel; -import neon.editor.Editor; -import neon.resources.LCreature; -import neon.resources.RCreature; - -public class LevelCreatureEditor extends ObjectEditor implements MouseListener { - private LCreature data; - private JTable table; - private DefaultTableModel model; - - @SuppressWarnings("serial") - public LevelCreatureEditor(JFrame parent, LCreature data) { - super(parent, "Leveled Creature Editor: " + data.id); - this.data = data; - - // help - JLabel help = - new JLabel( - "Right click on the list to add or delete " - + "a creature. A creature will start showing up when the player " - + "is at the indicated level."); - help.setBorder(new TitledBorder("Instructions")); - - // tabel - String[] columns = {"id", "level"}; - model = new DefaultTableModel(columns, 0); - table = - new JTable(model) { - public boolean isCellEditable(int rowIndex, int vColIndex) { - return vColIndex == 1; - } - }; - table.addMouseListener(this); - table.getTableHeader().addMouseListener(this); - JScrollPane scroller = new JScrollPane(table); - - frame.add(help, BorderLayout.PAGE_START); - frame.add(scroller, BorderLayout.CENTER); - frame.setPreferredSize(new Dimension(400, 400)); - } - - protected void save() { - data.creatures.clear(); - for (int i = 0; i < table.getModel().getRowCount(); i++) { - data.creatures.put( - (String) table.getModel().getValueAt(i, 0), - Integer.parseInt(table.getModel().getValueAt(i, 1).toString())); - } - data.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - for (String s : data.creatures.keySet()) { - Object[] row = {s, data.creatures.get(s)}; - model.addRow(row); - } - } - - public void mouseExited(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mousePressed(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - int rowNumber = table.rowAtPoint(e.getPoint()); - ListSelectionModel model = table.getSelectionModel(); - model.setSelectionInterval(rowNumber, rowNumber); - - JPopupMenu menu = new JPopupMenu(); - menu.add(new ClickAction("Delete creature")); - menu.add(new ClickAction("Add creature")); - menu.show(e.getComponent(), e.getX(), e.getY()); - } - } - - @SuppressWarnings("serial") - public class ClickAction extends AbstractAction { - public ClickAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add creature")) { - ArrayList creatures = new ArrayList(); - for (RCreature rc : Editor.resources.getResources(RCreature.class)) { - if (!rc.id.equals(data.id)) { // levelled creature niet in zichzelf steken - creatures.add(rc.id); - } - } - String s = - (String) - JOptionPane.showInputDialog( - frame, - "Choose creature:", - "Add creature", - JOptionPane.PLAIN_MESSAGE, - null, - creatures.toArray(), - 0); - if ((s != null) && (s.length() > 0)) { - String[] creature = {s, "0"}; - model.addRow(creature); - } - } else if (e.getActionCommand().equals("Delete creature")) { - model.removeRow(table.getSelectedRow()); - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012-2013 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.swing.table.DefaultTableModel; +import neon.editor.DataStore; +import neon.resources.LCreature; +import neon.resources.RCreature; + +public class LevelCreatureEditor extends ObjectEditor implements MouseListener { + private LCreature data; + private final DataStore dataStore; + private JTable table; + private DefaultTableModel model; + + @SuppressWarnings("serial") + public LevelCreatureEditor(JFrame parent, LCreature data, DataStore dataStore) { + super(parent, "Leveled Creature Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + + // help + JLabel help = + new JLabel( + "Right click on the list to add or delete " + + "a creature. A creature will start showing up when the player " + + "is at the indicated level."); + help.setBorder(new TitledBorder("Instructions")); + + // tabel + String[] columns = {"id", "level"}; + model = new DefaultTableModel(columns, 0); + table = + new JTable(model) { + public boolean isCellEditable(int rowIndex, int vColIndex) { + return vColIndex == 1; + } + }; + table.addMouseListener(this); + table.getTableHeader().addMouseListener(this); + JScrollPane scroller = new JScrollPane(table); + + frame.add(help, BorderLayout.PAGE_START); + frame.add(scroller, BorderLayout.CENTER); + frame.setPreferredSize(new Dimension(400, 400)); + } + + protected void save() { + data.creatures.clear(); + for (int i = 0; i < table.getModel().getRowCount(); i++) { + data.creatures.put( + (String) table.getModel().getValueAt(i, 0), + Integer.parseInt(table.getModel().getValueAt(i, 1).toString())); + } + data.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + for (String s : data.creatures.keySet()) { + Object[] row = {s, data.creatures.get(s)}; + model.addRow(row); + } + } + + public void mouseExited(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mousePressed(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + int rowNumber = table.rowAtPoint(e.getPoint()); + ListSelectionModel model = table.getSelectionModel(); + model.setSelectionInterval(rowNumber, rowNumber); + + JPopupMenu menu = new JPopupMenu(); + menu.add(new ClickAction("Delete creature")); + menu.add(new ClickAction("Add creature")); + menu.show(e.getComponent(), e.getX(), e.getY()); + } + } + + @SuppressWarnings("serial") + public class ClickAction extends AbstractAction { + public ClickAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add creature")) { + ArrayList creatures = new ArrayList(); + for (RCreature rc : dataStore.getResourceManager().getResources(RCreature.class)) { + if (!rc.id.equals(data.id)) { // levelled creature niet in zichzelf steken + creatures.add(rc.id); + } + } + String s = + (String) + JOptionPane.showInputDialog( + frame, + "Choose creature:", + "Add creature", + JOptionPane.PLAIN_MESSAGE, + null, + creatures.toArray(), + 0); + if ((s != null) && (s.length() > 0)) { + String[] creature = {s, "0"}; + model.addRow(creature); + } + } else if (e.getActionCommand().equals("Delete creature")) { + model.removeRow(table.getSelectedRow()); + } + } + } +} diff --git a/src/main/java/neon/editor/editors/LevelItemEditor.java b/src/main/java/neon/editor/editors/LevelItemEditor.java index 6c9c54d..6b686e1 100644 --- a/src/main/java/neon/editor/editors/LevelItemEditor.java +++ b/src/main/java/neon/editor/editors/LevelItemEditor.java @@ -1,139 +1,141 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012-2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.*; -import java.util.*; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import javax.swing.table.DefaultTableModel; -import neon.editor.Editor; -import neon.resources.LItem; -import neon.resources.RItem; - -public class LevelItemEditor extends ObjectEditor implements MouseListener { - private LItem data; - private JTable table; - private DefaultTableModel model; - - @SuppressWarnings("serial") - public LevelItemEditor(JFrame parent, LItem data) { - super(parent, "Leveled Item Editor: " + data.id); - this.data = data; - - // help - JLabel help = - new JLabel( - "Right click on the list to add or " - + "delete an item. An item will start showing up when the " - + "player is at the indicated level."); - help.setBorder(new TitledBorder("Instructions")); - - // tabel - String[] columns = {"id", "level"}; - model = new DefaultTableModel(columns, 0); - table = - new JTable(model) { - public boolean isCellEditable(int rowIndex, int colIndex) { - return colIndex == 1; - } - }; - table.addMouseListener(this); - table.getTableHeader().addMouseListener(this); - JScrollPane scroller = new JScrollPane(table); - - frame.add(help, BorderLayout.PAGE_START); - frame.add(scroller, BorderLayout.CENTER); - frame.setPreferredSize(new Dimension(400, 400)); - } - - protected void save() { - data.items.clear(); - for (int i = 0; i < table.getModel().getRowCount(); i++) { - data.items.put( - (String) table.getModel().getValueAt(i, 0), - Integer.parseInt(table.getModel().getValueAt(i, 1).toString())); - } - data.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - for (String s : data.items.keySet()) { - Object[] row = {s, data.items.get(s)}; - model.addRow(row); - } - } - - public void mouseExited(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mousePressed(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - int rowNumber = table.rowAtPoint(e.getPoint()); - ListSelectionModel model = table.getSelectionModel(); - model.setSelectionInterval(rowNumber, rowNumber); - - JPopupMenu menu = new JPopupMenu(); - menu.add(new ClickAction("Delete item")); - menu.add(new ClickAction("Add item")); - menu.show(e.getComponent(), e.getX(), e.getY()); - } - } - - @SuppressWarnings("serial") - public class ClickAction extends AbstractAction { - public ClickAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add item")) { - ArrayList items = new ArrayList(); - for (RItem item : Editor.resources.getResources(RItem.class)) { - if (!item.id.equals(data.id)) { // item niet in zichzelf steken - items.add(item.id); - } - } - String s = - (String) - JOptionPane.showInputDialog( - frame, - "Add item:", - "Add item", - JOptionPane.PLAIN_MESSAGE, - null, - items.toArray(), - 0); - if ((s != null) && (s.length() > 0)) { - String[] item = {s, "0"}; - model.addRow(item); - } - } else if (e.getActionCommand().equals("Delete item")) { - model.removeRow(table.getSelectedRow()); - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012-2013 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.swing.table.DefaultTableModel; +import neon.editor.DataStore; +import neon.resources.LItem; +import neon.resources.RItem; + +public class LevelItemEditor extends ObjectEditor implements MouseListener { + private LItem data; + private final DataStore dataStore; + private JTable table; + private DefaultTableModel model; + + @SuppressWarnings("serial") + public LevelItemEditor(JFrame parent, LItem data, DataStore dataStore) { + super(parent, "Leveled Item Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + + // help + JLabel help = + new JLabel( + "Right click on the list to add or " + + "delete an item. An item will start showing up when the " + + "player is at the indicated level."); + help.setBorder(new TitledBorder("Instructions")); + + // tabel + String[] columns = {"id", "level"}; + model = new DefaultTableModel(columns, 0); + table = + new JTable(model) { + public boolean isCellEditable(int rowIndex, int colIndex) { + return colIndex == 1; + } + }; + table.addMouseListener(this); + table.getTableHeader().addMouseListener(this); + JScrollPane scroller = new JScrollPane(table); + + frame.add(help, BorderLayout.PAGE_START); + frame.add(scroller, BorderLayout.CENTER); + frame.setPreferredSize(new Dimension(400, 400)); + } + + protected void save() { + data.items.clear(); + for (int i = 0; i < table.getModel().getRowCount(); i++) { + data.items.put( + (String) table.getModel().getValueAt(i, 0), + Integer.parseInt(table.getModel().getValueAt(i, 1).toString())); + } + data.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + for (String s : data.items.keySet()) { + Object[] row = {s, data.items.get(s)}; + model.addRow(row); + } + } + + public void mouseExited(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mousePressed(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + int rowNumber = table.rowAtPoint(e.getPoint()); + ListSelectionModel model = table.getSelectionModel(); + model.setSelectionInterval(rowNumber, rowNumber); + + JPopupMenu menu = new JPopupMenu(); + menu.add(new ClickAction("Delete item")); + menu.add(new ClickAction("Add item")); + menu.show(e.getComponent(), e.getX(), e.getY()); + } + } + + @SuppressWarnings("serial") + public class ClickAction extends AbstractAction { + public ClickAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add item")) { + ArrayList items = new ArrayList(); + for (RItem item : dataStore.getResourceManager().getResources(RItem.class)) { + if (!item.id.equals(data.id)) { // item niet in zichzelf steken + items.add(item.id); + } + } + String s = + (String) + JOptionPane.showInputDialog( + frame, + "Add item:", + "Add item", + JOptionPane.PLAIN_MESSAGE, + null, + items.toArray(), + 0); + if ((s != null) && (s.length() > 0)) { + String[] item = {s, "0"}; + model.addRow(item); + } + } else if (e.getActionCommand().equals("Delete item")) { + model.removeRow(table.getSelectedRow()); + } + } + } +} diff --git a/src/main/java/neon/editor/editors/LevelSpellEditor.java b/src/main/java/neon/editor/editors/LevelSpellEditor.java index b6e90d9..07fdc12 100644 --- a/src/main/java/neon/editor/editors/LevelSpellEditor.java +++ b/src/main/java/neon/editor/editors/LevelSpellEditor.java @@ -1,132 +1,134 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.BorderLayout; -import java.awt.event.*; -import java.util.*; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import javax.swing.table.DefaultTableModel; -import neon.editor.Editor; -import neon.resources.LSpell; -import neon.resources.RSpell; - -/** - * This class allows editing of levelled spells. Only real spells can be levelled, not curses, - * diseases, ... - * - * @author mdriesen - */ -@SuppressWarnings("serial") -public class LevelSpellEditor extends ObjectEditor implements MouseListener { - private LSpell data; - private JTable table; - private DefaultTableModel model; - - public LevelSpellEditor(JFrame parent, LSpell data) { - super(parent, "Levelled spell: " + data.id); - this.data = data; - - // tabel - String[] columns = {"id", "level"}; - model = new DefaultTableModel(columns, 0); - table = - new JTable(model) { - public boolean isCellEditable(int rowIndex, int vColIndex) { - return vColIndex == 1; - } - }; - table.addMouseListener(this); - table.getTableHeader().addMouseListener(this); - JScrollPane scroller = new JScrollPane(table); - scroller.setBorder(new TitledBorder("Spells")); - - frame.add(scroller, BorderLayout.CENTER); - } - - protected void save() { - data.spells.clear(); - for (int i = 0; i < table.getModel().getRowCount(); i++) { - data.spells.put( - (String) table.getModel().getValueAt(i, 0), - Integer.parseInt(table.getModel().getValueAt(i, 1).toString())); - } - data.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - for (String s : data.spells.keySet()) { - Object[] row = {s, data.spells.get(s)}; - model.addRow(row); - } - } - - public void mouseExited(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mousePressed(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - int rowNumber = table.rowAtPoint(e.getPoint()); - ListSelectionModel model = table.getSelectionModel(); - model.setSelectionInterval(rowNumber, rowNumber); - - JPopupMenu menu = new JPopupMenu(); - menu.add(new ClickAction("Delete spell")); - menu.add(new ClickAction("Add spell")); - menu.show(e.getComponent(), e.getX(), e.getY()); - } - } - - public class ClickAction extends AbstractAction { - public ClickAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add spell")) { - ArrayList spells = new ArrayList(); - for (RSpell spell : Editor.resources.getResources(RSpell.class)) { - spells.add(spell.id); - } - String s = - (String) - JOptionPane.showInputDialog( - frame, - "Add spell:", - "Add spell", - JOptionPane.PLAIN_MESSAGE, - null, - spells.toArray(), - 0); - if ((s != null) && (s.length() > 0)) { - String[] item = {s, "0"}; - model.addRow(item); - } - } else if (e.getActionCommand().equals("Delete spell")) { - model.removeRow(table.getSelectedRow()); - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.BorderLayout; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.swing.table.DefaultTableModel; +import neon.editor.DataStore; +import neon.resources.LSpell; +import neon.resources.RSpell; + +/** + * This class allows editing of levelled spells. Only real spells can be levelled, not curses, + * diseases, ... + * + * @author mdriesen + */ +@SuppressWarnings("serial") +public class LevelSpellEditor extends ObjectEditor implements MouseListener { + private LSpell data; + private final DataStore dataStore; + private JTable table; + private DefaultTableModel model; + + public LevelSpellEditor(JFrame parent, LSpell data, DataStore dataStore) { + super(parent, "Levelled spell: " + data.id); + this.data = data; + this.dataStore = dataStore; + + // tabel + String[] columns = {"id", "level"}; + model = new DefaultTableModel(columns, 0); + table = + new JTable(model) { + public boolean isCellEditable(int rowIndex, int vColIndex) { + return vColIndex == 1; + } + }; + table.addMouseListener(this); + table.getTableHeader().addMouseListener(this); + JScrollPane scroller = new JScrollPane(table); + scroller.setBorder(new TitledBorder("Spells")); + + frame.add(scroller, BorderLayout.CENTER); + } + + protected void save() { + data.spells.clear(); + for (int i = 0; i < table.getModel().getRowCount(); i++) { + data.spells.put( + (String) table.getModel().getValueAt(i, 0), + Integer.parseInt(table.getModel().getValueAt(i, 1).toString())); + } + data.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + for (String s : data.spells.keySet()) { + Object[] row = {s, data.spells.get(s)}; + model.addRow(row); + } + } + + public void mouseExited(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mousePressed(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + int rowNumber = table.rowAtPoint(e.getPoint()); + ListSelectionModel model = table.getSelectionModel(); + model.setSelectionInterval(rowNumber, rowNumber); + + JPopupMenu menu = new JPopupMenu(); + menu.add(new ClickAction("Delete spell")); + menu.add(new ClickAction("Add spell")); + menu.show(e.getComponent(), e.getX(), e.getY()); + } + } + + public class ClickAction extends AbstractAction { + public ClickAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add spell")) { + ArrayList spells = new ArrayList(); + for (RSpell spell : dataStore.getResourceManager().getResources(RSpell.class)) { + spells.add(spell.id); + } + String s = + (String) + JOptionPane.showInputDialog( + frame, + "Add spell:", + "Add spell", + JOptionPane.PLAIN_MESSAGE, + null, + spells.toArray(), + 0); + if ((s != null) && (s.length() > 0)) { + String[] item = {s, "0"}; + model.addRow(item); + } + } else if (e.getActionCommand().equals("Delete spell")) { + model.removeRow(table.getSelectedRow()); + } + } + } +} diff --git a/src/main/java/neon/editor/editors/LightEditor.java b/src/main/java/neon/editor/editors/LightEditor.java index 9d7ad5c..55b859c 100644 --- a/src/main/java/neon/editor/editors/LightEditor.java +++ b/src/main/java/neon/editor/editors/LightEditor.java @@ -1,158 +1,162 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.text.ParseException; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.ColorCellRenderer; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.resources.RItem; -import neon.util.ColorFactory; - -public class LightEditor extends ObjectEditor { - private JTextField nameField; - private JFormattedTextField costField, weightField, charField; - private JComboBox colorBox; - private RItem data; - - public LightEditor(JFrame parent, RItem data) { - super(parent, "Light Editor: " + data.id); - this.data = data; - - JPanel itemProps = new JPanel(); - GroupLayout layout = new GroupLayout(itemProps); - itemProps.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel nameLabel = new JLabel("Name: "); - JLabel costLabel = new JLabel("Cost: "); - JLabel colorLabel = new JLabel("Color: "); - JLabel charLabel = new JLabel("Character: "); - JLabel weightLabel = new JLabel("Weight: "); - nameField = new JTextField(15); - costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - colorBox = new JComboBox(ColorFactory.getColorNames()); - colorBox.setBackground(Color.black); - colorBox.setRenderer(new ColorCellRenderer()); - colorBox.addActionListener(new ColorListener(colorBox)); - charField = new JFormattedTextField(getMaskFormatter("*", 'X')); - weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCostHelpLabel(); - JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); - JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); - JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(costLabel) - .addComponent(costField) - .addComponent(costHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(colorLabel) - .addComponent(colorBox) - .addComponent(colorHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(charLabel) - .addComponent(charField) - .addComponent(charHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(weightLabel) - .addComponent(weightField) - .addComponent(weightHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(costLabel) - .addComponent(colorLabel) - .addComponent(charLabel) - .addComponent(weightLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(costField) - .addComponent(colorBox) - .addComponent(charField) - .addComponent(weightField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(costHelpLabel) - .addComponent(colorHelpLabel) - .addComponent(charHelpLabel) - .addComponent(weightHelpLabel))); - JScrollPane propScroller = new JScrollPane(itemProps); - propScroller.setBorder(new TitledBorder("Properties")); - - frame.add(propScroller, BorderLayout.CENTER); - } - - protected void load() { - nameField.setText(data.name); - costField.setValue(data.cost); - colorBox.setSelectedItem(data.color); - charField.setValue(data.text); - weightField.setValue(data.weight); - } - - protected void save() { - data.name = nameField.getText(); - try { - costField.commitEdit(); - data.cost = ((Long) costField.getValue()).intValue(); - } catch (ParseException e) { - data.cost = 0; - } - data.color = colorBox.getSelectedItem().toString(); - data.text = charField.getText(); - data.weight = Float.parseFloat(weightField.getText()); - - data.setPath(Editor.getStore().getActive().get("id")); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.text.ParseException; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.resources.RItem; +import neon.util.ColorFactory; + +public class LightEditor extends ObjectEditor { + private JTextField nameField; + private JFormattedTextField costField, weightField, charField; + private JComboBox colorBox; + private RItem data; + private final DataStore dataStore; + private final HelpLabels helpLabels; + + public LightEditor(JFrame parent, RItem data, DataStore dataStore) { + super(parent, "Light Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + this.helpLabels = new HelpLabels(dataStore); + + JPanel itemProps = new JPanel(); + GroupLayout layout = new GroupLayout(itemProps); + itemProps.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel nameLabel = new JLabel("Name: "); + JLabel costLabel = new JLabel("Cost: "); + JLabel colorLabel = new JLabel("Color: "); + JLabel charLabel = new JLabel("Character: "); + JLabel weightLabel = new JLabel("Weight: "); + nameField = new JTextField(15); + costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + colorBox = new JComboBox(ColorFactory.getColorNames()); + colorBox.setBackground(Color.black); + colorBox.setRenderer(new ColorCellRenderer()); + colorBox.addActionListener(new ColorListener(colorBox)); + charField = new JFormattedTextField(getMaskFormatter("*", 'X')); + weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel costHelpLabel = helpLabels.getCostHelpLabel(); + JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); + JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); + JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(costLabel) + .addComponent(costField) + .addComponent(costHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(colorLabel) + .addComponent(colorBox) + .addComponent(colorHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(charLabel) + .addComponent(charField) + .addComponent(charHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(weightLabel) + .addComponent(weightField) + .addComponent(weightHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(costLabel) + .addComponent(colorLabel) + .addComponent(charLabel) + .addComponent(weightLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(costField) + .addComponent(colorBox) + .addComponent(charField) + .addComponent(weightField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(costHelpLabel) + .addComponent(colorHelpLabel) + .addComponent(charHelpLabel) + .addComponent(weightHelpLabel))); + JScrollPane propScroller = new JScrollPane(itemProps); + propScroller.setBorder(new TitledBorder("Properties")); + + frame.add(propScroller, BorderLayout.CENTER); + } + + protected void load() { + nameField.setText(data.name); + costField.setValue(data.cost); + colorBox.setSelectedItem(data.color); + charField.setValue(data.text); + weightField.setValue(data.weight); + } + + protected void save() { + data.name = nameField.getText(); + try { + costField.commitEdit(); + data.cost = ((Long) costField.getValue()).intValue(); + } catch (ParseException e) { + data.cost = 0; + } + data.color = colorBox.getSelectedItem().toString(); + data.text = charField.getText(); + data.weight = Float.parseFloat(weightField.getText()); + + data.setPath(dataStore.getActive().get("id")); + } +} diff --git a/src/main/java/neon/editor/editors/MoneyEditor.java b/src/main/java/neon/editor/editors/MoneyEditor.java index 8dfbc5a..b3b2b59 100644 --- a/src/main/java/neon/editor/editors/MoneyEditor.java +++ b/src/main/java/neon/editor/editors/MoneyEditor.java @@ -1,138 +1,142 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.ColorCellRenderer; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.resources.RItem; -import neon.util.ColorFactory; - -public class MoneyEditor extends ObjectEditor { - private JTextField nameField; - private JFormattedTextField costField, charField; - private JComboBox colorBox; - private RItem data; - - public MoneyEditor(JFrame parent, RItem data) { - super(parent, "Money Editor: " + data.id); - this.data = data; - - JPanel itemProps = new JPanel(); - GroupLayout layout = new GroupLayout(itemProps); - itemProps.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel nameLabel = new JLabel("Name: "); - JLabel costLabel = new JLabel("Cost: "); - JLabel colorLabel = new JLabel("Color: "); - JLabel charLabel = new JLabel("Character: "); - nameField = new JTextField(15); - costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - colorBox = new JComboBox(ColorFactory.getColorNames()); - colorBox.setBackground(Color.black); - colorBox.setRenderer(new ColorCellRenderer()); - colorBox.addActionListener(new ColorListener(colorBox)); - charField = new JFormattedTextField(getMaskFormatter("*", 'X')); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCostHelpLabel(); - JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); - JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(costLabel) - .addComponent(costField) - .addComponent(costHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(colorLabel) - .addComponent(colorBox) - .addComponent(colorHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(charLabel) - .addComponent(charField) - .addComponent(charHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(costLabel) - .addComponent(colorLabel) - .addComponent(charLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(costField) - .addComponent(colorBox) - .addComponent(charField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(costHelpLabel) - .addComponent(colorHelpLabel) - .addComponent(charHelpLabel))); - JScrollPane propScroller = new JScrollPane(itemProps); - propScroller.setBorder(new TitledBorder("Properties")); - - frame.add(propScroller, BorderLayout.CENTER); - } - - protected void load() { - nameField.setText(data.name); - costField.setValue(data.cost); - colorBox.setSelectedItem(data.color); - charField.setValue(data.text); - } - - protected void save() { - data.name = nameField.getText(); - data.cost = Integer.parseInt(costField.getText()); - data.color = colorBox.getSelectedItem().toString(); - data.text = charField.getText(); - - data.setPath(Editor.getStore().getActive().get("id")); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.resources.RItem; +import neon.util.ColorFactory; + +public class MoneyEditor extends ObjectEditor { + private JTextField nameField; + private JFormattedTextField costField, charField; + private JComboBox colorBox; + private RItem data; + private final DataStore dataStore; + private final HelpLabels helpLabels; + + public MoneyEditor(JFrame parent, RItem data, DataStore dataStore) { + super(parent, "Money Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + helpLabels = new HelpLabels(dataStore); + + JPanel itemProps = new JPanel(); + GroupLayout layout = new GroupLayout(itemProps); + itemProps.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel nameLabel = new JLabel("Name: "); + JLabel costLabel = new JLabel("Cost: "); + JLabel colorLabel = new JLabel("Color: "); + JLabel charLabel = new JLabel("Character: "); + nameField = new JTextField(15); + costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + colorBox = new JComboBox(ColorFactory.getColorNames()); + colorBox.setBackground(Color.black); + colorBox.setRenderer(new ColorCellRenderer()); + colorBox.addActionListener(new ColorListener(colorBox)); + charField = new JFormattedTextField(getMaskFormatter("*", 'X')); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel costHelpLabel = helpLabels.getCostHelpLabel(); + JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); + JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(costLabel) + .addComponent(costField) + .addComponent(costHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(colorLabel) + .addComponent(colorBox) + .addComponent(colorHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(charLabel) + .addComponent(charField) + .addComponent(charHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(costLabel) + .addComponent(colorLabel) + .addComponent(charLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(costField) + .addComponent(colorBox) + .addComponent(charField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(costHelpLabel) + .addComponent(colorHelpLabel) + .addComponent(charHelpLabel))); + JScrollPane propScroller = new JScrollPane(itemProps); + propScroller.setBorder(new TitledBorder("Properties")); + + frame.add(propScroller, BorderLayout.CENTER); + } + + protected void load() { + nameField.setText(data.name); + costField.setValue(data.cost); + colorBox.setSelectedItem(data.color); + charField.setValue(data.text); + } + + protected void save() { + data.name = nameField.getText(); + data.cost = Integer.parseInt(costField.getText()); + data.color = colorBox.getSelectedItem().toString(); + data.text = charField.getText(); + + data.setPath(dataStore.getActive().get("id")); + } +} diff --git a/src/main/java/neon/editor/editors/NPCEditor.java b/src/main/java/neon/editor/editors/NPCEditor.java index 67ee012..f99e76c 100644 --- a/src/main/java/neon/editor/editors/NPCEditor.java +++ b/src/main/java/neon/editor/editors/NPCEditor.java @@ -25,7 +25,7 @@ import javax.swing.*; import javax.swing.border.*; import javax.swing.event.*; -import neon.editor.*; +import neon.editor.DataStore; import neon.editor.help.HelpLabels; import neon.editor.resources.RFaction; import neon.entities.property.Skill; @@ -35,6 +35,7 @@ public class NPCEditor extends ObjectEditor implements MouseListener { private RPerson data; + private final DataStore dataStore; private JList spellList, itemList, destList; private JTextField nameField; private JComboBox factionBox; @@ -62,12 +63,13 @@ public class NPCEditor extends ObjectEditor implements MouseListener { private Element currentDest; private ArrayList spells; - public NPCEditor(JFrame parent, RPerson data) { + public NPCEditor(JFrame parent, RPerson data, DataStore dataStore) { super(parent, "NPC Editor: " + data.id); this.data = data; + this.dataStore = dataStore; spells = new ArrayList(); - for (RSpell spell : Editor.resources.getResources(RSpell.class)) { + for (RSpell spell : dataStore.getResourceManager().getResources(RSpell.class)) { if (spell.type == SpellType.SPELL) { spells.add(spell.id); } @@ -81,7 +83,8 @@ public NPCEditor(JFrame parent, RPerson data) { JPanel generalPanel = new JPanel(); generalPanel.setBorder(new TitledBorder("General")); nameField = new JTextField(10); - raceBox = new JComboBox(Editor.resources.getResources(RCreature.class)); + raceBox = + new JComboBox(dataStore.getResourceManager().getResources(RCreature.class)); generalPanel.add(new JLabel("Name: ")); generalPanel.add(nameField); generalPanel.add(new JLabel(" ")); @@ -278,7 +281,8 @@ public NPCEditor(JFrame parent, RPerson data) { joinedFactions = new HashMap(); FactionListListener fl = new FactionListListener(); - factionBox = new JComboBox(Editor.resources.getResources(RFaction.class)); + factionBox = + new JComboBox(dataStore.getResourceManager().getResources(RFaction.class)); factionBox.addActionListener(fl); factionPanel.add(factionBox); factionCheckBox = new JCheckBox(); @@ -301,7 +305,7 @@ public NPCEditor(JFrame parent, RPerson data) { protected void load() { nameField.setText(data.name); - RCreature species = (RCreature) Editor.resources.getResource(data.species); + RCreature species = (RCreature) dataStore.getResourceManager().getResource(data.species); raceBox.setSelectedItem(species); for (String s : data.factions.keySet()) { @@ -528,7 +532,7 @@ protected void save() { data.services.add(service); } - data.setPath(Editor.getStore().getActive().get("id")); + data.setPath(dataStore.getActive().get("id")); } private class SkillListListener implements ActionListener { @@ -626,7 +630,7 @@ public ItemListAction(String name) { public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Add item")) { - Object[] items = Editor.resources.getResources(RItem.class).toArray(); + Object[] items = dataStore.getResourceManager().getResources(RItem.class).toArray(); String s = (String) JOptionPane.showInputDialog( diff --git a/src/main/java/neon/editor/editors/PoisonEditor.java b/src/main/java/neon/editor/editors/PoisonEditor.java index 89b51ff..dd46a1e 100644 --- a/src/main/java/neon/editor/editors/PoisonEditor.java +++ b/src/main/java/neon/editor/editors/PoisonEditor.java @@ -1,148 +1,150 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.magic.Effect; -import neon.resources.RSpell; - -public class PoisonEditor extends ObjectEditor implements ActionListener { - private JTextField nameField; - private JFormattedTextField sizeField, durationField; - private JComboBox effectBox; - private JTextArea scriptArea; - private RSpell data; - - public PoisonEditor(JFrame parent, RSpell data) { - super(parent, "Poison: " + data.id); - this.data = data; - - JPanel props = new JPanel(); - GroupLayout layout = new GroupLayout(props); - props.setLayout(layout); - layout.setAutoCreateGaps(true); - props.setBorder(new TitledBorder("Properties")); - - JLabel nameLabel = new JLabel("Name: "); - JLabel effectLabel = new JLabel("Effect: "); - JLabel sizeLabel = new JLabel("Magnitude: "); - JLabel durationLabel = new JLabel("Duration: "); - nameField = new JTextField(15); - effectBox = new JComboBox(Effect.values()); - effectBox.addActionListener(this); - sizeField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - durationField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel effectHelpLabel = HelpLabels.getEffectHelpLabel(); - JLabel sizeHelpLabel = HelpLabels.getSpellSizeHelpLabel(); - JLabel durationHelpLabel = HelpLabels.getDurationHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(effectLabel) - .addComponent(effectBox) - .addComponent(effectHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(sizeLabel) - .addComponent(sizeField) - .addComponent(sizeHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(durationLabel) - .addComponent(durationField) - .addComponent(durationHelpLabel)) - .addGap(10)); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(effectLabel) - .addComponent(sizeLabel) - .addComponent(durationLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(effectBox) - .addComponent(sizeField) - .addComponent(durationField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(effectHelpLabel) - .addComponent(sizeHelpLabel) - .addComponent(durationHelpLabel))); - frame.add(props, BorderLayout.PAGE_START); - - scriptArea = new JTextArea(6, 0); - scriptArea.setDisabledTextColor(Color.red); - JScrollPane scriptScroller = new JScrollPane(scriptArea); - scriptScroller.setBorder(new TitledBorder("Script")); - frame.add(scriptScroller, BorderLayout.CENTER); - } - - protected void load() { - nameField.setText(data.name); - effectBox.setSelectedItem(data.effect); - sizeField.setValue(data.size); - durationField.setValue(data.duration); - scriptArea.setText(data.script); - scriptArea.setEditable(data.effect == Effect.SCRIPTED); - } - - protected void save() { - data.name = nameField.getText(); - data.size = Integer.parseInt(sizeField.getText()); - data.effect = effectBox.getItemAt(effectBox.getSelectedIndex()); - data.duration = Integer.parseInt(durationField.getText()); - data.script = scriptArea.getText(); - data.setPath(Editor.getStore().getActive().get("id")); - } - - public void actionPerformed(ActionEvent e) { - scriptArea.setEditable(effectBox.getSelectedItem() == Effect.SCRIPTED); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.magic.Effect; +import neon.resources.RSpell; + +public class PoisonEditor extends ObjectEditor implements ActionListener { + private JTextField nameField; + private JFormattedTextField sizeField, durationField; + private JComboBox effectBox; + private JTextArea scriptArea; + private RSpell data; + private final DataStore dataStore; + + public PoisonEditor(JFrame parent, RSpell data, DataStore dataStore) { + super(parent, "Poison: " + data.id); + this.data = data; + this.dataStore = dataStore; + + JPanel props = new JPanel(); + GroupLayout layout = new GroupLayout(props); + props.setLayout(layout); + layout.setAutoCreateGaps(true); + props.setBorder(new TitledBorder("Properties")); + + JLabel nameLabel = new JLabel("Name: "); + JLabel effectLabel = new JLabel("Effect: "); + JLabel sizeLabel = new JLabel("Magnitude: "); + JLabel durationLabel = new JLabel("Duration: "); + nameField = new JTextField(15); + effectBox = new JComboBox(Effect.values()); + effectBox.addActionListener(this); + sizeField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + durationField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel effectHelpLabel = HelpLabels.getEffectHelpLabel(); + JLabel sizeHelpLabel = HelpLabels.getSpellSizeHelpLabel(); + JLabel durationHelpLabel = HelpLabels.getDurationHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(effectLabel) + .addComponent(effectBox) + .addComponent(effectHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(sizeLabel) + .addComponent(sizeField) + .addComponent(sizeHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(durationLabel) + .addComponent(durationField) + .addComponent(durationHelpLabel)) + .addGap(10)); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(effectLabel) + .addComponent(sizeLabel) + .addComponent(durationLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(effectBox) + .addComponent(sizeField) + .addComponent(durationField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(effectHelpLabel) + .addComponent(sizeHelpLabel) + .addComponent(durationHelpLabel))); + frame.add(props, BorderLayout.PAGE_START); + + scriptArea = new JTextArea(6, 0); + scriptArea.setDisabledTextColor(Color.red); + JScrollPane scriptScroller = new JScrollPane(scriptArea); + scriptScroller.setBorder(new TitledBorder("Script")); + frame.add(scriptScroller, BorderLayout.CENTER); + } + + protected void load() { + nameField.setText(data.name); + effectBox.setSelectedItem(data.effect); + sizeField.setValue(data.size); + durationField.setValue(data.duration); + scriptArea.setText(data.script); + scriptArea.setEditable(data.effect == Effect.SCRIPTED); + } + + protected void save() { + data.name = nameField.getText(); + data.size = Integer.parseInt(sizeField.getText()); + data.effect = effectBox.getItemAt(effectBox.getSelectedIndex()); + data.duration = Integer.parseInt(durationField.getText()); + data.script = scriptArea.getText(); + data.setPath(dataStore.getActive().get("id")); + } + + public void actionPerformed(ActionEvent e) { + scriptArea.setEditable(effectBox.getSelectedItem() == Effect.SCRIPTED); + } +} diff --git a/src/main/java/neon/editor/editors/PotionEditor.java b/src/main/java/neon/editor/editors/PotionEditor.java index 1a67e6e..c5a9df8 100644 --- a/src/main/java/neon/editor/editors/PotionEditor.java +++ b/src/main/java/neon/editor/editors/PotionEditor.java @@ -1,185 +1,191 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.text.ParseException; -import java.util.*; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.*; -import neon.editor.help.HelpLabels; -import neon.resources.RItem; -import neon.resources.RSpell; -import neon.util.ColorFactory; - -public class PotionEditor extends ObjectEditor { - private JTextField nameField; - private JFormattedTextField costField, weightField, charField; - private JComboBox colorBox, spellBox; - private RItem data; - - public PotionEditor(JFrame parent, RItem data) { - super(parent, "Potion Editor: " + data.id); - this.data = data; - - JPanel itemProps = new JPanel(); - GroupLayout layout = new GroupLayout(itemProps); - itemProps.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel nameLabel = new JLabel("Name: "); - JLabel costLabel = new JLabel("Cost: "); - JLabel colorLabel = new JLabel("Color: "); - JLabel charLabel = new JLabel("Character: "); - JLabel weightLabel = new JLabel("Weight: "); - JLabel spellLabel = new JLabel("Spell: "); - nameField = new JTextField(15); - costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - colorBox = new JComboBox(ColorFactory.getColorNames()); - colorBox.setBackground(Color.black); - colorBox.setRenderer(new ColorCellRenderer()); - colorBox.addActionListener(new ColorListener(colorBox)); - charField = new JFormattedTextField(getMaskFormatter("*", 'X')); - weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); - spellBox = new JComboBox(loadSpells()); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCostHelpLabel(); - JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); - JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); - JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); - JLabel spellHelpLabel = HelpLabels.getSpellHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(costLabel) - .addComponent(costField) - .addComponent(costHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(colorLabel) - .addComponent(colorBox) - .addComponent(colorHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(charLabel) - .addComponent(charField) - .addComponent(charHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(weightLabel) - .addComponent(weightField) - .addComponent(weightHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(spellLabel) - .addComponent(spellBox) - .addComponent(spellHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(costLabel) - .addComponent(colorLabel) - .addComponent(charLabel) - .addComponent(weightLabel) - .addComponent(spellLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(costField) - .addComponent(colorBox) - .addComponent(charField) - .addComponent(weightField) - .addComponent(spellBox)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(costHelpLabel) - .addComponent(colorHelpLabel) - .addComponent(charHelpLabel) - .addComponent(weightHelpLabel) - .addComponent(spellHelpLabel))); - JScrollPane propScroller = new JScrollPane(itemProps); - propScroller.setBorder(new TitledBorder("Properties")); - frame.add(propScroller, BorderLayout.CENTER); - } - - protected void load() { - nameField.setText(data.name); - costField.setValue(data.cost); - colorBox.setSelectedItem(data.color); - charField.setValue(data.text); - weightField.setValue(data.weight); - spellBox.setSelectedItem(data.spell); - } - - protected void save() { - data.name = nameField.getText(); - try { // fiddling to always get long back - costField.commitEdit(); - data.cost = ((Long) costField.getValue()).intValue(); - } catch (ParseException e) { - data.cost = 0; - } - data.color = colorBox.getSelectedItem().toString(); - data.text = charField.getText(); - data.weight = Float.parseFloat(weightField.getText()); - if (spellBox.getSelectedItem() != null) { - data.spell = spellBox.getSelectedItem().toString(); - } else { - data.spell = null; - } - data.setPath(Editor.getStore().getActive().get("id")); - } - - private Vector loadSpells() { - Vector spells = new Vector(); - spells.add(null); // potion can also have no effect - for (RSpell.Enchantment spell : Editor.resources.getResources(RSpell.Enchantment.class)) { - if (spell.item.equals("nutrition")) { - spells.add(spell.id); - } - } - return spells; - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.text.ParseException; +import java.util.*; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.resources.RItem; +import neon.resources.RSpell; +import neon.util.ColorFactory; + +public class PotionEditor extends ObjectEditor { + private JTextField nameField; + private JFormattedTextField costField, weightField, charField; + private JComboBox colorBox, spellBox; + private RItem data; + private final DataStore dataStore; + private final HelpLabels helpLabels; + + public PotionEditor(JFrame parent, RItem data, DataStore dataStore) { + super(parent, "Potion Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + helpLabels = new HelpLabels(dataStore); + JPanel itemProps = new JPanel(); + GroupLayout layout = new GroupLayout(itemProps); + itemProps.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel nameLabel = new JLabel("Name: "); + JLabel costLabel = new JLabel("Cost: "); + JLabel colorLabel = new JLabel("Color: "); + JLabel charLabel = new JLabel("Character: "); + JLabel weightLabel = new JLabel("Weight: "); + JLabel spellLabel = new JLabel("Spell: "); + nameField = new JTextField(15); + costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + colorBox = new JComboBox(ColorFactory.getColorNames()); + colorBox.setBackground(Color.black); + colorBox.setRenderer(new ColorCellRenderer()); + colorBox.addActionListener(new ColorListener(colorBox)); + charField = new JFormattedTextField(getMaskFormatter("*", 'X')); + weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); + spellBox = new JComboBox(loadSpells()); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel costHelpLabel = helpLabels.getCostHelpLabel(); + JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); + JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); + JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); + JLabel spellHelpLabel = HelpLabels.getSpellHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(costLabel) + .addComponent(costField) + .addComponent(costHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(colorLabel) + .addComponent(colorBox) + .addComponent(colorHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(charLabel) + .addComponent(charField) + .addComponent(charHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(weightLabel) + .addComponent(weightField) + .addComponent(weightHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(spellLabel) + .addComponent(spellBox) + .addComponent(spellHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(costLabel) + .addComponent(colorLabel) + .addComponent(charLabel) + .addComponent(weightLabel) + .addComponent(spellLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(costField) + .addComponent(colorBox) + .addComponent(charField) + .addComponent(weightField) + .addComponent(spellBox)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(costHelpLabel) + .addComponent(colorHelpLabel) + .addComponent(charHelpLabel) + .addComponent(weightHelpLabel) + .addComponent(spellHelpLabel))); + JScrollPane propScroller = new JScrollPane(itemProps); + propScroller.setBorder(new TitledBorder("Properties")); + frame.add(propScroller, BorderLayout.CENTER); + } + + protected void load() { + nameField.setText(data.name); + costField.setValue(data.cost); + colorBox.setSelectedItem(data.color); + charField.setValue(data.text); + weightField.setValue(data.weight); + spellBox.setSelectedItem(data.spell); + } + + protected void save() { + data.name = nameField.getText(); + try { // fiddling to always get long back + costField.commitEdit(); + data.cost = ((Long) costField.getValue()).intValue(); + } catch (ParseException e) { + data.cost = 0; + } + data.color = colorBox.getSelectedItem().toString(); + data.text = charField.getText(); + data.weight = Float.parseFloat(weightField.getText()); + if (spellBox.getSelectedItem() != null) { + data.spell = spellBox.getSelectedItem().toString(); + } else { + data.spell = null; + } + data.setPath(dataStore.getActive().get("id")); + } + + private Vector loadSpells() { + Vector spells = new Vector(); + spells.add(null); // potion can also have no effect + for (RSpell.Enchantment spell : + dataStore.getResourceManager().getResources(RSpell.Enchantment.class)) { + if (spell.item.equals("nutrition")) { + spells.add(spell.id); + } + } + return spells; + } +} diff --git a/src/main/java/neon/editor/editors/PowerEditor.java b/src/main/java/neon/editor/editors/PowerEditor.java index b554bab..7b0e551 100644 --- a/src/main/java/neon/editor/editors/PowerEditor.java +++ b/src/main/java/neon/editor/editors/PowerEditor.java @@ -1,190 +1,192 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.magic.Effect; -import neon.resources.RSpell; - -public class PowerEditor extends ObjectEditor implements ActionListener { - private JTextField nameField; - private JFormattedTextField areaField, rangeField, sizeField, durationField, intervalField; - private JComboBox effectBox; - private JTextArea scriptArea; - private RSpell.Power data; - - public PowerEditor(JFrame parent, RSpell.Power data) { - super(parent, "Power: " + data.id); - this.data = data; - - JPanel props = new JPanel(); - GroupLayout layout = new GroupLayout(props); - props.setLayout(layout); - layout.setAutoCreateGaps(true); - props.setBorder(new TitledBorder("Properties")); - - JLabel nameLabel = new JLabel("Name: "); - JLabel effectLabel = new JLabel("Effect: "); - JLabel sizeLabel = new JLabel("Magnitude: "); - JLabel rangeLabel = new JLabel("Range: "); - JLabel areaLabel = new JLabel("Radius: "); - JLabel durationLabel = new JLabel("Duration: "); - JLabel intervalLabel = new JLabel("Interval: "); - nameField = new JTextField(15); - effectBox = new JComboBox(Effect.values()); - effectBox.addActionListener(this); - areaField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - sizeField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - rangeField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - durationField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - intervalField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel effectHelpLabel = HelpLabels.getEffectHelpLabel(); - JLabel sizeHelpLabel = HelpLabels.getSpellSizeHelpLabel(); - JLabel rangeHelpLabel = HelpLabels.getSpellRangeHelpLabel(); - JLabel areaHelpLabel = HelpLabels.getSpellRadiusHelpLabel(); - JLabel durationHelpLabel = HelpLabels.getDurationHelpLabel(); - JLabel intervalHelpLabel = HelpLabels.getIntervalHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(effectLabel) - .addComponent(effectBox) - .addComponent(effectHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(sizeLabel) - .addComponent(sizeField) - .addComponent(sizeHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(rangeLabel) - .addComponent(rangeField) - .addComponent(rangeHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(areaLabel) - .addComponent(areaField) - .addComponent(areaHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(durationLabel) - .addComponent(durationField) - .addComponent(durationHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(intervalLabel) - .addComponent(intervalField) - .addComponent(intervalHelpLabel)) - .addGap(10)); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(effectLabel) - .addComponent(sizeLabel) - .addComponent(rangeLabel) - .addComponent(areaLabel) - .addComponent(durationLabel) - .addComponent(intervalLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(effectBox) - .addComponent(sizeField) - .addComponent(rangeField) - .addComponent(areaField) - .addComponent(durationField) - .addComponent(intervalField)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(effectHelpLabel) - .addComponent(sizeHelpLabel) - .addComponent(rangeHelpLabel) - .addComponent(areaHelpLabel) - .addComponent(durationHelpLabel) - .addComponent(intervalHelpLabel))); - frame.add(props, BorderLayout.PAGE_START); - - scriptArea = new JTextArea(6, 0); - scriptArea.setDisabledTextColor(Color.red); - JScrollPane scriptScroller = new JScrollPane(scriptArea); - scriptScroller.setBorder(new TitledBorder("Script")); - frame.add(scriptScroller, BorderLayout.CENTER); - } - - protected void load() { - nameField.setText(data.name); - effectBox.setSelectedItem(data.effect); - sizeField.setValue(data.size); - rangeField.setValue(data.range); - durationField.setValue(data.duration); - intervalField.setValue(data.interval); - areaField.setValue(data.radius); - scriptArea.setText(data.script); - scriptArea.setEditable(data.effect == Effect.SCRIPTED); - } - - protected void save() { - data.name = nameField.getText(); - data.size = Integer.parseInt(sizeField.getText()); - data.range = Integer.parseInt(rangeField.getText()); - data.radius = Integer.parseInt(areaField.getText()); - data.effect = effectBox.getItemAt(effectBox.getSelectedIndex()); - data.duration = Integer.parseInt(durationField.getText()); - data.interval = Integer.parseInt(intervalField.getText()); - data.script = scriptArea.getText(); - data.setPath(Editor.getStore().getActive().get("id")); - } - - public void actionPerformed(ActionEvent e) { - scriptArea.setEditable(effectBox.getSelectedItem() == Effect.SCRIPTED); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.magic.Effect; +import neon.resources.RSpell; + +public class PowerEditor extends ObjectEditor implements ActionListener { + private JTextField nameField; + private JFormattedTextField areaField, rangeField, sizeField, durationField, intervalField; + private JComboBox effectBox; + private JTextArea scriptArea; + private RSpell.Power data; + private final DataStore dataStore; + + public PowerEditor(JFrame parent, RSpell.Power data, DataStore dataStore) { + super(parent, "Power: " + data.id); + this.data = data; + this.dataStore = dataStore; + + JPanel props = new JPanel(); + GroupLayout layout = new GroupLayout(props); + props.setLayout(layout); + layout.setAutoCreateGaps(true); + props.setBorder(new TitledBorder("Properties")); + + JLabel nameLabel = new JLabel("Name: "); + JLabel effectLabel = new JLabel("Effect: "); + JLabel sizeLabel = new JLabel("Magnitude: "); + JLabel rangeLabel = new JLabel("Range: "); + JLabel areaLabel = new JLabel("Radius: "); + JLabel durationLabel = new JLabel("Duration: "); + JLabel intervalLabel = new JLabel("Interval: "); + nameField = new JTextField(15); + effectBox = new JComboBox(Effect.values()); + effectBox.addActionListener(this); + areaField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + sizeField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + rangeField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + durationField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + intervalField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel effectHelpLabel = HelpLabels.getEffectHelpLabel(); + JLabel sizeHelpLabel = HelpLabels.getSpellSizeHelpLabel(); + JLabel rangeHelpLabel = HelpLabels.getSpellRangeHelpLabel(); + JLabel areaHelpLabel = HelpLabels.getSpellRadiusHelpLabel(); + JLabel durationHelpLabel = HelpLabels.getDurationHelpLabel(); + JLabel intervalHelpLabel = HelpLabels.getIntervalHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(effectLabel) + .addComponent(effectBox) + .addComponent(effectHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(sizeLabel) + .addComponent(sizeField) + .addComponent(sizeHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(rangeLabel) + .addComponent(rangeField) + .addComponent(rangeHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(areaLabel) + .addComponent(areaField) + .addComponent(areaHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(durationLabel) + .addComponent(durationField) + .addComponent(durationHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(intervalLabel) + .addComponent(intervalField) + .addComponent(intervalHelpLabel)) + .addGap(10)); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(effectLabel) + .addComponent(sizeLabel) + .addComponent(rangeLabel) + .addComponent(areaLabel) + .addComponent(durationLabel) + .addComponent(intervalLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(effectBox) + .addComponent(sizeField) + .addComponent(rangeField) + .addComponent(areaField) + .addComponent(durationField) + .addComponent(intervalField)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(effectHelpLabel) + .addComponent(sizeHelpLabel) + .addComponent(rangeHelpLabel) + .addComponent(areaHelpLabel) + .addComponent(durationHelpLabel) + .addComponent(intervalHelpLabel))); + frame.add(props, BorderLayout.PAGE_START); + + scriptArea = new JTextArea(6, 0); + scriptArea.setDisabledTextColor(Color.red); + JScrollPane scriptScroller = new JScrollPane(scriptArea); + scriptScroller.setBorder(new TitledBorder("Script")); + frame.add(scriptScroller, BorderLayout.CENTER); + } + + protected void load() { + nameField.setText(data.name); + effectBox.setSelectedItem(data.effect); + sizeField.setValue(data.size); + rangeField.setValue(data.range); + durationField.setValue(data.duration); + intervalField.setValue(data.interval); + areaField.setValue(data.radius); + scriptArea.setText(data.script); + scriptArea.setEditable(data.effect == Effect.SCRIPTED); + } + + protected void save() { + data.name = nameField.getText(); + data.size = Integer.parseInt(sizeField.getText()); + data.range = Integer.parseInt(rangeField.getText()); + data.radius = Integer.parseInt(areaField.getText()); + data.effect = effectBox.getItemAt(effectBox.getSelectedIndex()); + data.duration = Integer.parseInt(durationField.getText()); + data.interval = Integer.parseInt(intervalField.getText()); + data.script = scriptArea.getText(); + data.setPath(dataStore.getActive().get("id")); + } + + public void actionPerformed(ActionEvent e) { + scriptArea.setEditable(effectBox.getSelectedItem() == Effect.SCRIPTED); + } +} diff --git a/src/main/java/neon/editor/editors/QuestEditor.java b/src/main/java/neon/editor/editors/QuestEditor.java index 6addd43..00a6d28 100644 --- a/src/main/java/neon/editor/editors/QuestEditor.java +++ b/src/main/java/neon/editor/editors/QuestEditor.java @@ -1,313 +1,316 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.awt.event.*; -import java.util.*; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableColumn; -import neon.editor.DialogEditor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.resources.quest.QuestVariable; -import neon.resources.quest.RQuest; - -public class QuestEditor extends ObjectEditor implements ActionListener, MouseListener { - private RQuest quest; - private JTextField nameField; - private JFormattedTextField freqField; - private DefaultTableModel conditionModel, varModel, dialogModel; - private JTable conditionTable, varTable, dialogTable; - private JCheckBox randomBox, initialBox; - private ClickAction cAdd = new ClickAction("Add condition"); - private ClickAction cRemove = new ClickAction("Remove condition"); - private ClickAction vAdd = new ClickAction("Add variable"); - private ClickAction vRemove = new ClickAction("Remove variable"); - private ClickAction tAdd = new ClickAction("Add topic"); - private ClickAction tRemove = new ClickAction("Remove topic"); - - public QuestEditor(JFrame parent, RQuest quest) { - super(parent, "Quest Editor: " + quest.id); - this.quest = quest; - - JPanel props = new JPanel(new GridLayout(0, 1)); - props.setBorder(new TitledBorder("Properties")); - JPanel topPanel = new JPanel(); - JPanel bottomPanel = new JPanel(); - nameField = new JTextField(15); - freqField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - freqField.setColumns(5); - randomBox = new JCheckBox("Repeats"); - initialBox = new JCheckBox("Initial"); - JLabel initialHelpLabel = HelpLabels.getInitialHelpLabel(); - topPanel.add(new JLabel("Name: ")); - topPanel.add(nameField); - topPanel.add(initialBox); - topPanel.add(initialHelpLabel); - bottomPanel.add(new JLabel("Chance: ")); - bottomPanel.add(freqField); - bottomPanel.add(randomBox); - props.add(topPanel); - props.add(bottomPanel); - randomBox.addActionListener(this); - - JTabbedPane stuff = new JTabbedPane(); - - JPanel conditionPanel = new JPanel(new BorderLayout()); - JPanel cButtonPanel = new JPanel(); - cButtonPanel.add(new JButton(cAdd)); - cButtonPanel.add(new JButton(cRemove)); - conditionModel = new DefaultTableModel(0, 1); - conditionTable = new JTable(conditionModel); - conditionTable.setTableHeader(null); - conditionTable.setFillsViewportHeight(true); - conditionTable.addMouseListener(this); - JScrollPane preScroller = new JScrollPane(conditionTable); - conditionPanel.add(cButtonPanel, BorderLayout.PAGE_END); - conditionPanel.add(preScroller, BorderLayout.CENTER); - - JPanel varPanel = new JPanel(new BorderLayout()); - JPanel vButtonPanel = new JPanel(); - vButtonPanel.add(new JButton(vAdd)); - vButtonPanel.add(new JButton(vRemove)); - String[] varColumns = {"name", "type", "id", "class"}; - varModel = - new QuestsTableModel(varColumns, String.class, String.class, String.class, String.class); - varTable = new JTable(varModel); - varTable.setFillsViewportHeight(true); - varTable.addMouseListener(this); - TableColumn typeColumn = varTable.getColumnModel().getColumn(1); - JComboBox comboBox = new JComboBox(); - comboBox.addItem("npc"); - comboBox.addItem("item"); - comboBox.addItem("creature"); - typeColumn.setCellEditor(new DefaultCellEditor(comboBox)); - JScrollPane varScroller = new JScrollPane(varTable); - varPanel.add(vButtonPanel, BorderLayout.PAGE_END); - varPanel.add(varScroller, BorderLayout.CENTER); - - JPanel dialogPanel = new JPanel(new BorderLayout()); - JPanel dButtonPanel = new JPanel(); - dButtonPanel.add(new JButton(tAdd)); - dButtonPanel.add(new JButton(tRemove)); - String[] dialogColumns = {"topic", "preconditions", "answer", "action"}; - dialogModel = - new QuestsTableModel(dialogColumns, String.class, String.class, String.class, String.class); - dialogTable = new JTable(dialogModel); - dialogTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - dialogTable.setFillsViewportHeight(true); - dialogTable.addMouseListener(this); - dialogTable.setDefaultEditor(String.class, new DialogEditor(parent)); - JScrollPane dialogScroller = new JScrollPane(dialogTable); - dialogPanel.add(dButtonPanel, BorderLayout.PAGE_END); - dialogPanel.add(dialogScroller, BorderLayout.CENTER); - - stuff.add("Prerequisites", conditionPanel); - stuff.add("Variables", varPanel); - stuff.add("Dialog", dialogPanel); - stuff.setBorder(new TitledBorder("Contents")); - - JPanel center = new JPanel(new BorderLayout()); - center.add(props, BorderLayout.PAGE_START); - center.add(stuff); - - frame.add(center, BorderLayout.CENTER); - } - - protected void save() { - // algemeen - quest.initial = initialBox.isSelected(); - quest.repeat = randomBox.isSelected(); - if (randomBox.isSelected()) { - quest.frequency = Integer.parseInt(freqField.getText()); - } - quest.name = nameField.getText(); - - // condities - quest.getConditions().clear(); - for (Vector data : (Vector) conditionModel.getDataVector()) { - quest.getConditions().add(data.get(0)); - } - - // Convert table data to QuestVariable objects - quest.getVariables().clear(); - for (Vector data : (Vector) varModel.getDataVector()) { - QuestVariable var = new QuestVariable(); - var.name = data.get(0) != null ? data.get(0).toString() : null; - var.category = data.get(1) != null ? data.get(1).toString() : null; - var.id = data.get(2) != null ? data.get(2).toString() : null; - var.typeFilter = data.get(3) != null ? data.get(3).toString() : null; - quest.getVariables().add(var); - } - - // quest.getTopics().clear(); - for (Vector data : (Vector) dialogModel.getDataVector()) { - String id = data.get(0).toString(); - String condition = (data.get(1) != null ? data.get(1).toString() : null); - String answer = (data.get(2) != null ? data.get(2).toString() : null); - String action = (data.get(3) != null ? data.get(3).toString() : null); - // quest.getTopics().add(new Topic(id, condition, answer, action)); - } - } - - protected void load() { - nameField.setText(quest.name); - initialBox.setSelected(quest.initial); - randomBox.setSelected(quest.repeat); - freqField.setEnabled(quest.repeat); - if (quest.repeat) { - freqField.setValue(quest.frequency); - } else { - freqField.setValue(null); - } - - // Load QuestVariable objects into table - for (QuestVariable var : quest.getVariables()) { - String[] data = {var.name, var.category, var.id, var.typeFilter}; - varModel.insertRow(0, data); - } - - for (String condition : quest.getConditions()) { - String[] row = {condition}; - conditionModel.addRow(row); - } - - // for(Topic topic : quest.getTopics()) { - // String[] data = {topic.getID(), topic.getCondition(), - // topic.getAnswer(), topic.getAction()}; - // dialogModel.insertRow(0, data); - // } - } - - public void actionPerformed(ActionEvent e) { - if (randomBox.isSelected()) { - freqField.setEnabled(true); - } else { - freqField.setEnabled(false); - } - } - - public void mousePressed(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseExited(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - JPopupMenu menu = new JPopupMenu(); - if (e.getSource().equals(conditionTable)) { - menu.add(cAdd); - menu.add(cRemove); - int row = conditionTable.rowAtPoint(e.getPoint()); - conditionTable.getSelectionModel().setSelectionInterval(row, row); - } else if (e.getSource().equals(varTable)) { - menu.add(vAdd); - menu.add(vRemove); - int row = varTable.rowAtPoint(e.getPoint()); - varTable.getSelectionModel().setSelectionInterval(row, row); - } else if (e.getSource().equals(dialogTable)) { - menu.add(tAdd); - menu.add(tRemove); - int row = dialogTable.rowAtPoint(e.getPoint()); - dialogTable.getSelectionModel().setSelectionInterval(row, row); - } - menu.show(e.getComponent(), e.getX(), e.getY()); - } - } - - @SuppressWarnings("serial") - private class ClickAction extends AbstractAction { - public ClickAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add condition")) { - String s = - (String) - JOptionPane.showInputDialog( - frame, - "Give new quest precondition:", - "New condition:", - JOptionPane.PLAIN_MESSAGE, - null, - null, - null); - if (s != null) { - String[] row = {s}; - conditionModel.addRow(row); - } - } else if (e.getActionCommand().equals("Remove condition")) { - conditionModel.removeRow(conditionTable.getSelectedRow()); - } else if (e.getActionCommand().equals("Add variable")) { - String s = - (String) - JOptionPane.showInputDialog( - frame, - "Variable name:", - "Add variable", - JOptionPane.PLAIN_MESSAGE, - null, - null, - ""); - if (s != null) { - String[] row = {s, "item", "", ""}; - varModel.addRow(row); - } - } else if (e.getActionCommand().equals("Remove variable")) { - varModel.removeRow(varTable.getSelectedRow()); - } else if (e.getActionCommand().equals("Add topic")) { - String s = - (String) - JOptionPane.showInputDialog( - frame, "Topic name:", "Add topic", JOptionPane.PLAIN_MESSAGE, null, null, ""); - if (s != null) { - String[] row = {s, "", "", ""}; - dialogModel.addRow(row); - } - } else if (e.getActionCommand().equals("Remove topic")) { - dialogModel.removeRow(dialogTable.getSelectedRow()); - } - } - } - - @SuppressWarnings("serial") - private static class QuestsTableModel extends DefaultTableModel { - private Class[] classes; - - public QuestsTableModel(String[] columns, Class... classes) { - super(columns, 0); - this.classes = classes; - } - - public Class getColumnClass(int i) { - return classes[i]; - } - - public boolean isCellEditable(int row, int column) { - return column != 0; - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumn; +import neon.editor.DataStore; +import neon.editor.DialogEditor; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.resources.quest.QuestVariable; +import neon.resources.quest.RQuest; + +public class QuestEditor extends ObjectEditor implements ActionListener, MouseListener { + private RQuest quest; + private JTextField nameField; + private JFormattedTextField freqField; + private DefaultTableModel conditionModel, varModel, dialogModel; + private JTable conditionTable, varTable, dialogTable; + private JCheckBox randomBox, initialBox; + private ClickAction cAdd = new ClickAction("Add condition"); + private ClickAction cRemove = new ClickAction("Remove condition"); + private ClickAction vAdd = new ClickAction("Add variable"); + private ClickAction vRemove = new ClickAction("Remove variable"); + private ClickAction tAdd = new ClickAction("Add topic"); + private ClickAction tRemove = new ClickAction("Remove topic"); + private final DataStore dataStore; + + public QuestEditor(JFrame parent, RQuest quest, DataStore dataStore) { + super(parent, "Quest Editor: " + quest.id); + this.quest = quest; + this.dataStore = dataStore; + + JPanel props = new JPanel(new GridLayout(0, 1)); + props.setBorder(new TitledBorder("Properties")); + JPanel topPanel = new JPanel(); + JPanel bottomPanel = new JPanel(); + nameField = new JTextField(15); + freqField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + freqField.setColumns(5); + randomBox = new JCheckBox("Repeats"); + initialBox = new JCheckBox("Initial"); + JLabel initialHelpLabel = HelpLabels.getInitialHelpLabel(); + topPanel.add(new JLabel("Name: ")); + topPanel.add(nameField); + topPanel.add(initialBox); + topPanel.add(initialHelpLabel); + bottomPanel.add(new JLabel("Chance: ")); + bottomPanel.add(freqField); + bottomPanel.add(randomBox); + props.add(topPanel); + props.add(bottomPanel); + randomBox.addActionListener(this); + + JTabbedPane stuff = new JTabbedPane(); + + JPanel conditionPanel = new JPanel(new BorderLayout()); + JPanel cButtonPanel = new JPanel(); + cButtonPanel.add(new JButton(cAdd)); + cButtonPanel.add(new JButton(cRemove)); + conditionModel = new DefaultTableModel(0, 1); + conditionTable = new JTable(conditionModel); + conditionTable.setTableHeader(null); + conditionTable.setFillsViewportHeight(true); + conditionTable.addMouseListener(this); + JScrollPane preScroller = new JScrollPane(conditionTable); + conditionPanel.add(cButtonPanel, BorderLayout.PAGE_END); + conditionPanel.add(preScroller, BorderLayout.CENTER); + + JPanel varPanel = new JPanel(new BorderLayout()); + JPanel vButtonPanel = new JPanel(); + vButtonPanel.add(new JButton(vAdd)); + vButtonPanel.add(new JButton(vRemove)); + String[] varColumns = {"name", "type", "id", "class"}; + varModel = + new QuestsTableModel(varColumns, String.class, String.class, String.class, String.class); + varTable = new JTable(varModel); + varTable.setFillsViewportHeight(true); + varTable.addMouseListener(this); + TableColumn typeColumn = varTable.getColumnModel().getColumn(1); + JComboBox comboBox = new JComboBox(); + comboBox.addItem("npc"); + comboBox.addItem("item"); + comboBox.addItem("creature"); + typeColumn.setCellEditor(new DefaultCellEditor(comboBox)); + JScrollPane varScroller = new JScrollPane(varTable); + varPanel.add(vButtonPanel, BorderLayout.PAGE_END); + varPanel.add(varScroller, BorderLayout.CENTER); + + JPanel dialogPanel = new JPanel(new BorderLayout()); + JPanel dButtonPanel = new JPanel(); + dButtonPanel.add(new JButton(tAdd)); + dButtonPanel.add(new JButton(tRemove)); + String[] dialogColumns = {"topic", "preconditions", "answer", "action"}; + dialogModel = + new QuestsTableModel(dialogColumns, String.class, String.class, String.class, String.class); + dialogTable = new JTable(dialogModel); + dialogTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + dialogTable.setFillsViewportHeight(true); + dialogTable.addMouseListener(this); + dialogTable.setDefaultEditor(String.class, new DialogEditor(parent)); + JScrollPane dialogScroller = new JScrollPane(dialogTable); + dialogPanel.add(dButtonPanel, BorderLayout.PAGE_END); + dialogPanel.add(dialogScroller, BorderLayout.CENTER); + + stuff.add("Prerequisites", conditionPanel); + stuff.add("Variables", varPanel); + stuff.add("Dialog", dialogPanel); + stuff.setBorder(new TitledBorder("Contents")); + + JPanel center = new JPanel(new BorderLayout()); + center.add(props, BorderLayout.PAGE_START); + center.add(stuff); + + frame.add(center, BorderLayout.CENTER); + } + + protected void save() { + // algemeen + quest.initial = initialBox.isSelected(); + quest.repeat = randomBox.isSelected(); + if (randomBox.isSelected()) { + quest.frequency = Integer.parseInt(freqField.getText()); + } + quest.name = nameField.getText(); + + // condities + quest.getConditions().clear(); + for (Vector data : (Vector) conditionModel.getDataVector()) { + quest.getConditions().add(data.get(0)); + } + + // Convert table data to QuestVariable objects + quest.getVariables().clear(); + for (Vector data : (Vector) varModel.getDataVector()) { + QuestVariable var = new QuestVariable(); + var.name = data.get(0) != null ? data.get(0).toString() : null; + var.category = data.get(1) != null ? data.get(1).toString() : null; + var.id = data.get(2) != null ? data.get(2).toString() : null; + var.typeFilter = data.get(3) != null ? data.get(3).toString() : null; + quest.getVariables().add(var); + } + + // quest.getTopics().clear(); + for (Vector data : (Vector) dialogModel.getDataVector()) { + String id = data.get(0).toString(); + String condition = (data.get(1) != null ? data.get(1).toString() : null); + String answer = (data.get(2) != null ? data.get(2).toString() : null); + String action = (data.get(3) != null ? data.get(3).toString() : null); + // quest.getTopics().add(new Topic(id, condition, answer, action)); + } + } + + protected void load() { + nameField.setText(quest.name); + initialBox.setSelected(quest.initial); + randomBox.setSelected(quest.repeat); + freqField.setEnabled(quest.repeat); + if (quest.repeat) { + freqField.setValue(quest.frequency); + } else { + freqField.setValue(null); + } + + // Load QuestVariable objects into table + for (QuestVariable var : quest.getVariables()) { + String[] data = {var.name, var.category, var.id, var.typeFilter}; + varModel.insertRow(0, data); + } + + for (String condition : quest.getConditions()) { + String[] row = {condition}; + conditionModel.addRow(row); + } + + // for(Topic topic : quest.getTopics()) { + // String[] data = {topic.getID(), topic.getCondition(), + // topic.getAnswer(), topic.getAction()}; + // dialogModel.insertRow(0, data); + // } + } + + public void actionPerformed(ActionEvent e) { + if (randomBox.isSelected()) { + freqField.setEnabled(true); + } else { + freqField.setEnabled(false); + } + } + + public void mousePressed(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseExited(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + JPopupMenu menu = new JPopupMenu(); + if (e.getSource().equals(conditionTable)) { + menu.add(cAdd); + menu.add(cRemove); + int row = conditionTable.rowAtPoint(e.getPoint()); + conditionTable.getSelectionModel().setSelectionInterval(row, row); + } else if (e.getSource().equals(varTable)) { + menu.add(vAdd); + menu.add(vRemove); + int row = varTable.rowAtPoint(e.getPoint()); + varTable.getSelectionModel().setSelectionInterval(row, row); + } else if (e.getSource().equals(dialogTable)) { + menu.add(tAdd); + menu.add(tRemove); + int row = dialogTable.rowAtPoint(e.getPoint()); + dialogTable.getSelectionModel().setSelectionInterval(row, row); + } + menu.show(e.getComponent(), e.getX(), e.getY()); + } + } + + @SuppressWarnings("serial") + private class ClickAction extends AbstractAction { + public ClickAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add condition")) { + String s = + (String) + JOptionPane.showInputDialog( + frame, + "Give new quest precondition:", + "New condition:", + JOptionPane.PLAIN_MESSAGE, + null, + null, + null); + if (s != null) { + String[] row = {s}; + conditionModel.addRow(row); + } + } else if (e.getActionCommand().equals("Remove condition")) { + conditionModel.removeRow(conditionTable.getSelectedRow()); + } else if (e.getActionCommand().equals("Add variable")) { + String s = + (String) + JOptionPane.showInputDialog( + frame, + "Variable name:", + "Add variable", + JOptionPane.PLAIN_MESSAGE, + null, + null, + ""); + if (s != null) { + String[] row = {s, "item", "", ""}; + varModel.addRow(row); + } + } else if (e.getActionCommand().equals("Remove variable")) { + varModel.removeRow(varTable.getSelectedRow()); + } else if (e.getActionCommand().equals("Add topic")) { + String s = + (String) + JOptionPane.showInputDialog( + frame, "Topic name:", "Add topic", JOptionPane.PLAIN_MESSAGE, null, null, ""); + if (s != null) { + String[] row = {s, "", "", ""}; + dialogModel.addRow(row); + } + } else if (e.getActionCommand().equals("Remove topic")) { + dialogModel.removeRow(dialogTable.getSelectedRow()); + } + } + } + + @SuppressWarnings("serial") + private static class QuestsTableModel extends DefaultTableModel { + private Class[] classes; + + public QuestsTableModel(String[] columns, Class... classes) { + super(columns, 0); + this.classes = classes; + } + + public Class getColumnClass(int i) { + return classes[i]; + } + + public boolean isCellEditable(int row, int column) { + return column != 0; + } + } +} diff --git a/src/main/java/neon/editor/editors/RegionThemeEditor.java b/src/main/java/neon/editor/editors/RegionThemeEditor.java index 10451fb..bd0600d 100644 --- a/src/main/java/neon/editor/editors/RegionThemeEditor.java +++ b/src/main/java/neon/editor/editors/RegionThemeEditor.java @@ -1,258 +1,261 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.BorderLayout; -import java.awt.event.*; -import java.util.Map; -import java.util.Vector; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import javax.swing.table.DefaultTableModel; -import neon.editor.Editor; -import neon.resources.RCreature; -import neon.resources.RItem; -import neon.resources.RRegionTheme; -import neon.resources.RTerrain; - -@SuppressWarnings("serial") -public class RegionThemeEditor extends ObjectEditor implements MouseListener { - private JTextField floorField; - private JComboBox typeBox; - private JComboBox doorBox; - private JComboBox wallBox; - private JTable creatureTable, plantTable; - private DefaultTableModel creatureModel, plantModel; - private RRegionTheme theme; - - public RegionThemeEditor(JFrame parent, RRegionTheme theme) { - super(parent, "Region theme: " + theme.id); - this.theme = theme; - - JPanel props = new JPanel(); - GroupLayout layout = new GroupLayout(props); - props.setLayout(layout); - layout.setAutoCreateGaps(true); - props.setBorder(new TitledBorder("Properties")); - JLabel typeLabel = new JLabel("Type: "); - JLabel floorLabel = new JLabel("Surface: "); - JLabel doorLabel = new JLabel("Doors: "); - JLabel wallLabel = new JLabel("Walls: "); - typeBox = new JComboBox(RRegionTheme.Type.values()); - floorField = new JTextField(15); - doorBox = new JComboBox(Editor.resources.getResources(RItem.Door.class)); - wallBox = new JComboBox(Editor.resources.getResources(RTerrain.class)); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(typeLabel) - .addComponent(typeBox)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(floorLabel) - .addComponent(floorField)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(doorLabel) - .addComponent(doorBox)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(wallLabel) - .addComponent(wallBox))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(typeLabel) - .addComponent(floorLabel) - .addComponent(doorLabel) - .addComponent( - wallLabel, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(typeBox) - .addComponent( - floorField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(doorBox) - .addComponent(wallBox))); - - JTabbedPane stuff = new JTabbedPane(); - - String[] cColumns = {"id", "chance"}; - creatureModel = new ThemesTableModel(cColumns, String.class, Integer.class); - creatureTable = new JTable(creatureModel); - creatureTable.setFillsViewportHeight(true); - creatureTable.addMouseListener(this); - JScrollPane creatureScroller = new JScrollPane(creatureTable); - - String[] pColumns = {"id", "abundance"}; - plantModel = new ThemesTableModel(pColumns, String.class, Integer.class); - plantTable = new JTable(plantModel); - plantTable.setFillsViewportHeight(true); - plantTable.addMouseListener(this); - JScrollPane plantScroller = new JScrollPane(plantTable); - - stuff.add("Vegetation", plantScroller); - stuff.add("Creatures", creatureScroller); - stuff.setBorder(new TitledBorder("Contents")); - - JPanel center = new JPanel(new BorderLayout()); - center.add(props, BorderLayout.PAGE_START); - center.add(stuff, BorderLayout.CENTER); - - frame.add(center, BorderLayout.CENTER); - } - - protected void save() { - theme.wall = ((RTerrain) wallBox.getSelectedItem()).id; - theme.door = ((RItem.Door) doorBox.getSelectedItem()).id; - theme.floor = floorField.getText(); - theme.type = (RRegionTheme.Type) typeBox.getSelectedItem(); - theme.creatures.clear(); - for (Vector data : (Vector) creatureModel.getDataVector()) { - theme.creatures.put(data.get(0).toString(), (Integer) data.get(1)); - } - for (Vector data : (Vector) plantModel.getDataVector()) { - theme.vegetation.put(data.get(0).toString(), (Integer) data.get(1)); - } - theme.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - typeBox.setSelectedItem(theme.type); - RItem.Door door = (RItem.Door) Editor.resources.getResource(theme.door); - doorBox.setSelectedItem(door); - floorField.setText(theme.floor); - RTerrain wall = (RTerrain) Editor.resources.getResource(theme.wall, "terrain"); - wallBox.setSelectedItem(wall); - creatureModel.setRowCount(0); - for (Map.Entry creature : theme.creatures.entrySet()) { - Object[] data = {creature.getKey(), creature.getValue()}; - creatureModel.insertRow(0, data); - } - for (Map.Entry plant : theme.vegetation.entrySet()) { - Object[] data = {plant.getKey(), plant.getValue()}; - plantModel.insertRow(0, data); - } - } - - public void mouseEntered(MouseEvent e) {} - - public void mouseExited(MouseEvent e) {} - - public void mousePressed(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - JPopupMenu menu = new JPopupMenu(); - if (e.getSource().equals(creatureTable)) { - menu.add(new ClickAction("Add creature")); - menu.add(new ClickAction("Remove creature")); - int row = creatureTable.rowAtPoint(e.getPoint()); - creatureTable.getSelectionModel().setSelectionInterval(row, row); - } else if (e.getSource().equals(plantTable)) { - menu.add(new ClickAction("Add vegetation")); - menu.add(new ClickAction("Remove vegetation")); - int row = plantTable.rowAtPoint(e.getPoint()); - plantTable.getSelectionModel().setSelectionInterval(row, row); - } - menu.show(e.getComponent(), e.getX(), e.getY()); - } - } - - private class ClickAction extends AbstractAction { - public ClickAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add creature")) { - Object[] creatures = Editor.resources.getResources(RCreature.class).toArray(); - String s = - JOptionPane.showInputDialog( - frame, - "Choose creature:", - "Add creature", - JOptionPane.PLAIN_MESSAGE, - null, - creatures, - null) - .toString(); - if (s != null) { - Object[] row = {s, 1}; - creatureModel.addRow(row); - } - } else if (e.getActionCommand().equals("Remove creature")) { - creatureModel.removeRow(creatureTable.getSelectedRow()); - } else if (e.getActionCommand().equals("Add vegetation")) { - Object[] plants = Editor.resources.getResources(RItem.class).toArray(); - String s = - JOptionPane.showInputDialog( - frame, - "Choose creature:", - "Add vegetation", - JOptionPane.PLAIN_MESSAGE, - null, - plants, - null) - .toString(); - if (s != null) { - Object[] row = {s, 1}; - plantModel.addRow(row); - } - } else if (e.getActionCommand().equals("Remove vegetation")) { - plantModel.removeRow(plantTable.getSelectedRow()); - } - } - } - - private static class ThemesTableModel extends DefaultTableModel { - private Class[] classes; - - public ThemesTableModel(String[] columns, Class... classes) { - super(columns, 0); - this.classes = classes; - } - - public Class getColumnClass(int i) { - return classes[i]; - } - - public boolean isCellEditable(int row, int column) { - return column != 0; - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.BorderLayout; +import java.awt.event.*; +import java.util.Map; +import java.util.Vector; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.swing.table.DefaultTableModel; +import neon.editor.DataStore; +import neon.resources.RCreature; +import neon.resources.RItem; +import neon.resources.RRegionTheme; +import neon.resources.RTerrain; + +@SuppressWarnings("serial") +public class RegionThemeEditor extends ObjectEditor implements MouseListener { + private JTextField floorField; + private JComboBox typeBox; + private JComboBox doorBox; + private JComboBox wallBox; + private JTable creatureTable, plantTable; + private DefaultTableModel creatureModel, plantModel; + private RRegionTheme theme; + private final DataStore dataStore; + + public RegionThemeEditor(JFrame parent, RRegionTheme theme, DataStore dataStore) { + super(parent, "Region theme: " + theme.id); + this.theme = theme; + this.dataStore = dataStore; + + JPanel props = new JPanel(); + GroupLayout layout = new GroupLayout(props); + props.setLayout(layout); + layout.setAutoCreateGaps(true); + props.setBorder(new TitledBorder("Properties")); + JLabel typeLabel = new JLabel("Type: "); + JLabel floorLabel = new JLabel("Surface: "); + JLabel doorLabel = new JLabel("Doors: "); + JLabel wallLabel = new JLabel("Walls: "); + typeBox = new JComboBox(RRegionTheme.Type.values()); + floorField = new JTextField(15); + doorBox = + new JComboBox(dataStore.getResourceManager().getResources(RItem.Door.class)); + wallBox = new JComboBox(dataStore.getResourceManager().getResources(RTerrain.class)); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(typeLabel) + .addComponent(typeBox)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(floorLabel) + .addComponent(floorField)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(doorLabel) + .addComponent(doorBox)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(wallLabel) + .addComponent(wallBox))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(typeLabel) + .addComponent(floorLabel) + .addComponent(doorLabel) + .addComponent( + wallLabel, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(typeBox) + .addComponent( + floorField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(doorBox) + .addComponent(wallBox))); + + JTabbedPane stuff = new JTabbedPane(); + + String[] cColumns = {"id", "chance"}; + creatureModel = new ThemesTableModel(cColumns, String.class, Integer.class); + creatureTable = new JTable(creatureModel); + creatureTable.setFillsViewportHeight(true); + creatureTable.addMouseListener(this); + JScrollPane creatureScroller = new JScrollPane(creatureTable); + + String[] pColumns = {"id", "abundance"}; + plantModel = new ThemesTableModel(pColumns, String.class, Integer.class); + plantTable = new JTable(plantModel); + plantTable.setFillsViewportHeight(true); + plantTable.addMouseListener(this); + JScrollPane plantScroller = new JScrollPane(plantTable); + + stuff.add("Vegetation", plantScroller); + stuff.add("Creatures", creatureScroller); + stuff.setBorder(new TitledBorder("Contents")); + + JPanel center = new JPanel(new BorderLayout()); + center.add(props, BorderLayout.PAGE_START); + center.add(stuff, BorderLayout.CENTER); + + frame.add(center, BorderLayout.CENTER); + } + + protected void save() { + theme.wall = ((RTerrain) wallBox.getSelectedItem()).id; + theme.door = ((RItem.Door) doorBox.getSelectedItem()).id; + theme.floor = floorField.getText(); + theme.type = (RRegionTheme.Type) typeBox.getSelectedItem(); + theme.creatures.clear(); + for (Vector data : (Vector) creatureModel.getDataVector()) { + theme.creatures.put(data.get(0).toString(), (Integer) data.get(1)); + } + for (Vector data : (Vector) plantModel.getDataVector()) { + theme.vegetation.put(data.get(0).toString(), (Integer) data.get(1)); + } + theme.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + typeBox.setSelectedItem(theme.type); + RItem.Door door = (RItem.Door) dataStore.getResourceManager().getResource(theme.door); + doorBox.setSelectedItem(door); + floorField.setText(theme.floor); + RTerrain wall = (RTerrain) dataStore.getResourceManager().getResource(theme.wall, "terrain"); + wallBox.setSelectedItem(wall); + creatureModel.setRowCount(0); + for (Map.Entry creature : theme.creatures.entrySet()) { + Object[] data = {creature.getKey(), creature.getValue()}; + creatureModel.insertRow(0, data); + } + for (Map.Entry plant : theme.vegetation.entrySet()) { + Object[] data = {plant.getKey(), plant.getValue()}; + plantModel.insertRow(0, data); + } + } + + public void mouseEntered(MouseEvent e) {} + + public void mouseExited(MouseEvent e) {} + + public void mousePressed(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + JPopupMenu menu = new JPopupMenu(); + if (e.getSource().equals(creatureTable)) { + menu.add(new ClickAction("Add creature")); + menu.add(new ClickAction("Remove creature")); + int row = creatureTable.rowAtPoint(e.getPoint()); + creatureTable.getSelectionModel().setSelectionInterval(row, row); + } else if (e.getSource().equals(plantTable)) { + menu.add(new ClickAction("Add vegetation")); + menu.add(new ClickAction("Remove vegetation")); + int row = plantTable.rowAtPoint(e.getPoint()); + plantTable.getSelectionModel().setSelectionInterval(row, row); + } + menu.show(e.getComponent(), e.getX(), e.getY()); + } + } + + private class ClickAction extends AbstractAction { + public ClickAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add creature")) { + Object[] creatures = dataStore.getResourceManager().getResources(RCreature.class).toArray(); + String s = + JOptionPane.showInputDialog( + frame, + "Choose creature:", + "Add creature", + JOptionPane.PLAIN_MESSAGE, + null, + creatures, + null) + .toString(); + if (s != null) { + Object[] row = {s, 1}; + creatureModel.addRow(row); + } + } else if (e.getActionCommand().equals("Remove creature")) { + creatureModel.removeRow(creatureTable.getSelectedRow()); + } else if (e.getActionCommand().equals("Add vegetation")) { + Object[] plants = dataStore.getResourceManager().getResources(RItem.class).toArray(); + String s = + JOptionPane.showInputDialog( + frame, + "Choose creature:", + "Add vegetation", + JOptionPane.PLAIN_MESSAGE, + null, + plants, + null) + .toString(); + if (s != null) { + Object[] row = {s, 1}; + plantModel.addRow(row); + } + } else if (e.getActionCommand().equals("Remove vegetation")) { + plantModel.removeRow(plantTable.getSelectedRow()); + } + } + } + + private static class ThemesTableModel extends DefaultTableModel { + private Class[] classes; + + public ThemesTableModel(String[] columns, Class... classes) { + super(columns, 0); + this.classes = classes; + } + + public Class getColumnClass(int i) { + return classes[i]; + } + + public boolean isCellEditable(int row, int column) { + return column != 0; + } + } +} diff --git a/src/main/java/neon/editor/editors/ScrollEditor.java b/src/main/java/neon/editor/editors/ScrollEditor.java index 2244c3c..1bc3b4a 100644 --- a/src/main/java/neon/editor/editors/ScrollEditor.java +++ b/src/main/java/neon/editor/editors/ScrollEditor.java @@ -1,203 +1,209 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.text.ParseException; -import java.util.*; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.*; -import neon.editor.help.HelpLabels; -import neon.resources.RItem; -import neon.resources.RSpell; -import neon.resources.RSpell.SpellType; -import neon.util.ColorFactory; - -public class ScrollEditor extends ObjectEditor { - private JTextField nameField; - private JFormattedTextField costField, weightField, charField; - private JComboBox colorBox; - private JComboBox spellBox; - private JTextArea textArea; - private RItem.Text data; - private Vector spells; - - public ScrollEditor(JFrame parent, RItem.Text data) { - super(parent, "Scroll Editor: " + data.id); - this.data = data; - - JPanel itemProps = new JPanel(); - GroupLayout layout = new GroupLayout(itemProps); - itemProps.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel nameLabel = new JLabel("Name: "); - JLabel costLabel = new JLabel("Cost: "); - JLabel colorLabel = new JLabel("Color: "); - JLabel charLabel = new JLabel("Character: "); - JLabel weightLabel = new JLabel("Weight: "); - JLabel spellLabel = new JLabel("Spell: "); - JLabel textLabel = new JLabel("Text: "); - nameField = new JTextField(15); - costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - colorBox = new JComboBox(ColorFactory.getColorNames()); - colorBox.setBackground(Color.black); - colorBox.setRenderer(new ColorCellRenderer()); - colorBox.addActionListener(new ColorListener(colorBox)); - charField = new JFormattedTextField(getMaskFormatter("*", 'X')); - weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); - loadSpells(); - spellBox = new JComboBox(spells); - textArea = new JTextArea(); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCostHelpLabel(); - JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); - JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); - JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); - JLabel spellHelpLabel = HelpLabels.getSpellHelpLabel(); - JLabel textHelpLabel = HelpLabels.getScrollTextHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(costLabel) - .addComponent(costField) - .addComponent(costHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(colorLabel) - .addComponent(colorBox) - .addComponent(colorHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(charLabel) - .addComponent(charField) - .addComponent(charHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(weightLabel) - .addComponent(weightField) - .addComponent(weightHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(spellLabel) - .addComponent(spellBox) - .addComponent(spellHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(textLabel) - .addComponent(textArea) - .addComponent(textHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(costLabel) - .addComponent(colorLabel) - .addComponent(charLabel) - .addComponent(weightLabel) - .addComponent(spellLabel) - .addComponent(textLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(costField) - .addComponent(colorBox) - .addComponent(charField) - .addComponent(weightField) - .addComponent(spellBox) - .addComponent(textArea)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(costHelpLabel) - .addComponent(colorHelpLabel) - .addComponent(charHelpLabel) - .addComponent(weightHelpLabel) - .addComponent(spellHelpLabel) - .addComponent(textHelpLabel))); - JScrollPane propScroller = new JScrollPane(itemProps); - propScroller.setBorder(new TitledBorder("Properties")); - - frame.add(propScroller, BorderLayout.CENTER); - } - - protected void save() { - data.name = nameField.getText(); - try { // workaround to always get a long value back - costField.commitEdit(); - data.cost = ((Long) costField.getValue()).intValue(); - } catch (ParseException e) { - data.cost = 0; - } - data.color = colorBox.getSelectedItem().toString(); - data.text = charField.getText(); - data.weight = Float.parseFloat(weightField.getText()); - data.content = textArea.getText(); - if (spellBox.getSelectedItem() != null) { - data.spell = spellBox.getSelectedItem().toString(); - } else { - data.spell = null; - } - data.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - nameField.setText(data.name); - costField.setValue(data.cost); - colorBox.setSelectedItem(data.color); - charField.setValue(data.text); - weightField.setValue(data.weight); - textArea.setText(data.content); - spellBox.setSelectedItem(data.spell); - } - - private void loadSpells() { - spells = new Vector(); - for (RSpell spell : Editor.resources.getResources(RSpell.class)) { - if (spell.type.equals(SpellType.SPELL)) { - spells.add(spell.id); - } - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.text.ParseException; +import java.util.*; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.resources.RItem; +import neon.resources.RSpell; +import neon.resources.RSpell.SpellType; +import neon.util.ColorFactory; + +public class ScrollEditor extends ObjectEditor { + private JTextField nameField; + private JFormattedTextField costField, weightField, charField; + private JComboBox colorBox; + private JComboBox spellBox; + private JTextArea textArea; + private RItem.Text data; + private final DataStore dataStore; + private Vector spells; + + private final HelpLabels helpLabels; + + public ScrollEditor(JFrame parent, RItem.Text data, DataStore dataStore) { + super(parent, "Scroll Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + helpLabels = new HelpLabels(dataStore); + JPanel itemProps = new JPanel(); + GroupLayout layout = new GroupLayout(itemProps); + itemProps.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel nameLabel = new JLabel("Name: "); + JLabel costLabel = new JLabel("Cost: "); + JLabel colorLabel = new JLabel("Color: "); + JLabel charLabel = new JLabel("Character: "); + JLabel weightLabel = new JLabel("Weight: "); + JLabel spellLabel = new JLabel("Spell: "); + JLabel textLabel = new JLabel("Text: "); + nameField = new JTextField(15); + costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + colorBox = new JComboBox(ColorFactory.getColorNames()); + colorBox.setBackground(Color.black); + colorBox.setRenderer(new ColorCellRenderer()); + colorBox.addActionListener(new ColorListener(colorBox)); + charField = new JFormattedTextField(getMaskFormatter("*", 'X')); + weightField = new JFormattedTextField(NeonFormat.getFloatInstance()); + loadSpells(); + spellBox = new JComboBox(spells); + textArea = new JTextArea(); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel costHelpLabel = helpLabels.getCostHelpLabel(); + JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); + JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); + JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); + JLabel spellHelpLabel = HelpLabels.getSpellHelpLabel(); + JLabel textHelpLabel = HelpLabels.getScrollTextHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(costLabel) + .addComponent(costField) + .addComponent(costHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(colorLabel) + .addComponent(colorBox) + .addComponent(colorHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(charLabel) + .addComponent(charField) + .addComponent(charHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(weightLabel) + .addComponent(weightField) + .addComponent(weightHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(spellLabel) + .addComponent(spellBox) + .addComponent(spellHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(textLabel) + .addComponent(textArea) + .addComponent(textHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(costLabel) + .addComponent(colorLabel) + .addComponent(charLabel) + .addComponent(weightLabel) + .addComponent(spellLabel) + .addComponent(textLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(costField) + .addComponent(colorBox) + .addComponent(charField) + .addComponent(weightField) + .addComponent(spellBox) + .addComponent(textArea)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(costHelpLabel) + .addComponent(colorHelpLabel) + .addComponent(charHelpLabel) + .addComponent(weightHelpLabel) + .addComponent(spellHelpLabel) + .addComponent(textHelpLabel))); + JScrollPane propScroller = new JScrollPane(itemProps); + propScroller.setBorder(new TitledBorder("Properties")); + + frame.add(propScroller, BorderLayout.CENTER); + } + + protected void save() { + data.name = nameField.getText(); + try { // workaround to always get a long value back + costField.commitEdit(); + data.cost = ((Long) costField.getValue()).intValue(); + } catch (ParseException e) { + data.cost = 0; + } + data.color = colorBox.getSelectedItem().toString(); + data.text = charField.getText(); + data.weight = Float.parseFloat(weightField.getText()); + data.content = textArea.getText(); + if (spellBox.getSelectedItem() != null) { + data.spell = spellBox.getSelectedItem().toString(); + } else { + data.spell = null; + } + data.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + nameField.setText(data.name); + costField.setValue(data.cost); + colorBox.setSelectedItem(data.color); + charField.setValue(data.text); + weightField.setValue(data.weight); + textArea.setText(data.content); + spellBox.setSelectedItem(data.spell); + } + + private void loadSpells() { + spells = new Vector(); + for (RSpell spell : dataStore.getResourceManager().getResources(RSpell.class)) { + if (spell.type.equals(SpellType.SPELL)) { + spells.add(spell.id); + } + } + } +} diff --git a/src/main/java/neon/editor/editors/SignEditor.java b/src/main/java/neon/editor/editors/SignEditor.java index 16b74fb..82dcf04 100644 --- a/src/main/java/neon/editor/editors/SignEditor.java +++ b/src/main/java/neon/editor/editors/SignEditor.java @@ -1,196 +1,198 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import java.awt.event.*; -import java.util.*; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import javax.swing.table.DefaultTableModel; -import neon.editor.Editor; -import neon.editor.help.HelpLabels; -import neon.entities.property.Ability; -import neon.resources.RSign; -import neon.resources.RSpell; - -@SuppressWarnings("serial") -public class SignEditor extends ObjectEditor implements MouseListener { - private DefaultTableModel abilityModel, powerModel; - private JTable abilityTable, powerTable; - private RSign sign; - private JTextField nameField; - - public SignEditor(JFrame parent, RSign sign) { - super(parent, "Birth sign: " + sign.id); - this.sign = sign; - - JLabel nameLabel = new JLabel("Name: "); - nameField = new JTextField(15); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JPanel namePanel = new JPanel(); - namePanel.add(nameLabel); - namePanel.add(nameField); - namePanel.add(new JLabel(" ")); - namePanel.add(nameHelpLabel); - - String[] abilities = {"ability", "magnitude"}; - abilityModel = new SignsTableModel(abilities, Ability.class, Integer.class); - abilityTable = new JTable(abilityModel); - abilityTable.setFillsViewportHeight(true); - abilityTable.addMouseListener(this); - JScrollPane abilityScroller = new JScrollPane(abilityTable); - - String[] powers = {"power"}; - powerModel = new SignsTableModel(powers, String.class); - powerTable = new JTable(powerModel); - powerTable.setFillsViewportHeight(true); - powerTable.addMouseListener(this); - JScrollPane powerScroller = new JScrollPane(powerTable); - - JTabbedPane stuff = new JTabbedPane(); - stuff.add("Abilities", abilityScroller); - stuff.add("Powers", powerScroller); - - JPanel props = new JPanel(new BorderLayout()); - props.add(namePanel, BorderLayout.PAGE_START); - props.add(stuff, BorderLayout.CENTER); - props.setBorder(new TitledBorder("Properties")); - frame.add(props, BorderLayout.CENTER); - } - - protected void save() { - sign.name = nameField.getText(); - sign.abilities.clear(); - for (Vector data : (Vector) abilityModel.getDataVector()) { - sign.abilities.put((Ability) data.get(0), (Integer) data.get(1)); - } - sign.powers.clear(); - for (Vector data : (Vector) powerModel.getDataVector()) { - sign.powers.add(data.get(0).toString()); - } - sign.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - nameField.setText(sign.name); - powerModel.setNumRows(0); - abilityModel.setNumRows(0); - for (String power : sign.powers) { - String[] data = {power}; - powerModel.insertRow(0, data); - } - for (Map.Entry ability : sign.abilities.entrySet()) { - Object[] data = {ability.getKey(), ability.getValue()}; - abilityModel.insertRow(0, data); - } - } - - public void mousePressed(MouseEvent e) {} - - public void mouseReleased(MouseEvent e) {} - - public void mouseEntered(MouseEvent e) {} - - public void mouseExited(MouseEvent e) {} - - public void mouseClicked(MouseEvent e) { - if (e.getButton() == MouseEvent.BUTTON3) { - JPopupMenu menu = new JPopupMenu(); - if (e.getSource().equals(powerTable)) { - menu.add(new ClickAction("Add power")); - menu.add(new ClickAction("Remove power")); - int row = powerTable.rowAtPoint(e.getPoint()); - powerTable.getSelectionModel().setSelectionInterval(row, row); - } else if (e.getSource().equals(abilityTable)) { - menu.add(new ClickAction("Add ability")); - menu.add(new ClickAction("Remove ability")); - int row = abilityTable.rowAtPoint(e.getPoint()); - abilityTable.getSelectionModel().setSelectionInterval(row, row); - } - menu.show(e.getComponent(), e.getX(), e.getY()); - } - } - - private class ClickAction extends AbstractAction { - public ClickAction(String name) { - super(name); - } - - public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Add power")) { - ArrayList powers = new ArrayList(); - for (RSpell.Power power : Editor.resources.getResources(RSpell.Power.class)) { - powers.add(power.id); - } - String s = - (String) - JOptionPane.showInputDialog( - frame, - "Choose power:", - "Add power", - JOptionPane.PLAIN_MESSAGE, - null, - powers.toArray(), - null); - if (s != null) { - String[] row = {s}; - powerModel.addRow(row); - } - } else if (e.getActionCommand().equals("Remove power")) { - powerModel.removeRow(powerTable.getSelectedRow()); - } else if (e.getActionCommand().equals("Add ability")) { - Object[] abilities = Ability.values(); - Ability a = - (Ability) - JOptionPane.showInputDialog( - frame, - "Choose ability:", - "Add ability", - JOptionPane.PLAIN_MESSAGE, - null, - abilities, - null); - if (a != null) { - Object[] row = {a, 0}; - abilityModel.addRow(row); - } - } else if (e.getActionCommand().equals("Remove ability")) { - abilityModel.removeRow(abilityTable.getSelectedRow()); - } - } - } - - private static class SignsTableModel extends DefaultTableModel { - private Class[] classes; - - public SignsTableModel(String[] columns, Class... classes) { - super(columns, 0); - this.classes = classes; - } - - public Class getColumnClass(int i) { - return classes[i]; - } - - public boolean isCellEditable(int row, int column) { - return column != 0; - } - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.swing.table.DefaultTableModel; +import neon.editor.DataStore; +import neon.editor.help.HelpLabels; +import neon.entities.property.Ability; +import neon.resources.RSign; +import neon.resources.RSpell; + +@SuppressWarnings("serial") +public class SignEditor extends ObjectEditor implements MouseListener { + private DefaultTableModel abilityModel, powerModel; + private JTable abilityTable, powerTable; + private RSign sign; + private JTextField nameField; + private final DataStore dataStore; + + public SignEditor(JFrame parent, RSign sign, DataStore dataStore) { + super(parent, "Birth sign: " + sign.id); + this.sign = sign; + this.dataStore = dataStore; + + JLabel nameLabel = new JLabel("Name: "); + nameField = new JTextField(15); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JPanel namePanel = new JPanel(); + namePanel.add(nameLabel); + namePanel.add(nameField); + namePanel.add(new JLabel(" ")); + namePanel.add(nameHelpLabel); + + String[] abilities = {"ability", "magnitude"}; + abilityModel = new SignsTableModel(abilities, Ability.class, Integer.class); + abilityTable = new JTable(abilityModel); + abilityTable.setFillsViewportHeight(true); + abilityTable.addMouseListener(this); + JScrollPane abilityScroller = new JScrollPane(abilityTable); + + String[] powers = {"power"}; + powerModel = new SignsTableModel(powers, String.class); + powerTable = new JTable(powerModel); + powerTable.setFillsViewportHeight(true); + powerTable.addMouseListener(this); + JScrollPane powerScroller = new JScrollPane(powerTable); + + JTabbedPane stuff = new JTabbedPane(); + stuff.add("Abilities", abilityScroller); + stuff.add("Powers", powerScroller); + + JPanel props = new JPanel(new BorderLayout()); + props.add(namePanel, BorderLayout.PAGE_START); + props.add(stuff, BorderLayout.CENTER); + props.setBorder(new TitledBorder("Properties")); + frame.add(props, BorderLayout.CENTER); + } + + protected void save() { + sign.name = nameField.getText(); + sign.abilities.clear(); + for (Vector data : (Vector) abilityModel.getDataVector()) { + sign.abilities.put((Ability) data.get(0), (Integer) data.get(1)); + } + sign.powers.clear(); + for (Vector data : (Vector) powerModel.getDataVector()) { + sign.powers.add(data.get(0).toString()); + } + sign.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + nameField.setText(sign.name); + powerModel.setNumRows(0); + abilityModel.setNumRows(0); + for (String power : sign.powers) { + String[] data = {power}; + powerModel.insertRow(0, data); + } + for (Map.Entry ability : sign.abilities.entrySet()) { + Object[] data = {ability.getKey(), ability.getValue()}; + abilityModel.insertRow(0, data); + } + } + + public void mousePressed(MouseEvent e) {} + + public void mouseReleased(MouseEvent e) {} + + public void mouseEntered(MouseEvent e) {} + + public void mouseExited(MouseEvent e) {} + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON3) { + JPopupMenu menu = new JPopupMenu(); + if (e.getSource().equals(powerTable)) { + menu.add(new ClickAction("Add power")); + menu.add(new ClickAction("Remove power")); + int row = powerTable.rowAtPoint(e.getPoint()); + powerTable.getSelectionModel().setSelectionInterval(row, row); + } else if (e.getSource().equals(abilityTable)) { + menu.add(new ClickAction("Add ability")); + menu.add(new ClickAction("Remove ability")); + int row = abilityTable.rowAtPoint(e.getPoint()); + abilityTable.getSelectionModel().setSelectionInterval(row, row); + } + menu.show(e.getComponent(), e.getX(), e.getY()); + } + } + + private class ClickAction extends AbstractAction { + public ClickAction(String name) { + super(name); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Add power")) { + ArrayList powers = new ArrayList(); + for (RSpell.Power power : dataStore.getResourceManager().getResources(RSpell.Power.class)) { + powers.add(power.id); + } + String s = + (String) + JOptionPane.showInputDialog( + frame, + "Choose power:", + "Add power", + JOptionPane.PLAIN_MESSAGE, + null, + powers.toArray(), + null); + if (s != null) { + String[] row = {s}; + powerModel.addRow(row); + } + } else if (e.getActionCommand().equals("Remove power")) { + powerModel.removeRow(powerTable.getSelectedRow()); + } else if (e.getActionCommand().equals("Add ability")) { + Object[] abilities = Ability.values(); + Ability a = + (Ability) + JOptionPane.showInputDialog( + frame, + "Choose ability:", + "Add ability", + JOptionPane.PLAIN_MESSAGE, + null, + abilities, + null); + if (a != null) { + Object[] row = {a, 0}; + abilityModel.addRow(row); + } + } else if (e.getActionCommand().equals("Remove ability")) { + abilityModel.removeRow(abilityTable.getSelectedRow()); + } + } + } + + private static class SignsTableModel extends DefaultTableModel { + private Class[] classes; + + public SignsTableModel(String[] columns, Class... classes) { + super(columns, 0); + this.classes = classes; + } + + public Class getColumnClass(int i) { + return classes[i]; + } + + public boolean isCellEditable(int row, int column) { + return column != 0; + } + } +} diff --git a/src/main/java/neon/editor/editors/SpellEditor.java b/src/main/java/neon/editor/editors/SpellEditor.java index f91d124..0a319b1 100644 --- a/src/main/java/neon/editor/editors/SpellEditor.java +++ b/src/main/java/neon/editor/editors/SpellEditor.java @@ -22,7 +22,7 @@ import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.NeonFormat; import neon.editor.help.HelpLabels; import neon.magic.Effect; @@ -34,10 +34,12 @@ public class SpellEditor extends ObjectEditor implements ActionListener { private JComboBox effectBox; private JTextArea scriptArea; private RSpell data; + private final DataStore dataStore; - public SpellEditor(JFrame parent, RSpell data) { + public SpellEditor(JFrame parent, RSpell data, DataStore dataStore) { super(parent, "Spell: " + data.id); this.data = data; + this.dataStore = dataStore; JPanel props = new JPanel(); GroupLayout layout = new GroupLayout(props); @@ -167,7 +169,7 @@ protected void save() { data.effect = effectBox.getItemAt(effectBox.getSelectedIndex()); data.duration = Integer.parseInt(durationField.getText()); data.script = scriptArea.getText(); - data.setPath(Editor.getStore().getActive().get("id")); + data.setPath(dataStore.getActive().get("id")); } public void actionPerformed(ActionEvent e) { diff --git a/src/main/java/neon/editor/editors/TattooEditor.java b/src/main/java/neon/editor/editors/TattooEditor.java index 5fac40d..c98977f 100644 --- a/src/main/java/neon/editor/editors/TattooEditor.java +++ b/src/main/java/neon/editor/editors/TattooEditor.java @@ -1,123 +1,125 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import javax.swing.*; -import javax.swing.border.TitledBorder; -import neon.editor.Editor; -import neon.editor.NeonFormat; -import neon.editor.help.HelpLabels; -import neon.entities.property.Ability; -import neon.resources.RTattoo; - -public class TattooEditor extends ObjectEditor { - private RTattoo tattoo; - private JComboBox abilityBox; - private JSpinner abilitySpinner; - private JTextField nameField; - private JFormattedTextField costField; - - public TattooEditor(JFrame parent, RTattoo tattoo) { - super(parent, "Tattoo: " + tattoo.id); - this.tattoo = tattoo; - - JPanel abilityPanel = new JPanel(); - abilityPanel.setBorder(new TitledBorder("Properties")); - JLabel nameLabel = new JLabel("Name: "); - JLabel abilityLabel = new JLabel("Ability: "); - JLabel costLabel = new JLabel("Price: "); - nameField = new JTextField(15); - abilityBox = new JComboBox(Ability.values()); - abilitySpinner = new JSpinner(new SpinnerNumberModel(0, 0, 100, 1)); - costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); - JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel abilityHelpLabel = HelpLabels.getTattooAbilityHelpLabel(); - frame.add(abilityPanel, BorderLayout.CENTER); - - GroupLayout layout = new GroupLayout(abilityPanel); - abilityPanel.setLayout(layout); - layout.setAutoCreateGaps(true); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(nameLabel) - .addComponent(nameField) - .addComponent(nameHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(abilityLabel) - .addComponent(abilityBox) - .addComponent(abilitySpinner) - .addComponent(abilityHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(costLabel) - .addComponent(costField))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(abilityLabel) - .addComponent(costLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent( - nameField, - GroupLayout.PREFERRED_SIZE, - GroupLayout.DEFAULT_SIZE, - GroupLayout.PREFERRED_SIZE) - .addComponent(abilityBox) - .addComponent(costField)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(abilitySpinner)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(nameHelpLabel) - .addComponent(abilityHelpLabel))); - } - - protected void save() { - tattoo.name = nameField.getText(); - tattoo.ability = (Ability) abilityBox.getSelectedItem(); - tattoo.magnitude = (Integer) abilitySpinner.getValue(); - tattoo.cost = Integer.parseInt(costField.getText()); - tattoo.setPath(Editor.getStore().getActive().get("id")); - } - - protected void load() { - nameField.setText(tattoo.name); - costField.setValue(tattoo.cost); - abilityBox.setSelectedItem(tattoo.ability); - abilitySpinner.setValue(tattoo.magnitude); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import neon.editor.DataStore; +import neon.editor.NeonFormat; +import neon.editor.help.HelpLabels; +import neon.entities.property.Ability; +import neon.resources.RTattoo; + +public class TattooEditor extends ObjectEditor { + private RTattoo tattoo; + private JComboBox abilityBox; + private JSpinner abilitySpinner; + private JTextField nameField; + private JFormattedTextField costField; + private final DataStore dataStore; + + public TattooEditor(JFrame parent, RTattoo tattoo, DataStore dataStore) { + super(parent, "Tattoo: " + tattoo.id); + this.tattoo = tattoo; + this.dataStore = dataStore; + + JPanel abilityPanel = new JPanel(); + abilityPanel.setBorder(new TitledBorder("Properties")); + JLabel nameLabel = new JLabel("Name: "); + JLabel abilityLabel = new JLabel("Ability: "); + JLabel costLabel = new JLabel("Price: "); + nameField = new JTextField(15); + abilityBox = new JComboBox(Ability.values()); + abilitySpinner = new JSpinner(new SpinnerNumberModel(0, 0, 100, 1)); + costField = new JFormattedTextField(NeonFormat.getIntegerInstance()); + JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); + JLabel abilityHelpLabel = HelpLabels.getTattooAbilityHelpLabel(); + frame.add(abilityPanel, BorderLayout.CENTER); + + GroupLayout layout = new GroupLayout(abilityPanel); + abilityPanel.setLayout(layout); + layout.setAutoCreateGaps(true); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameField) + .addComponent(nameHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(abilityLabel) + .addComponent(abilityBox) + .addComponent(abilitySpinner) + .addComponent(abilityHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(costLabel) + .addComponent(costField))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(nameLabel) + .addComponent(abilityLabel) + .addComponent(costLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent( + nameField, + GroupLayout.PREFERRED_SIZE, + GroupLayout.DEFAULT_SIZE, + GroupLayout.PREFERRED_SIZE) + .addComponent(abilityBox) + .addComponent(costField)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(abilitySpinner)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(nameHelpLabel) + .addComponent(abilityHelpLabel))); + } + + protected void save() { + tattoo.name = nameField.getText(); + tattoo.ability = (Ability) abilityBox.getSelectedItem(); + tattoo.magnitude = (Integer) abilitySpinner.getValue(); + tattoo.cost = Integer.parseInt(costField.getText()); + tattoo.setPath(dataStore.getActive().get("id")); + } + + protected void load() { + nameField.setText(tattoo.name); + costField.setValue(tattoo.cost); + abilityBox.setSelectedItem(tattoo.ability); + abilitySpinner.setValue(tattoo.magnitude); + } +} diff --git a/src/main/java/neon/editor/editors/TerrainEditor.java b/src/main/java/neon/editor/editors/TerrainEditor.java index cebf01f..7ba6e40 100644 --- a/src/main/java/neon/editor/editors/TerrainEditor.java +++ b/src/main/java/neon/editor/editors/TerrainEditor.java @@ -1,118 +1,120 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2012 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.editors; - -import java.awt.*; -import javax.swing.*; -import javax.swing.border.*; -import neon.editor.ColorCellRenderer; -import neon.editor.Editor; -import neon.editor.help.HelpLabels; -import neon.maps.Region.Modifier; -import neon.resources.RTerrain; -import neon.util.ColorFactory; - -public class TerrainEditor extends ObjectEditor { - private JFormattedTextField charField; - private JComboBox colorBox; - private JComboBox modBox; - private RTerrain data; - - public TerrainEditor(JFrame parent, RTerrain data) { - super(parent, "Terrain Editor: " + data.id); - this.data = data; - - JPanel terrainProps = new JPanel(); - GroupLayout layout = new GroupLayout(terrainProps); - terrainProps.setLayout(layout); - layout.setAutoCreateGaps(true); - - JLabel colorLabel = new JLabel("Color: "); - JLabel charLabel = new JLabel("Character: "); - JLabel modLabel = new JLabel("Modifier: "); - colorBox = new JComboBox(ColorFactory.getColorNames()); - colorBox.setBackground(Color.black); - colorBox.setRenderer(new ColorCellRenderer()); - colorBox.addActionListener(new ColorListener(colorBox)); - charField = new JFormattedTextField(getMaskFormatter("*", 'X')); - modBox = new JComboBox(Modifier.values()); - JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); - JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); - JLabel modHelpLabel = HelpLabels.getTerrainHelpLabel(); - layout.setVerticalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(colorLabel) - .addComponent(colorBox) - .addComponent(colorHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(charLabel) - .addComponent(charField) - .addComponent(charHelpLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(modLabel) - .addComponent(modBox) - .addComponent(modHelpLabel))); - layout.setHorizontalGroup( - layout - .createSequentialGroup() - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(colorLabel) - .addComponent(charLabel) - .addComponent(modLabel)) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(colorBox) - .addComponent(charField) - .addComponent(modBox)) - .addGap(10) - .addGroup( - layout - .createParallelGroup(GroupLayout.Alignment.LEADING, false) - .addComponent(colorHelpLabel) - .addComponent(charHelpLabel) - .addComponent(modHelpLabel))); - JScrollPane propScroller = new JScrollPane(terrainProps); - propScroller.setBorder(new TitledBorder("Properties")); - frame.add(propScroller, BorderLayout.CENTER); - } - - protected void load() { - colorBox.setSelectedItem(data.color); - charField.setValue(data.text); - modBox.setSelectedItem(data.modifier); - } - - protected void save() { - data.color = colorBox.getSelectedItem().toString(); - data.text = charField.getText(); - data.modifier = (Modifier) modBox.getSelectedItem(); - data.setPath(Editor.getStore().getActive().get("id")); - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.editor.editors; + +import java.awt.*; +import javax.swing.*; +import javax.swing.border.*; +import neon.editor.ColorCellRenderer; +import neon.editor.DataStore; +import neon.editor.help.HelpLabels; +import neon.maps.Region.Modifier; +import neon.resources.RTerrain; +import neon.util.ColorFactory; + +public class TerrainEditor extends ObjectEditor { + private JFormattedTextField charField; + private JComboBox colorBox; + private JComboBox modBox; + private RTerrain data; + private final DataStore dataStore; + + public TerrainEditor(JFrame parent, RTerrain data, DataStore dataStore) { + super(parent, "Terrain Editor: " + data.id); + this.data = data; + this.dataStore = dataStore; + + JPanel terrainProps = new JPanel(); + GroupLayout layout = new GroupLayout(terrainProps); + terrainProps.setLayout(layout); + layout.setAutoCreateGaps(true); + + JLabel colorLabel = new JLabel("Color: "); + JLabel charLabel = new JLabel("Character: "); + JLabel modLabel = new JLabel("Modifier: "); + colorBox = new JComboBox(ColorFactory.getColorNames()); + colorBox.setBackground(Color.black); + colorBox.setRenderer(new ColorCellRenderer()); + colorBox.addActionListener(new ColorListener(colorBox)); + charField = new JFormattedTextField(getMaskFormatter("*", 'X')); + modBox = new JComboBox(Modifier.values()); + JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); + JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); + JLabel modHelpLabel = HelpLabels.getTerrainHelpLabel(); + layout.setVerticalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(colorLabel) + .addComponent(colorBox) + .addComponent(colorHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(charLabel) + .addComponent(charField) + .addComponent(charHelpLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(modLabel) + .addComponent(modBox) + .addComponent(modHelpLabel))); + layout.setHorizontalGroup( + layout + .createSequentialGroup() + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(colorLabel) + .addComponent(charLabel) + .addComponent(modLabel)) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(colorBox) + .addComponent(charField) + .addComponent(modBox)) + .addGap(10) + .addGroup( + layout + .createParallelGroup(GroupLayout.Alignment.LEADING, false) + .addComponent(colorHelpLabel) + .addComponent(charHelpLabel) + .addComponent(modHelpLabel))); + JScrollPane propScroller = new JScrollPane(terrainProps); + propScroller.setBorder(new TitledBorder("Properties")); + frame.add(propScroller, BorderLayout.CENTER); + } + + protected void load() { + colorBox.setSelectedItem(data.color); + charField.setValue(data.text); + modBox.setSelectedItem(data.modifier); + } + + protected void save() { + data.color = colorBox.getSelectedItem().toString(); + data.text = charField.getText(); + data.modifier = (Modifier) modBox.getSelectedItem(); + data.setPath(dataStore.getActive().get("id")); + } +} diff --git a/src/main/java/neon/editor/editors/WeaponEditor.java b/src/main/java/neon/editor/editors/WeaponEditor.java index 313545d..78458bc 100644 --- a/src/main/java/neon/editor/editors/WeaponEditor.java +++ b/src/main/java/neon/editor/editors/WeaponEditor.java @@ -23,7 +23,7 @@ import javax.swing.*; import javax.swing.border.*; import neon.editor.ColorCellRenderer; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.NeonFormat; import neon.editor.help.HelpLabels; import neon.resources.RSpell; @@ -32,18 +32,23 @@ import neon.util.ColorFactory; public class WeaponEditor extends ObjectEditor { - private JTextField nameField; - private JFormattedTextField costField, weightField, charField; - private JComboBox colorBox; - private JComboBox spellBox; - private JComboBox typeBox; - private JTextField damageField; - private RWeapon data; + private final JTextField nameField; + private final JFormattedTextField costField; + private final JFormattedTextField weightField; + private final JFormattedTextField charField; + private final JComboBox colorBox; + private final JComboBox spellBox; + private final JComboBox typeBox; + private final JTextField damageField; + private final RWeapon data; + private final DataStore dataStore; + private final HelpLabels helpLabels; - public WeaponEditor(JFrame parent, RWeapon data) { + public WeaponEditor(JFrame parent, RWeapon data, DataStore dataStore) { super(parent, "Weapon Editor: " + data.id); this.data = data; - + this.dataStore = dataStore; + helpLabels = new HelpLabels(dataStore); JPanel itemProps = new JPanel(); GroupLayout layout = new GroupLayout(itemProps); itemProps.setLayout(layout); @@ -69,7 +74,7 @@ public WeaponEditor(JFrame parent, RWeapon data) { damageField = new JTextField(10); spellBox = new JComboBox(loadSpells()); JLabel nameHelpLabel = HelpLabels.getNameHelpLabel(); - JLabel costHelpLabel = HelpLabels.getCostHelpLabel(); + JLabel costHelpLabel = helpLabels.getCostHelpLabel(); JLabel colorHelpLabel = HelpLabels.getColorHelpLabel(); JLabel charHelpLabel = HelpLabels.getCharHelpLabel(); JLabel weightHelpLabel = HelpLabels.getWeightHelpLabel(); @@ -181,7 +186,7 @@ protected void save() { data.weight = Float.parseFloat(weightField.getText()); data.damage = damageField.getText(); data.weaponType = typeBox.getItemAt(typeBox.getSelectedIndex()); - data.setPath(Editor.getStore().getActive().get("id")); + data.setPath(dataStore.getActive().get("id")); if (spellBox.getSelectedItem() != null) { data.spell = spellBox.getSelectedItem().toString(); } else { @@ -203,7 +208,8 @@ protected void load() { private Vector loadSpells() { Vector spells = new Vector(); spells.add(null); - for (RSpell.Enchantment spell : Editor.resources.getResources(RSpell.Enchantment.class)) { + for (RSpell.Enchantment spell : + dataStore.getResourceManager().getResources(RSpell.Enchantment.class)) { if (spell.item.equals("weapon")) { spells.add(spell.id); } diff --git a/src/main/java/neon/editor/editors/ZoneThemeEditor.java b/src/main/java/neon/editor/editors/ZoneThemeEditor.java index 5fd650f..090ea54 100644 --- a/src/main/java/neon/editor/editors/ZoneThemeEditor.java +++ b/src/main/java/neon/editor/editors/ZoneThemeEditor.java @@ -25,7 +25,7 @@ import javax.swing.border.*; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.NeonFormat; import neon.editor.help.HelpLabels; import neon.resources.RCreature; @@ -41,10 +41,12 @@ public class ZoneThemeEditor extends ObjectEditor implements MouseListener { private JTable creatureTable, itemTable, featureTable; private RZoneTheme theme; private JComboBox typeBox; + private final DataStore dataStore; - public ZoneThemeEditor(JFrame parent, RZoneTheme theme) { + public ZoneThemeEditor(JFrame parent, RZoneTheme theme, DataStore dataStore) { super(parent, "Zone theme: " + theme.id); this.theme = theme; + this.dataStore = dataStore; JPanel props = new JPanel(); GroupLayout layout = new GroupLayout(props); @@ -197,7 +199,7 @@ protected void save() { theme.doors = doorsField.getText(); theme.min = Integer.parseInt(minField.getText()); theme.max = Integer.parseInt(maxField.getText()); - theme.setPath(Editor.getStore().getActive().get("id")); + theme.setPath(dataStore.getActive().get("id")); theme.creatures.clear(); for (Vector data : (Vector) creatureModel.getDataVector()) { @@ -286,7 +288,7 @@ public ClickAction(String name) { public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Add item")) { - Object[] items = Editor.resources.getResources(RItem.class).toArray(); + Object[] items = dataStore.getResourceManager().getResources(RItem.class).toArray(); String s = (String) JOptionPane.showInputDialog( @@ -304,7 +306,7 @@ public void actionPerformed(ActionEvent e) { } else if (e.getActionCommand().equals("Remove item")) { itemModel.removeRow(itemTable.getSelectedRow()); } else if (e.getActionCommand().equals("Add feature")) { - Object[] terrain = Editor.resources.getResources(RTerrain.class).toArray(); + Object[] terrain = dataStore.getResourceManager().getResources(RTerrain.class).toArray(); String s = (String) JOptionPane.showInputDialog( @@ -322,7 +324,7 @@ public void actionPerformed(ActionEvent e) { } else if (e.getActionCommand().equals("Remove feature")) { featureModel.removeRow(featureTable.getSelectedRow()); } else if (e.getActionCommand().equals("Add creature")) { - Object[] creatures = Editor.resources.getResources(RCreature.class).toArray(); + Object[] creatures = dataStore.getResourceManager().getResources(RCreature.class).toArray(); String s = JOptionPane.showInputDialog( frame, diff --git a/src/main/java/neon/editor/help/HelpLabels.java b/src/main/java/neon/editor/help/HelpLabels.java index 5fd998e..5c01ba6 100644 --- a/src/main/java/neon/editor/help/HelpLabels.java +++ b/src/main/java/neon/editor/help/HelpLabels.java @@ -23,10 +23,15 @@ import javax.swing.JLabel; import javax.swing.ToolTipManager; import javax.swing.border.EtchedBorder; -import neon.editor.Editor; +import neon.editor.DataStore; public class HelpLabels { private static ToolTipListener listener = new ToolTipListener(); + private final DataStore dataStore; + + public HelpLabels(DataStore dataStore) { + this.dataStore = dataStore; + } public static JLabel getAggressionHelpLabel() { return getLabel( @@ -139,13 +144,12 @@ public static JLabel getConHelpLabel() { "Constitution determines healing rate, starting health and speed increases on level up."); } - public static JLabel getCostHelpLabel() { - return getLabel("The cost of this item in " + Editor.getStore().getActive().get("small") + "."); + public JLabel getCostHelpLabel() { + return getLabel("The cost of this item in " + dataStore.getActive().get("small") + "."); } - public static JLabel getCraftingCostHelpLabel() { - return getLabel( - "The cost to craft this item (in " + Editor.getStore().getActive().get("small") + ")."); + public JLabel getCraftingCostHelpLabel() { + return getLabel("The cost to craft this item (in " + dataStore.getActive().get("small") + ")."); } public static JLabel getCreatureTypeHelpLabel() { diff --git a/src/main/java/neon/editor/maps/ContainerInstanceEditor.java b/src/main/java/neon/editor/maps/ContainerInstanceEditor.java index f1be72f..6a44eff 100644 --- a/src/main/java/neon/editor/maps/ContainerInstanceEditor.java +++ b/src/main/java/neon/editor/maps/ContainerInstanceEditor.java @@ -23,7 +23,7 @@ import java.util.*; import javax.swing.*; import javax.swing.border.TitledBorder; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.help.HelpLabels; import neon.editor.resources.IContainer; import neon.editor.resources.IObject; @@ -42,11 +42,14 @@ public class ContainerInstanceEditor implements ActionListener, MouseListener { private JSpinner lockSpinner, trapSpinner; private JComboBox keyBox; private JComboBox spellBox; + private final DataStore dataStore; - public ContainerInstanceEditor(IContainer ic, JFrame parent, ZoneTreeNode node) { + public ContainerInstanceEditor( + IContainer ic, JFrame parent, ZoneTreeNode node, DataStore dataStore) { container = ic; this.node = node; frame = new JDialog(parent, "Container instance editor: " + container.resource.id); + this.dataStore = dataStore; JPanel content = new JPanel(new BorderLayout()); frame.setContentPane(content); @@ -190,7 +193,7 @@ private void initContainer() { } // keys laden - for (RItem ri : Editor.resources.getResources(RItem.class)) { + for (RItem ri : dataStore.getResourceManager().getResources(RItem.class)) { if (ri.type == Type.item) { keyBox.addItem(ri); } @@ -202,7 +205,8 @@ private void initContainer() { keyBox.setSelectedItem(container.key); // spells laden - for (RSpell.Enchantment rs : Editor.resources.getResources(RSpell.Enchantment.class)) { + for (RSpell.Enchantment rs : + dataStore.getResourceManager().getResources(RSpell.Enchantment.class)) { if (rs.item.equals("trap")) { spellBox.addItem(rs); } @@ -280,13 +284,13 @@ public ItemListAction(String name) { public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Add item")) { - Object[] items = Editor.resources.getResources(RItem.class).toArray(); + Object[] items = dataStore.getResourceManager().getResources(RItem.class).toArray(); RItem ri = (RItem) JOptionPane.showInputDialog( frame, "Add item:", "Add item", JOptionPane.PLAIN_MESSAGE, null, items, 0); if (ri != null) { - IObject io = new IObject(ri, 0, 0, 0, 0); + IObject io = new IObject(ri, 0, 0, 0, 0, dataStore); model.addElement(io); } } else if (e.getActionCommand().equals("Delete item")) { diff --git a/src/main/java/neon/editor/maps/DoorInstanceEditor.java b/src/main/java/neon/editor/maps/DoorInstanceEditor.java index 485642a..1f4a94c 100644 --- a/src/main/java/neon/editor/maps/DoorInstanceEditor.java +++ b/src/main/java/neon/editor/maps/DoorInstanceEditor.java @@ -25,7 +25,7 @@ import java.text.NumberFormat; import javax.swing.*; import javax.swing.border.TitledBorder; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.help.HelpLabels; import neon.editor.resources.IDoor; import neon.editor.resources.RMap; @@ -48,9 +48,11 @@ public class DoorInstanceEditor implements ActionListener, ItemListener { private JComboBox stateBox; private JComboBox keyBox; private JComboBox spellBox; + private final DataStore dataStore; - public DoorInstanceEditor(IDoor door, JFrame parent) { + public DoorInstanceEditor(IDoor door, JFrame parent, DataStore dataStore) { this.door = door; + this.dataStore = dataStore; frame = new JDialog(parent, "Door instance editor: " + door.resource.id); JPanel content = new JPanel(new BorderLayout()); frame.setContentPane(content); @@ -273,7 +275,7 @@ public void show() { public void initDoor() { // maps laden - for (RMap map : Editor.resources.getResources(RMap.class)) { + for (RMap map : dataStore.getResourceManager().getResources(RMap.class)) { mapBox.addItem(map); } @@ -285,7 +287,7 @@ public void initDoor() { } // themes laden - for (RDungeonTheme theme : Editor.resources.getResources(RDungeonTheme.class)) { + for (RDungeonTheme theme : dataStore.getResourceManager().getResources(RDungeonTheme.class)) { themeBox.addItem(theme); } @@ -307,7 +309,7 @@ public void initDoor() { } // keys laden - for (RItem ri : Editor.resources.getResources(RItem.class)) { + for (RItem ri : dataStore.getResourceManager().getResources(RItem.class)) { if (ri.type == Type.item) { keyBox.addItem(ri); } @@ -321,7 +323,8 @@ public void initDoor() { keyBox.setSelectedItem(door.key); stateBox.setSelectedItem(door.state); // spells laden - for (RSpell.Enchantment rs : Editor.resources.getResources(RSpell.Enchantment.class)) { + for (RSpell.Enchantment rs : + dataStore.getResourceManager().getResources(RSpell.Enchantment.class)) { if (rs.item.equals("trap")) { spellBox.addItem(rs); } diff --git a/src/main/java/neon/editor/maps/EditablePane.java b/src/main/java/neon/editor/maps/EditablePane.java index 73a96fd..60dd4c4 100644 --- a/src/main/java/neon/editor/maps/EditablePane.java +++ b/src/main/java/neon/editor/maps/EditablePane.java @@ -21,6 +21,7 @@ import java.awt.*; import java.awt.event.*; import javax.swing.*; +import neon.editor.DataStore; import neon.editor.Editor; import neon.editor.ObjectTransferHandler; import neon.editor.resources.IContainer; @@ -49,9 +50,11 @@ public class EditablePane extends JScrollPane private Dimension delta; private JVectorPane pane; private IRegion newRegion; + private final DataStore dataStore; /** Initializes this EditablePane. */ - public EditablePane(ZoneTreeNode node, float width, float height) { + public EditablePane(ZoneTreeNode node, float width, float height, DataStore dataStore) { + this.dataStore = dataStore; if (node.getZone().getScene() == null) { node.getZone().map.load(); } @@ -115,9 +118,10 @@ public void mouseClicked(MouseEvent e) { Renderable selected = pane.getSelectedObject(); if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1 && selected != null) { if (selected instanceof IDoor) { - new DoorInstanceEditor((IDoor) selected, Editor.getFrame()).show(); + new DoorInstanceEditor((IDoor) selected, Editor.getFrame(), dataStore).show(); } else if (selected instanceof IContainer) { - new ContainerInstanceEditor((IContainer) selected, Editor.getFrame(), node).show(); + new ContainerInstanceEditor((IContainer) selected, Editor.getFrame(), node, dataStore) + .show(); } } else if (e.getButton() == MouseEvent.BUTTON3) { JPopupMenu menu = new JPopupMenu(); @@ -174,7 +178,7 @@ public void mousePressed(MouseEvent e) { region.setAttribute("w", "1"); region.setAttribute("h", "1"); region.setAttribute("l", Integer.toString(layer)); - newRegion = new IRegion(region); + newRegion = new IRegion(region, dataStore); scene.addElement(newRegion, newRegion.getBounds(), newRegion.z); } } else { @@ -244,7 +248,8 @@ private Instance clone(Instance original) { (int) (y / pane.getZoom()), original.getZ(), original.width, - original.height); + original.height, + dataStore); } else if (original instanceof IObject) { // copy state of doors and containers -> no? cloneElement.setAttribute("id", originalElement.getAttributeValue("id")); @@ -254,7 +259,8 @@ private Instance clone(Instance original) { (int) (x / pane.getZoom()), (int) (y / pane.getZoom()), original.getZ(), - 0); + 0, + dataStore); } return clone; } @@ -299,11 +305,12 @@ public void actionPerformed(ActionEvent e) { } } else if (e.getActionCommand().equals("Properties...")) { if (selected instanceof IDoor) { - new DoorInstanceEditor((IDoor) selected, Editor.getFrame()).show(); + new DoorInstanceEditor((IDoor) selected, Editor.getFrame(), dataStore).show(); } else if (selected instanceof IContainer) { - new ContainerInstanceEditor((IContainer) selected, Editor.getFrame(), node).show(); + new ContainerInstanceEditor((IContainer) selected, Editor.getFrame(), node, dataStore) + .show(); } else if (selected instanceof IRegion) { - new RegionInstanceEditor((IRegion) selected, Editor.getFrame(), node).show(); + new RegionInstanceEditor((IRegion) selected, Editor.getFrame(), node, dataStore).show(); } } repaint(); diff --git a/src/main/java/neon/editor/maps/LevelDialog.java b/src/main/java/neon/editor/maps/LevelDialog.java index f9c1489..ac2126a 100644 --- a/src/main/java/neon/editor/maps/LevelDialog.java +++ b/src/main/java/neon/editor/maps/LevelDialog.java @@ -22,7 +22,7 @@ import java.awt.event.*; import javax.swing.*; import javax.swing.border.EmptyBorder; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.resources.RTerrain; import neon.resources.RZoneTheme; @@ -33,6 +33,11 @@ public class LevelDialog implements ActionListener { private JComboBox terrainBox, randomBox; private boolean cancelled; private JTextField nameField; + private final DataStore dataStore; + + public LevelDialog(DataStore dataStore) { + this.dataStore = dataStore; + } public Properties showInputDialog(JFrame frame) { dialog = new JDialog(frame, "Create new zone", true); @@ -52,7 +57,7 @@ public Properties showInputDialog(JFrame frame) { // terrain kiezen terrainBox = new JComboBox(); - for (RTerrain terrain : Editor.resources.getResources(RTerrain.class)) { + for (RTerrain terrain : dataStore.getResourceManager().getResources(RTerrain.class)) { terrainBox.addItem(terrain.id); } mapPanel.add(new JLabel("Base terrain: ")); @@ -61,7 +66,7 @@ public Properties showInputDialog(JFrame frame) { // random dungeon randomBox = new JComboBox(); randomBox.addItem("none"); - for (RZoneTheme theme : Editor.resources.getResources(RZoneTheme.class)) { + for (RZoneTheme theme : dataStore.getResourceManager().getResources(RZoneTheme.class)) { randomBox.addItem(theme.id); } mapPanel.add(new JLabel("Random")); diff --git a/src/main/java/neon/editor/maps/MapDialog.java b/src/main/java/neon/editor/maps/MapDialog.java index 06f7e28..8998c60 100644 --- a/src/main/java/neon/editor/maps/MapDialog.java +++ b/src/main/java/neon/editor/maps/MapDialog.java @@ -22,7 +22,7 @@ import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.resources.RDungeonTheme; import neon.resources.RTerrain; @@ -36,6 +36,11 @@ public class MapDialog implements ActionListener { private JComboBox terrainBox; private JComboBox randomBox; private boolean cancelled; + private final DataStore dataStore; + + public MapDialog(DataStore dataStore) { + this.dataStore = dataStore; + } public Properties showInputDialog(JFrame frame) { dialog = new JDialog(frame, "Create new map", true); @@ -62,7 +67,7 @@ public Properties showInputDialog(JFrame frame) { mapPanel.add(ySpinner); terrainBox = new JComboBox(); - for (RTerrain terrain : Editor.resources.getResources(RTerrain.class)) { + for (RTerrain terrain : dataStore.getResourceManager().getResources(RTerrain.class)) { terrainBox.addItem(terrain.id); } mapPanel.add(new JLabel("Base terrain: ")); @@ -72,7 +77,7 @@ public Properties showInputDialog(JFrame frame) { randomBox = new JComboBox(); randomBox.addItem("none"); randomBox.setEnabled(false); - for (RDungeonTheme theme : Editor.resources.getResources(RDungeonTheme.class)) { + for (RDungeonTheme theme : dataStore.getResourceManager().getResources(RDungeonTheme.class)) { randomBox.addItem(theme.id); } mapPanel.add(new JLabel("Random")); diff --git a/src/main/java/neon/editor/maps/MapEditor.java b/src/main/java/neon/editor/maps/MapEditor.java index 1792b91..6492737 100644 --- a/src/main/java/neon/editor/maps/MapEditor.java +++ b/src/main/java/neon/editor/maps/MapEditor.java @@ -27,13 +27,13 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; +import neon.editor.DataStore; import neon.editor.Editor; import neon.editor.resources.IObject; import neon.editor.resources.IRegion; import neon.editor.resources.Instance; import neon.editor.resources.RMap; import neon.editor.resources.RZone; -import neon.resources.ResourceManager; public class MapEditor { private static String terrain; @@ -48,10 +48,11 @@ public class MapEditor { private JTabbedPane tabs; private JCheckBox levelBox; private JSpinner levelSpinner; - private final ResourceManager resourceManager; - public MapEditor(JTabbedPane tabs, JPanel panel, ResourceManager resourceManager) { - this.resourceManager = resourceManager; - activeMaps = new HashSet(); + private final DataStore dataStore; + + public MapEditor(JTabbedPane tabs, JPanel panel, DataStore dataStore) { + this.dataStore = dataStore; + activeMaps = new HashSet(); mapUIDs = new HashMap(); this.tabs = tabs; @@ -59,7 +60,7 @@ public MapEditor(JTabbedPane tabs, JPanel panel, ResourceManager resourceManager mapTree = new JTree(new DefaultMutableTreeNode("maps")); mapTree.setRootVisible(false); mapTree.setShowsRootHandles(true); - mapTree.addMouseListener(new MapTreeListener(mapTree, tabs, this)); + mapTree.addMouseListener(new MapTreeListener(mapTree, tabs, this, dataStore)); mapTree.setVisible(false); mapScrollPane = new JScrollPane(mapTree); mapScrollPane.setBorder(new TitledBorder("Maps")); @@ -137,25 +138,25 @@ public static boolean drawMode() { public void deleteMap(String id) { // TODO: activeMaps is , not ! activeMaps.remove(id); - resourceManager.removeResource(id); + dataStore.getResourceManager().removeResource(id); } public void makeMap(MapDialog.Properties props) { if (!props.cancelled()) { // editableMap maken short uid = createNewUID(); - RMap map = new RMap(uid, Editor.getStore().getActive().get("id"), props,resourceManager); + RMap map = new RMap(uid, dataStore.getActive().get("id"), props, dataStore); activeMaps.add(map); // en node maken DefaultTreeModel model = (DefaultTreeModel) mapTree.getModel(); DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); - MapTreeNode node = new MapTreeNode(map); + MapTreeNode node = new MapTreeNode(map, dataStore); if (!map.isDungeon()) { - node.add(new ZoneTreeNode(0, map.getZone(0))); + node.add(new ZoneTreeNode(0, map.getZone(0), dataStore)); } model.insertNodeInto(node, root, root.getChildCount()); mapTree.expandPath(new TreePath(root)); - resourceManager.addResource(map, "maps"); + dataStore.getResourceManager().addResource(map, "maps"); } } @@ -164,13 +165,13 @@ public void loadMaps(Collection maps, String path) { DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); for (RMap map : maps) { mapUIDs.put(map.id, map.uid); - MapTreeNode node = new MapTreeNode(map); + MapTreeNode node = new MapTreeNode(map, dataStore); if (map.isDungeon()) { for (Map.Entry zone : map.zones.entrySet()) { - node.add(new ZoneTreeNode(zone.getKey(), zone.getValue())); + node.add(new ZoneTreeNode(zone.getKey(), zone.getValue(), dataStore)); } } else { - node.add(new ZoneTreeNode(0, map.getZone(0))); + node.add(new ZoneTreeNode(0, map.getZone(0), dataStore)); } model.insertNodeInto(node, root, root.getChildCount()); } diff --git a/src/main/java/neon/editor/maps/MapInfoEditor.java b/src/main/java/neon/editor/maps/MapInfoEditor.java index 247756b..0d515bc 100644 --- a/src/main/java/neon/editor/maps/MapInfoEditor.java +++ b/src/main/java/neon/editor/maps/MapInfoEditor.java @@ -25,7 +25,7 @@ import javax.swing.border.*; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.resources.RMap; import neon.resources.RDungeonTheme; @@ -37,10 +37,12 @@ public class MapInfoEditor implements ActionListener { private RMap data; private MapTreeNode node; private JTree tree; + private final DataStore dataStore; - public MapInfoEditor(JFrame parent, MapTreeNode node, JTree tree) { + public MapInfoEditor(JFrame parent, MapTreeNode node, JTree tree, DataStore dataStore) { data = node.getMap(); frame = new JDialog(parent, "Map editor: " + data.id); + this.dataStore = dataStore; JPanel content = new JPanel(new BorderLayout()); frame.setContentPane(content); this.node = node; @@ -66,7 +68,9 @@ public MapInfoEditor(JFrame parent, MapTreeNode node, JTree tree) { JLabel nameLabel = new JLabel("Name: "); JLabel themeLabel = new JLabel("Theme: "); nameField = new JTextField(15); - themeBox = new JComboBox(Editor.resources.getResources(RDungeonTheme.class)); + themeBox = + new JComboBox( + dataStore.getResourceManager().getResources(RDungeonTheme.class)); themeBox.addItem(null); themeBox.setEnabled(node.getMap().isDungeon()); themeBox.addActionListener(this); @@ -137,7 +141,7 @@ private void save() { data.theme = (RDungeonTheme) themeBox.getSelectedItem(); } } - data.setPath(Editor.getStore().getActive().get("id")); + data.setPath(dataStore.getActive().get("id")); } public void actionPerformed(ActionEvent e) { diff --git a/src/main/java/neon/editor/maps/MapTreeListener.java b/src/main/java/neon/editor/maps/MapTreeListener.java index 0a9e1fb..4abccfe 100644 --- a/src/main/java/neon/editor/maps/MapTreeListener.java +++ b/src/main/java/neon/editor/maps/MapTreeListener.java @@ -21,14 +21,14 @@ import java.awt.event.*; import javax.swing.*; import javax.swing.tree.*; +import neon.editor.DataStore; import neon.editor.Editor; import neon.editor.resources.IObject; import neon.editor.resources.IRegion; import neon.editor.resources.Instance; import neon.editor.resources.RMap; import neon.editor.resources.RZone; -import neon.editor.services.EditorResourceProvider; -import neon.maps.generators.DungeonGenerator; +import neon.maps.generators.DungeonTerrainGenerator; import neon.resources.RCreature; import neon.resources.RItem; import neon.resources.RTerrain; @@ -40,11 +40,13 @@ public class MapTreeListener implements MouseListener { private JTree tree; private JTabbedPane tabs; private MapEditor editor; + private final DataStore dataStore; - public MapTreeListener(JTree tree, JTabbedPane mapPane, MapEditor editor) { + public MapTreeListener(JTree tree, JTabbedPane mapPane, MapEditor editor, DataStore dataStore) { this.tree = tree; tabs = mapPane; this.editor = editor; + this.dataStore = dataStore; } public void mouseExited(MouseEvent e) {} @@ -77,7 +79,7 @@ public void mousePressed(MouseEvent e) { if (choice != JOptionPane.CANCEL_OPTION) { // and put on screen node.getZone().theme = null; if (node.getPane() == null) { - node.setPane(new EditablePane(node, tabs.getWidth(), tabs.getHeight())); + node.setPane(new EditablePane(node, tabs.getWidth(), tabs.getHeight(), dataStore)); editor.getActiveMaps().add(node.getZone().map); } if (tabs.indexOfComponent(node.getPane()) == -1) { @@ -125,8 +127,7 @@ public void mouseClicked(MouseEvent e) { private void generateZone(RZone zone) { RZoneTheme theme = zone.theme; - String[][] terrain = - new DungeonGenerator(theme, null, new EditorResourceProvider(), null).generateTiles(); + String[][] terrain = new DungeonTerrainGenerator().generateTilesOnly(theme).terrain(); int width = terrain.length; int height = terrain[0].length; zone.map.load(); // map in orde brengen @@ -134,12 +135,13 @@ private void generateZone(RZone zone) { Instance r = new IRegion( - (RTerrain) Editor.resources.getResource(theme.walls, "terrain"), + (RTerrain) dataStore.getResourceManager().getResource(theme.walls, "terrain"), 0, 0, 0, width, - height); + height, + dataStore); scene.addElement(r, r.getBounds(), r.z); byte layer = 1; @@ -150,24 +152,38 @@ private void generateZone(RZone zone) { Instance region = new IRegion( - (RTerrain) Editor.resources.getResource(content[0], "terrain"), + (RTerrain) dataStore.getResourceManager().getResource(content[0], "terrain"), x, y, layer, 1, - 1); + 1, + dataStore); scene.addElement(region, region.getBounds(), region.z); if (content.length > 1) { for (int i = 1; i < content.length; i++) { if (content[i].startsWith("i")) { String id = content[i].replace("i:", ""); - Instance item = new IObject((RItem) Editor.resources.getResource(id), x, y, 1, 1); + Instance item = + new IObject( + (RItem) dataStore.getResourceManager().getResource(id), + x, + y, + 1, + 1, + dataStore); scene.addElement(item, item.getBounds(), item.z); } else if (content[i].startsWith("c")) { String id = content[i].replace("c:", ""); Instance creature = - new IObject((RCreature) Editor.resources.getResource(id), x, y, 1, 1); + new IObject( + (RCreature) dataStore.getResourceManager().getResource(id), + x, + y, + 1, + 1, + dataStore); scene.addElement(creature, creature.getBounds(), creature.z); // } else if(content[i].startsWith("p")) { // String id = content[i].replace("p:", ""); @@ -211,7 +227,8 @@ public void actionPerformed(ActionEvent e) { Editor.getFrame(), question, "Theme warning", JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION) { map.theme = null; - LevelDialog.Properties props = new LevelDialog().showInputDialog(Editor.getFrame()); + LevelDialog.Properties props = + new LevelDialog(dataStore).showInputDialog(Editor.getFrame()); if (!props.cancelled()) { int index = 0; while (map.zones.containsKey(index)) { @@ -226,15 +243,16 @@ public void actionPerformed(ActionEvent e) { region.setAttribute("h", Integer.toString(props.getHeight())); region.setAttribute("text", props.getTerrain()); region.setAttribute("l", "0"); - IRegion ri = new IRegion(region); + IRegion ri = new IRegion(region, dataStore); zone = new RZone(props.getName(), map.getPath()[0], ri, map); } else { System.out.println(props.getTheme()); RZoneTheme theme = - (RZoneTheme) Editor.resources.getResource(props.getTheme(), "theme"); + (RZoneTheme) + dataStore.getResourceManager().getResource(props.getTheme(), "theme"); zone = new RZone(props.getName(), map.getPath()[0], theme, map); } - ZoneTreeNode node = new ZoneTreeNode(index, zone); + ZoneTreeNode node = new ZoneTreeNode(index, zone, dataStore); map.zones.put(index, zone); MapTreeNode top = (MapTreeNode) tree.getLastSelectedPathComponent(); model.insertNodeInto(node, top, index); @@ -247,16 +265,16 @@ public void actionPerformed(ActionEvent e) { map.removeZone(node.getZoneLevel()); } else if (e.getActionCommand().equals("Edit zone")) { ZoneTreeNode node = (ZoneTreeNode) tree.getLastSelectedPathComponent(); - new ZoneEditor(node, Editor.getFrame()).show(); + new ZoneEditor(node, Editor.getFrame(), dataStore).show(); } else if (e.getActionCommand().equals("Add map")) { - editor.makeMap(new MapDialog().showInputDialog(Editor.getFrame())); + editor.makeMap(new MapDialog(dataStore).showInputDialog(Editor.getFrame())); } else if (e.getActionCommand().equals("Delete map")) { MapTreeNode map = (MapTreeNode) tree.getLastSelectedPathComponent(); model.removeNodeFromParent(map); editor.deleteMap(map.getMap().id); } else if (e.getActionCommand().equals("Edit map")) { MapTreeNode map = (MapTreeNode) tree.getLastSelectedPathComponent(); - new MapInfoEditor(Editor.getFrame(), map, tree).show(); + new MapInfoEditor(Editor.getFrame(), map, tree, dataStore).show(); } } } diff --git a/src/main/java/neon/editor/maps/MapTreeNode.java b/src/main/java/neon/editor/maps/MapTreeNode.java index 3f0e9bc..6ebb63d 100644 --- a/src/main/java/neon/editor/maps/MapTreeNode.java +++ b/src/main/java/neon/editor/maps/MapTreeNode.java @@ -19,20 +19,22 @@ package neon.editor.maps; import javax.swing.tree.DefaultMutableTreeNode; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.resources.RMap; @SuppressWarnings("serial") public class MapTreeNode extends DefaultMutableTreeNode { private RMap map; + private final DataStore dataStore; - public MapTreeNode(RMap map) { + public MapTreeNode(RMap map, DataStore dataStore) { super(map.toString()); this.map = map; + this.dataStore = dataStore; } public String toString() { - if (!map.getPath()[0].equals(Editor.getStore().getActive().get("id"))) { + if (!map.getPath()[0].equals(dataStore.getActive().get("id"))) { // niet-actieve data is cursief weergegeven return "" + map.id + ""; } else { diff --git a/src/main/java/neon/editor/maps/RegionInstanceEditor.java b/src/main/java/neon/editor/maps/RegionInstanceEditor.java index bc89a3a..334857f 100644 --- a/src/main/java/neon/editor/maps/RegionInstanceEditor.java +++ b/src/main/java/neon/editor/maps/RegionInstanceEditor.java @@ -25,12 +25,11 @@ import java.util.Enumeration; import javax.swing.*; import javax.swing.border.TitledBorder; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.resources.IRegion; import neon.editor.resources.Instance; import neon.editor.resources.RZone; -import neon.editor.services.EditorResourceProvider; -import neon.maps.generators.WildernessGenerator; +import neon.maps.generators.WildernessTerrainGenerator; import neon.resources.RRegionTheme; import neon.resources.RScript; import neon.resources.RTerrain; @@ -45,13 +44,15 @@ public class RegionInstanceEditor implements ActionListener, MouseListener { private JComboBox terrainBox; private JList scriptList; private DefaultListModel scriptListModel; - private RZone zone; + private final RZone zone; private JSpinner zSpinner; + private final DataStore dataStore; - public RegionInstanceEditor(IRegion r, JFrame parent, ZoneTreeNode zone) { + public RegionInstanceEditor(IRegion r, JFrame parent, ZoneTreeNode zone, DataStore dataStore) { this.zone = zone.getZone(); region = r; frame = new JDialog(parent, "Region instance editor: " + region.resource.id); + this.dataStore = dataStore; JPanel content = new JPanel(new BorderLayout()); frame.setContentPane(content); @@ -86,7 +87,8 @@ public RegionInstanceEditor(IRegion r, JFrame parent, ZoneTreeNode zone) { wField = new JFormattedTextField(NumberFormat.getIntegerInstance()); wField.setColumns(10); hField = new JFormattedTextField(NumberFormat.getIntegerInstance()); - terrainBox = new JComboBox(Editor.resources.getResources(RTerrain.class)); + terrainBox = + new JComboBox(dataStore.getResourceManager().getResources(RTerrain.class)); zSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 124, 1)); labelField = new JTextField(); destLayout.setVerticalGroup( @@ -163,7 +165,7 @@ public RegionInstanceEditor(IRegion r, JFrame parent, ZoneTreeNode zone) { JPanel randomPanel = new JPanel(); themeBox = new JComboBox(); themeBox.addItem(null); - for (RRegionTheme theme : Editor.resources.getResources(RRegionTheme.class)) { + for (RRegionTheme theme : dataStore.getResourceManager().getResources(RRegionTheme.class)) { themeBox.addItem(theme); } JButton randomButton = new JButton("Generate randomly"); @@ -244,8 +246,8 @@ public void actionPerformed(ActionEvent e) { } } String[][] content = - new WildernessGenerator(terrain, null, new EditorResourceProvider()) - .generate(region.getBounds(), region.theme, region.resource.id); + new WildernessTerrainGenerator() + .generateTerrainOnly(region.getBounds(), region.theme, region.resource.id); makeContent(content); } themeBox.setSelectedItem(null); @@ -295,7 +297,7 @@ public ScriptListAction(String name) { public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Add script")) { - Object[] spells = Editor.getStore().getScripts().values().toArray(); + Object[] spells = dataStore.getScripts().values().toArray(); RScript rs = (RScript) JOptionPane.showInputDialog( @@ -326,7 +328,7 @@ private void makeContent(String[][] tiles) { e.setAttribute("y", Integer.toString(y + region.y)); e.setAttribute("id", id); e.setAttribute("uid", Integer.toString(zone.map.createUID(e))); - Instance instance = RZone.getInstance(e, zone); + Instance instance = zone.getInstance(e, zone); zone.getScene().addElement(instance, instance.getBounds(), instance.z); } else if (entry.startsWith("c:")) { } else if (!entry.isEmpty()) { @@ -337,7 +339,7 @@ private void makeContent(String[][] tiles) { element.setAttribute("w", "1"); element.setAttribute("h", "1"); element.setAttribute("l", Integer.toString(region.z + 1)); - Instance instance = new IRegion(element); + Instance instance = new IRegion(element, dataStore); zone.getScene() .addElement( instance, new Rectangle(x + region.x, y + region.y, 1, 1), region.z + 1); diff --git a/src/main/java/neon/editor/maps/TerrainListener.java b/src/main/java/neon/editor/maps/TerrainListener.java index a6ecfd9..0c1a508 100644 --- a/src/main/java/neon/editor/maps/TerrainListener.java +++ b/src/main/java/neon/editor/maps/TerrainListener.java @@ -29,10 +29,12 @@ public class TerrainListener implements ListSelectionListener, MouseListener { private MapEditor editor; private JList list; + private final DataStore dataStore; - public TerrainListener(MapEditor editor, JList list) { + public TerrainListener(MapEditor editor, JList list, DataStore dataStore) { this.editor = editor; this.list = list; + this.dataStore = dataStore; } public void valueChanged(ListSelectionEvent e) { @@ -53,7 +55,7 @@ public void mousePressed(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { if (e.getClickCount() == 2) { if (list.getSelectedValue() != null) { - new TerrainEditor(Editor.getFrame(), list.getSelectedValue()).show(); + new TerrainEditor(Editor.getFrame(), list.getSelectedValue(), dataStore).show(); } } } @@ -86,16 +88,16 @@ public void actionPerformed(ActionEvent e) { "New terrain", JOptionPane.QUESTION_MESSAGE); if ((s != null) && (s.length() > 0)) { - RTerrain type = new RTerrain(s, Editor.getStore().getActive().get("id")); + RTerrain type = new RTerrain(s, dataStore.getActive().get("id")); model.addElement(type); list.setSelectedValue(type, true); - Editor.resources.addResource(type, "terrain"); - new TerrainEditor(Editor.getFrame(), type).show(); + dataStore.getResourceManager().addResource(type, "terrain"); + new TerrainEditor(Editor.getFrame(), type, dataStore).show(); } } else if (e.getActionCommand().equals("Delete terrain type")) { try { if (list.getSelectedIndex() >= 0) { - Editor.resources.removeResource(list.getSelectedValue(), "terrain"); + dataStore.getResourceManager().removeResource(list.getSelectedValue(), "terrain"); model.removeElement(list.getSelectedValue()); } } catch (ArrayIndexOutOfBoundsException a) { diff --git a/src/main/java/neon/editor/maps/ZoneEditor.java b/src/main/java/neon/editor/maps/ZoneEditor.java index 44d083d..70896c0 100644 --- a/src/main/java/neon/editor/maps/ZoneEditor.java +++ b/src/main/java/neon/editor/maps/ZoneEditor.java @@ -24,6 +24,7 @@ import javax.swing.*; import javax.swing.border.TitledBorder; import javax.swing.table.*; +import neon.editor.DataStore; import neon.editor.Editor; import neon.editor.resources.IContainer; import neon.editor.resources.IDoor; @@ -40,8 +41,10 @@ public class ZoneEditor implements ActionListener { private RZone zone; private JTextField nameField; private JComboBox themeBox; + private final DataStore dataStore; - public ZoneEditor(ZoneTreeNode node, JFrame parent) { + public ZoneEditor(ZoneTreeNode node, JFrame parent, DataStore dataStore) { + this.dataStore = dataStore; JPanel content = new JPanel(new BorderLayout()); frame = new JDialog(parent, "Zone editor: " + node); frame.setContentPane(content); @@ -56,7 +59,8 @@ public ZoneEditor(ZoneTreeNode node, JFrame parent) { JLabel nameLabel = new JLabel("Name: "); JLabel themeLabel = new JLabel("Theme: "); nameField = new JTextField(15); - themeBox = new JComboBox(Editor.resources.getResources(RZoneTheme.class)); + themeBox = + new JComboBox(dataStore.getResourceManager().getResources(RZoneTheme.class)); themeBox.addItem(null); themeBox.addActionListener(this); layout.setVerticalGroup( @@ -213,9 +217,10 @@ public void mousePressed(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { if (e.getClickCount() == 2) { if (instance instanceof IDoor) { - new DoorInstanceEditor((IDoor) instance, Editor.getFrame()).show(); + new DoorInstanceEditor((IDoor) instance, Editor.getFrame(), dataStore).show(); } else if (instance instanceof IContainer) { - new ContainerInstanceEditor((IContainer) instance, Editor.getFrame(), node).show(); + new ContainerInstanceEditor((IContainer) instance, Editor.getFrame(), node, dataStore) + .show(); } } } diff --git a/src/main/java/neon/editor/maps/ZoneTreeNode.java b/src/main/java/neon/editor/maps/ZoneTreeNode.java index c77954b..1654928 100644 --- a/src/main/java/neon/editor/maps/ZoneTreeNode.java +++ b/src/main/java/neon/editor/maps/ZoneTreeNode.java @@ -19,27 +19,31 @@ package neon.editor.maps; import javax.swing.tree.*; -import neon.editor.Editor; +import lombok.Getter; +import lombok.Setter; +import neon.editor.DataStore; import neon.editor.resources.RZone; @SuppressWarnings("serial") public class ZoneTreeNode extends DefaultMutableTreeNode { - private RZone zone; - private EditablePane pane; + @Getter private RZone zone; + @Setter @Getter private EditablePane pane; private int level; + private final DataStore dataStore; /** * Initializes a new node representing a map level. * * @param level */ - public ZoneTreeNode(int level, RZone zone) { + public ZoneTreeNode(int level, RZone zone, DataStore dataStore) { this.level = level; this.zone = zone; + this.dataStore = dataStore; } public String toString() { - if (!zone.getPath()[0].equals(Editor.getStore().getActive().get("id"))) { + if (!zone.getPath()[0].equals(dataStore.getActive().get("id"))) { // niet-actieve data is cursief weergegeven return "" + zone.name + ""; } else { @@ -47,10 +51,6 @@ public String toString() { } } - public RZone getZone() { - return zone; - } - public int getZoneLevel() { return level; } @@ -58,12 +58,4 @@ public int getZoneLevel() { public short getUID() { return zone.map.getUID(); } - - public EditablePane getPane() { - return pane; - } - - public void setPane(EditablePane pane) { - this.pane = pane; - } } diff --git a/src/main/java/neon/editor/resources/IContainer.java b/src/main/java/neon/editor/resources/IContainer.java index 7c6f9f6..8a3a4af 100644 --- a/src/main/java/neon/editor/resources/IContainer.java +++ b/src/main/java/neon/editor/resources/IContainer.java @@ -19,7 +19,7 @@ package neon.editor.resources; import java.util.ArrayList; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.resources.RData; import neon.resources.RItem; import neon.resources.RSpell; @@ -32,25 +32,28 @@ public class IContainer extends IObject { public RSpell.Enchantment spell; public ArrayList contents = new ArrayList(); - public IContainer(RData resource, int x, int y, int z, int uid) { - super(resource, x, y, z, uid); + public IContainer(RData resource, int x, int y, int z, int uid, DataStore dataStore) { + super(resource, x, y, z, uid, dataStore); } - public IContainer(Element properties) { - super(properties); + public IContainer(Element properties, DataStore dataStore) { + super(properties, dataStore); for (Element e : properties.getChildren("item")) { - RItem ri = (RItem) Editor.resources.getResource(e.getAttributeValue("id")); - contents.add(new IObject(ri, 0, 0, 0, Integer.parseInt(e.getAttributeValue("uid")))); + RItem ri = (RItem) dataStore.getResourceManager().getResource(e.getAttributeValue("id")); + contents.add( + new IObject(ri, 0, 0, 0, Integer.parseInt(e.getAttributeValue("uid")), dataStore)); } if (properties.getAttribute("lock") != null) { lock = Integer.parseInt(properties.getAttributeValue("lock")); - key = (RItem) Editor.resources.getResource(properties.getAttributeValue("key")); + key = (RItem) dataStore.getResourceManager().getResource(properties.getAttributeValue("key")); } if (properties.getAttribute("trap") != null) { trap = Integer.parseInt(properties.getAttributeValue("trap")); spell = (RSpell.Enchantment) - Editor.resources.getResource(properties.getAttributeValue("spell"), "magic"); + dataStore + .getResourceManager() + .getResource(properties.getAttributeValue("spell"), "magic"); } } diff --git a/src/main/java/neon/editor/resources/IDoor.java b/src/main/java/neon/editor/resources/IDoor.java index 1545211..6abf612 100644 --- a/src/main/java/neon/editor/resources/IDoor.java +++ b/src/main/java/neon/editor/resources/IDoor.java @@ -19,7 +19,7 @@ package neon.editor.resources; import java.awt.Point; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.resources.RData; import neon.resources.RDungeonTheme; import neon.resources.RItem; @@ -38,12 +38,12 @@ public class IDoor extends IObject { public String text; public RSpell.Enchantment spell; - public IDoor(RData resource, int x, int y, int z, int uid) { - super(resource, x, y, z, uid); + public IDoor(RData resource, int x, int y, int z, int uid, DataStore dataStore) { + super(resource, x, y, z, uid, dataStore); } - public IDoor(Element properties, RZone zone) { - super(properties); + public IDoor(Element properties, RZone zone, DataStore dataStore) { + super(properties, dataStore); if (properties.getAttribute("state") != null) { state = State.valueOf(properties.getAttributeValue("state")); } else { @@ -51,23 +51,28 @@ public IDoor(Element properties, RZone zone) { } if (properties.getAttribute("lock") != null) { lock = Integer.parseInt(properties.getAttributeValue("lock")); - key = (RItem) Editor.resources.getResource(properties.getAttributeValue("key")); + key = (RItem) dataStore.getResourceManager().getResource(properties.getAttributeValue("key")); } if (properties.getAttribute("trap") != null) { trap = Integer.parseInt(properties.getAttributeValue("trap")); spell = (RSpell.Enchantment) - Editor.resources.getResource(properties.getAttributeValue("spell"), "magic"); + dataStore + .getResourceManager() + .getResource(properties.getAttributeValue("spell"), "magic"); } if (properties.getChild("dest") != null) { Element dest = properties.getChild("dest"); if (dest.getAttribute("theme") != null) { destTheme = - (RDungeonTheme) Editor.resources.getResource(dest.getAttributeValue("theme"), "theme"); + (RDungeonTheme) + dataStore + .getResourceManager() + .getResource(dest.getAttributeValue("theme"), "theme"); } else { if (dest.getAttribute("map") != null) { int uid = Integer.parseInt(dest.getAttributeValue("map")); - for (RMap map : Editor.resources.getResources(RMap.class)) { + for (RMap map : dataStore.getResourceManager().getResources(RMap.class)) { if (map.uid == uid) { destMap = map; } diff --git a/src/main/java/neon/editor/resources/IObject.java b/src/main/java/neon/editor/resources/IObject.java index 2f1b726..bf5e418 100644 --- a/src/main/java/neon/editor/resources/IObject.java +++ b/src/main/java/neon/editor/resources/IObject.java @@ -20,7 +20,7 @@ import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.maps.MapEditor; import neon.resources.RData; import neon.resources.RItem; @@ -33,18 +33,18 @@ public class IObject extends Instance { private JVShape cachedSvgShape; private String cachedSvgContent; - public IObject(RData resource, int x, int y, int z, int uid) { - super(resource, x, y, z, 1, 1); + public IObject(RData resource, int x, int y, int z, int uid, DataStore dataStore) { + super(resource, x, y, z, 1, 1, dataStore); this.uid = uid; } - public IObject(Element properties) { - super(properties); + public IObject(Element properties, DataStore dataStore) { + super(properties, dataStore); width = 1; height = 1; uid = Integer.parseInt(properties.getAttributeValue("uid")); String id = properties.getAttributeValue("id"); - resource = (RData) Editor.resources.getResource(id); + resource = (RData) dataStore.getResourceManager().getResource(id); if (properties.getName().equals("creature")) { z = Byte.MAX_VALUE - 1; } else { // kan "item", "door" of "container" zijn diff --git a/src/main/java/neon/editor/resources/IPerson.java b/src/main/java/neon/editor/resources/IPerson.java index 97d2135..c34073a 100644 --- a/src/main/java/neon/editor/resources/IPerson.java +++ b/src/main/java/neon/editor/resources/IPerson.java @@ -21,7 +21,7 @@ import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.maps.MapEditor; import neon.resources.RCreature; import neon.resources.RPerson; @@ -32,14 +32,15 @@ public class IPerson extends IObject { private RCreature species; - public IPerson(Element properties) { - super(properties); - resource = (RPerson) Editor.resources.getResource(properties.getAttributeValue("id")); - species = (RCreature) Editor.resources.getResource(((RPerson) resource).species); + public IPerson(Element properties, DataStore dataStore) { + super(properties, dataStore); + resource = + (RPerson) dataStore.getResourceManager().getResource(properties.getAttributeValue("id")); + species = (RCreature) dataStore.getResourceManager().getResource(((RPerson) resource).species); } - public IPerson(RPerson resource, int x, int y, int z, Element e) { - super(resource, x, y, z, 0); + public IPerson(RPerson resource, int x, int y, int z, Element e, DataStore dataStore) { + super(resource, x, y, z, 0, dataStore); this.resource = resource; } diff --git a/src/main/java/neon/editor/resources/IRegion.java b/src/main/java/neon/editor/resources/IRegion.java index 1a6757a..f0e63f2 100644 --- a/src/main/java/neon/editor/resources/IRegion.java +++ b/src/main/java/neon/editor/resources/IRegion.java @@ -19,7 +19,7 @@ package neon.editor.resources; import java.util.ArrayList; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.resources.RData; import neon.resources.RRegionTheme; import neon.resources.RScript; @@ -31,19 +31,24 @@ public class IRegion extends Instance { public ArrayList scripts = new ArrayList(); public String label; - public IRegion(RTerrain terrain, int x, int y, int z, int w, int h) { - super(terrain, x, y, z, w, h); + public IRegion(RTerrain terrain, int x, int y, int z, int w, int h, DataStore dataStore) { + super(terrain, x, y, z, w, h, dataStore); } - public IRegion(Element properties) { - super(properties); + public IRegion(Element properties, DataStore dataStore) { + super(properties, dataStore); resource = - (RData) Editor.resources.getResource(properties.getAttributeValue("text"), "terrain"); + (RData) + dataStore + .getResourceManager() + .getResource(properties.getAttributeValue("text"), "terrain"); theme = (RRegionTheme) - Editor.resources.getResource(properties.getAttributeValue("random"), "theme"); + dataStore + .getResourceManager() + .getResource(properties.getAttributeValue("random"), "theme"); for (Element script : properties.getChildren("script")) { - scripts.add(Editor.getStore().getScripts().get(script.getAttributeValue("id"))); + scripts.add(dataStore.getScripts().get(script.getAttributeValue("id"))); } label = properties.getAttributeValue("label"); } diff --git a/src/main/java/neon/editor/resources/Instance.java b/src/main/java/neon/editor/resources/Instance.java index 60963ec..b55322f 100644 --- a/src/main/java/neon/editor/resources/Instance.java +++ b/src/main/java/neon/editor/resources/Instance.java @@ -23,6 +23,7 @@ import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; +import neon.editor.DataStore; import neon.editor.maps.MapEditor; import neon.resources.RData; import neon.ui.graphics.Renderable; @@ -38,19 +39,22 @@ public abstract class Instance implements Renderable { public int x, y, z, width, height; public RData resource; public boolean isCut = false; + protected final DataStore dataStore; - public Instance(RData resource, int x, int y, int z, int w, int h) { + public Instance(RData resource, int x, int y, int z, int w, int h, DataStore dataStore) { this.resource = resource; this.x = x; this.y = y; this.z = z; width = w; height = h; + this.dataStore = dataStore; } - public Instance(Element properties) { + public Instance(Element properties, DataStore dataStore) { x = Integer.parseInt(properties.getAttributeValue("x")); y = Integer.parseInt(properties.getAttributeValue("y")); + this.dataStore = dataStore; if (properties.getAttribute("w") != null) { width = Integer.parseInt(properties.getAttributeValue("w")); } diff --git a/src/main/java/neon/editor/resources/RMap.java b/src/main/java/neon/editor/resources/RMap.java index 5fb3618..adaee0a 100644 --- a/src/main/java/neon/editor/resources/RMap.java +++ b/src/main/java/neon/editor/resources/RMap.java @@ -19,14 +19,13 @@ package neon.editor.resources; import java.util.*; -import neon.editor.Editor; +import neon.editor.DataStore; import neon.editor.maps.*; import neon.maps.model.DungeonModel; import neon.maps.model.WorldModel; import neon.resources.RData; import neon.resources.RDungeonTheme; import neon.resources.RScript; -import neon.resources.ResourceManager; import neon.systems.files.XMLTranslator; import neon.ui.graphics.Renderable; import org.jdom2.*; @@ -49,22 +48,25 @@ public class RMap extends RData { public short uid; private boolean type; private ArrayList uids; - private final ResourceManager resourceManager; + + private final DataStore dataStore; // for already existing maps during loadMod - public RMap(String id, Element properties, ResourceManager resourceManager, String... path) { + public RMap(String id, Element properties, DataStore dataStore, String... path) { super(id, path); uid = Short.parseShort(properties.getChild("header").getAttributeValue("uid")); - this.resourceManager = resourceManager; - name = properties.getChild("header").getChildText("name"); + + this.dataStore = dataStore; + name = properties.getChild("header").getChildText("name"); type = properties.getName().equals("dungeon"); if (type == DUNGEON) { if (properties.getChild("header").getAttribute("theme") != null) { theme = (RDungeonTheme) - Editor.resources.getResource( - properties.getChild("header").getAttributeValue("theme"), "theme"); + dataStore + .getResourceManager() + .getResource(properties.getChild("header").getAttributeValue("theme"), "theme"); } else { for (Element zone : properties.getChildren("level")) { zones.put(Integer.parseInt(zone.getAttributeValue("l")), new RZone(zone, this, path)); @@ -76,12 +78,12 @@ public RMap(String id, Element properties, ResourceManager resourceManager, Stri } // for new maps to be created - public RMap(short uid, String mod, MapDialog.Properties props, ResourceManager resourceManager) { + public RMap(short uid, String mod, MapDialog.Properties props, DataStore dataStore) { super(props.getID(), mod); this.uid = uid; type = props.isDungeon(); - this.resourceManager = resourceManager; - name = props.getName(); + this.dataStore = dataStore; + name = props.getName(); if (!props.isDungeon()) { // always set zone and base region for outdoor Element region = new Element("region"); @@ -91,7 +93,7 @@ public RMap(short uid, String mod, MapDialog.Properties props, ResourceManager r region.setAttribute("h", Integer.toString(props.getHeight())); region.setAttribute("text", props.getTerrain()); region.setAttribute("l", "0"); - Instance ri = new IRegion(region); + Instance ri = new IRegion(region, dataStore); RZone zone = new RZone(name, mod, ri, this); zones.put(0, zone); } @@ -397,9 +399,12 @@ public void load() { if (uids == null) { // avoid loading map twice uids = new ArrayList(); try { - String file = Editor.getStore().getMod(path[0]).getPath()[0]; + String file = dataStore.getMod(path[0]).getPath()[0]; Element root = - Editor.files.getFile(new XMLTranslator(), file, "maps", id + ".xml").getRootElement(); + dataStore + .getFileSystem() + .getFile(new XMLTranslator(), file, "maps", id + ".xml") + .getRootElement(); if (root.getName().equals("world")) { uids.addAll(zones.get(0).load(root)); diff --git a/src/main/java/neon/editor/resources/RZone.java b/src/main/java/neon/editor/resources/RZone.java index 8f61729..49bfe76 100644 --- a/src/main/java/neon/editor/resources/RZone.java +++ b/src/main/java/neon/editor/resources/RZone.java @@ -20,7 +20,8 @@ import java.awt.Rectangle; import java.util.ArrayList; -import neon.editor.Editor; +import lombok.Getter; +import neon.editor.DataStore; import neon.resources.RData; import neon.resources.RPerson; import neon.resources.RZoneTheme; @@ -46,6 +47,7 @@ public class RZone extends RData { public RMap map; public RZoneTheme theme; private Scene scene; + @Getter private DataStore dataStore; // zone loaded as element from file public RZone(Element properties, RMap map, String... path) { @@ -58,7 +60,10 @@ public RZone(Element properties, RMap map, String... path) { this.map = map; name = id; theme = - (RZoneTheme) Editor.resources.getResource(properties.getAttributeValue("theme"), "theme"); + (RZoneTheme) + dataStore + .getResourceManager() + .getResource(properties.getAttributeValue("theme"), "theme"); } // new zone with theme @@ -111,7 +116,7 @@ public ArrayList load(Element zone) { } // if map contains no creatures try { // regions for (Element region : zone.getChild("regions").getChildren()) { - Instance r = new IRegion(region); + Instance r = new IRegion(region, dataStore); scene.addElement(r, r.getBounds(), r.z); } } catch (NullPointerException e) { @@ -132,15 +137,15 @@ public ArrayList load(Element zone) { return uids; } - public static Instance getInstance(Element e, RZone zone) { - if (Editor.resources.getResource(e.getAttributeValue("id")) instanceof RPerson) { - return new IPerson(e); + public Instance getInstance(Element e, RZone zone) { + if (dataStore.getResourceManager().getResource(e.getAttributeValue("id")) instanceof RPerson) { + return new IPerson(e, dataStore); } else if (e.getName().equals("door")) { - return new IDoor(e, zone); + return new IDoor(e, zone, dataStore); } else if (e.getName().equals("container")) { - return new IContainer(e); + return new IContainer(e, dataStore); } else { - return new IObject(e); + return new IObject(e, dataStore); } } diff --git a/src/main/java/neon/editor/services/EditorResourceProvider.java b/src/main/java/neon/editor/services/EditorResourceProvider.java deleted file mode 100644 index 42f8127..0000000 --- a/src/main/java/neon/editor/services/EditorResourceProvider.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.editor.services; - -import neon.editor.Editor; -import neon.maps.services.ResourceProvider; -import neon.resources.Resource; - -/** - * Editor-specific implementation of ResourceProvider that delegates to Editor.resources. This - * allows editor components to use map generators without depending on Engine static methods. - * - * @author mdriesen - */ -public class EditorResourceProvider implements ResourceProvider { - @Override - public Resource getResource(String id) { - return Editor.resources.getResource(id); - } - - @Override - public Resource getResource(String id, String type) { - return Editor.resources.getResource(id, type); - } -} diff --git a/src/main/java/neon/entities/EntityFactory.java b/src/main/java/neon/entities/CreatureFactory.java similarity index 56% rename from src/main/java/neon/entities/EntityFactory.java rename to src/main/java/neon/entities/CreatureFactory.java index 01594ee..22071bf 100644 --- a/src/main/java/neon/entities/EntityFactory.java +++ b/src/main/java/neon/entities/CreatureFactory.java @@ -21,95 +21,39 @@ import java.awt.Rectangle; import java.util.*; import neon.ai.*; +import neon.core.GameStores; import neon.core.handlers.InventoryHandler; -import neon.entities.components.Enchantment; import neon.entities.components.FactionComponent; -import neon.entities.components.RenderComponent; -import neon.entities.components.ShapeComponent; import neon.entities.property.Gender; import neon.magic.SpellFactory; import neon.resources.*; -import neon.ui.graphics.shapes.JVShape; -import neon.ui.graphics.svg.SVGLoader; import neon.util.Dice; -public class EntityFactory { - private final AIFactory aiFactory = new AIFactory(); - +public class CreatureFactory { + private final AIFactory aiFactory; private final InventoryHandler inventoryHandler; - private final UIDStore uidStore; - private final ResourceManager resourceManager; private final SpellFactory spellFactory; + // private final GameStores gameStores; + private final ItemFactory itemFactory; + private final ResourceManager resourceManager; + private final UIDStore uidStore; - public EntityFactory(UIDStore uidStore, ResourceManager resourceManager) { - this.uidStore = uidStore; - this.resourceManager = resourceManager; - inventoryHandler = new InventoryHandler(uidStore); - spellFactory = new SpellFactory(resourceManager); - } - - public Item getItem(String id, long uid) { - Item item = getItem(id, -1, -1, uid); - return item; - } - - public Item getItem(String id, int x, int y, long uid) { - // item aanmaken - RItem resource; - if (resourceManager.getResource(id) instanceof LItem) { - LItem li = (LItem) resourceManager.getResource(id); - ArrayList items = new ArrayList(li.items.keySet()); - resource = (RItem) resourceManager.getResource(items.get(Dice.roll(1, items.size(), -1))); - } else { - resource = (RItem) resourceManager.getResource(id); - } - Item item = getItem(resource, uid); - - // positie - ShapeComponent itemBounds = item.getShapeComponent(); - itemBounds.setLocation(x, y); - RenderComponent renderer = item.getRenderComponent(); - renderer.setZ(resource.top ? Byte.MAX_VALUE : Byte.MAX_VALUE - 2); - - if (resource.svg != null) { // svg custom look gedefinieerd - JVShape shape = SVGLoader.loadShape(resource.svg); - shape.setX(x); - shape.setY(y); - shape.setZ(renderer.getZ()); - item.setRenderComponent(shape); - itemBounds.setWidth(shape.getBounds().width); - itemBounds.setHeight(shape.getBounds().height); - } - - if (resource.spell != null) { - int mana = 0; - if (resource instanceof RWeapon) { - mana = ((RWeapon) resource).mana; - } - item.setMagicComponent( - new Enchantment(spellFactory.getSpell(resource.spell), mana, item.getUID())); - } - - return item; + public CreatureFactory(GameStores gameStores, Player player) { + inventoryHandler = new InventoryHandler(gameStores.getStore()); + spellFactory = new SpellFactory(gameStores.getResources()); + this.resourceManager = gameStores.getResources(); + this.uidStore = gameStores.getStore(); + this.aiFactory = new AIFactory(gameStores.getResources(), gameStores.getStore(), player); + this.itemFactory = new ItemFactory(gameStores.getResources()); } - private static Item getItem(RItem resource, long uid) { - // item aanmaken - return switch (resource.type) { - case container -> new Container(uid, (RItem.Container) resource); - case food -> new Item.Food(uid, resource); - case aid -> new Item.Aid(uid, resource); - case book -> new Item.Book(uid, (RItem.Text) resource); - case clothing -> new Clothing(uid, (RClothing) resource); - case armor -> new Armor(uid, (RClothing) resource); - case coin -> new Item.Coin(uid, resource); - case door -> new Door(uid, resource); - case light -> new Item.Light(uid, resource); - case potion -> new Item.Potion(uid, resource); - case scroll -> new Item.Scroll(uid, (RItem.Text) resource); - case weapon -> new Weapon(uid, (RWeapon) resource); - default -> new Item(uid, resource); - }; + public CreatureFactory(ResourceManager resourceManager, UIDStore uidStore, Player player) { + inventoryHandler = new InventoryHandler(uidStore); + spellFactory = new SpellFactory(resourceManager); + this.resourceManager = resourceManager; + this.uidStore = uidStore; + this.aiFactory = new AIFactory(resourceManager, uidStore, player); + this.itemFactory = new ItemFactory(resourceManager); } /* @@ -126,7 +70,7 @@ private Creature getPerson(String id, int x, int y, long uid, RCreature species) bounds.setLocation(x, y); for (String i : person.items) { long itemUID = uidStore.createNewEntityUID(); - Item item = getItem(i, itemUID); + Item item = itemFactory.getItem(i, itemUID); uidStore.addEntity(item); inventoryHandler.addItem(creature, itemUID); } diff --git a/src/main/java/neon/entities/ItemFactory.java b/src/main/java/neon/entities/ItemFactory.java new file mode 100644 index 0000000..0971ab0 --- /dev/null +++ b/src/main/java/neon/entities/ItemFactory.java @@ -0,0 +1,104 @@ +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.entities; + +import java.util.*; +import neon.entities.components.Enchantment; +import neon.entities.components.RenderComponent; +import neon.entities.components.ShapeComponent; +import neon.magic.SpellFactory; +import neon.resources.*; +import neon.ui.graphics.shapes.JVShape; +import neon.ui.graphics.svg.SVGLoader; +import neon.util.Dice; + +public class ItemFactory { + private final SpellFactory spellFactory; + + private final ResourceManager resourceManager; + + public ItemFactory(ResourceManager resourceManager) { + spellFactory = new SpellFactory(resourceManager); + this.resourceManager = resourceManager; + } + + public Item getItem(String id, long uid) { + Item item = getItem(id, -1, -1, uid); + return item; + } + + public Item getItem(String id, int x, int y, long uid) { + // item aanmaken + RItem resource; + if (resourceManager.getResource(id) instanceof LItem) { + LItem li = (LItem) resourceManager.getResource(id); + ArrayList items = new ArrayList(li.items.keySet()); + resource = (RItem) resourceManager.getResource(items.get(Dice.roll(1, items.size(), -1))); + } else { + resource = (RItem) resourceManager.getResource(id); + } + Item item = getItem(resource, uid); + + // positie + ShapeComponent itemBounds = item.getShapeComponent(); + itemBounds.setLocation(x, y); + RenderComponent renderer = item.getRenderComponent(); + renderer.setZ(resource.top ? Byte.MAX_VALUE : Byte.MAX_VALUE - 2); + + if (resource.svg != null) { // svg custom look gedefinieerd + JVShape shape = SVGLoader.loadShape(resource.svg); + shape.setX(x); + shape.setY(y); + shape.setZ(renderer.getZ()); + item.setRenderComponent(shape); + itemBounds.setWidth(shape.getBounds().width); + itemBounds.setHeight(shape.getBounds().height); + } + + if (resource.spell != null) { + int mana = 0; + if (resource instanceof RWeapon) { + mana = ((RWeapon) resource).mana; + } + item.setMagicComponent( + new Enchantment(spellFactory.getSpell(resource.spell), mana, item.getUID())); + } + + return item; + } + + private Item getItem(RItem resource, long uid) { + // item aanmaken + return switch (resource.type) { + case container -> new Container(uid, (RItem.Container) resource); + case food -> new Item.Food(uid, resource); + case aid -> new Item.Aid(uid, resource); + case book -> new Item.Book(uid, (RItem.Text) resource); + case clothing -> new Clothing(uid, (RClothing) resource); + case armor -> new Armor(uid, (RClothing) resource); + case coin -> new Item.Coin(uid, resource); + case door -> new Door(uid, resource); + case light -> new Item.Light(uid, resource); + case potion -> new Item.Potion(uid, resource); + case scroll -> new Item.Scroll(uid, (RItem.Text) resource); + case weapon -> new Weapon(uid, (RWeapon) resource); + default -> new Item(uid, resource); + }; + } +} diff --git a/src/main/java/neon/entities/Player.java b/src/main/java/neon/entities/Player.java index f508cc5..3ea6b20 100644 --- a/src/main/java/neon/entities/Player.java +++ b/src/main/java/neon/entities/Player.java @@ -19,6 +19,9 @@ package neon.entities; import java.util.EnumMap; +import java.util.concurrent.atomic.AtomicReference; +import lombok.Getter; +import lombok.Setter; import neon.core.GameStores; import neon.core.handlers.SkillHandler; import neon.entities.components.Inventory; @@ -28,21 +31,34 @@ import neon.entities.property.Gender; import neon.entities.property.Skill; import neon.entities.property.Slot; +import neon.maps.Map; +import neon.maps.Zone; import neon.narrative.Journal; import neon.resources.RCreature; import neon.resources.RWeapon.WeaponType; public class Player extends Hominid { private final int baseLevel; - private Journal journal = new Journal(); - private Specialisation spec; - private String profession; - private EnumMap mods; - private String sign; + + /** + * -- GETTER -- + * + * @return the player's journal + */ + @Getter private final Journal journal = new Journal(); + + private final Specialisation spec; + @Getter private final String profession; + private final EnumMap mods; private boolean sneak = false; - private Creature mount; private final GameStores gameStores; + @Setter @Getter private String sign; + @Getter private Creature mount; + + private final AtomicReference currentZone = new AtomicReference<>(); + private final AtomicReference currentMap = new AtomicReference<>(); + public Player( RCreature species, String name, @@ -69,15 +85,27 @@ public String getID() { return "player"; } + public Zone getCurrentZone() { + return currentZone.get(); + } + + public void setCurrentZone(Zone zone) { + currentZone.set(zone); + } + + public Map getCurrentMap() { + return currentMap.get(); + } + + public void setCurrentMap(Map map) { + currentMap.set(map); + } + /* * allerlei actions die de player kan ondernemen en niet in een aparte handler staan */ public boolean pickLock(Lock lock) { - if (SkillHandler.check(this, Skill.LOCKPICKING) > lock.getLockDC()) { - return true; - } else { - return false; - } + return SkillHandler.check(this, Skill.LOCKPICKING) > lock.getLockDC(); } public void setSneaking(boolean sneaking) { @@ -110,13 +138,6 @@ public String getAVString() { return damage; } - /** - * @return the player's journal - */ - public Journal getJournal() { - return journal; - } - // algehele level van de player. Wordt berekend a.d.h.v. de stats @Override public int getLevel() { @@ -218,14 +239,10 @@ public void addBaseInt(float amount) { species.iq += amount; } - public String getProfession() { - return profession; - } - public enum Specialisation { combat, magic, - stealth; + stealth } public void trainSkill(Skill skill, float mod) { @@ -239,14 +256,6 @@ public void restoreSkill(Skill skill, int value) { skill, Math.min(species.skills.get(skill) + mods.get(skill), skills.get(skill) + value)); } - public String getSign() { - return sign; - } - - public void setSign(String sign) { - this.sign = sign; - } - public void mount(Creature mount) { this.mount = mount; } @@ -255,10 +264,6 @@ public void unmount() { mount = null; } - public Creature getMount() { - return mount; - } - public boolean isMounted() { return mount != null; } diff --git a/src/main/java/neon/entities/UIDStore.java b/src/main/java/neon/entities/UIDStore.java index b30ff46..7eb05ee 100644 --- a/src/main/java/neon/entities/UIDStore.java +++ b/src/main/java/neon/entities/UIDStore.java @@ -22,8 +22,10 @@ import com.google.common.collect.HashBiMap; import java.io.*; import java.util.Map; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import neon.maps.services.EntityStore; +import neon.systems.files.FileSystem; import neon.util.mapstorage.MapStore; import neon.util.mapstorage.MapStoreMVStoreAdapter; import org.h2.mvstore.MVStore; @@ -39,7 +41,7 @@ public class UIDStore implements EntityStore, Closeable { // dummy uid for objects that don't actually exist public static final long DUMMY = 0; - + @Getter private final FileSystem fileSystem; // uid database private final MapStore uidDb; // uids of all objects in the game @@ -54,13 +56,15 @@ public class UIDStore implements EntityStore, Closeable { * * @param file */ - public UIDStore(String file) { + public UIDStore(FileSystem fileSystem, String file) { + this.fileSystem = fileSystem; uidDb = new MapStoreMVStoreAdapter(MVStore.open(file)); objects = uidDb.openMap("object"); mods = uidDb.openMap("mods"); } - public UIDStore(MapStore mapStore) { + public UIDStore(FileSystem fileSystem, MapStore mapStore) { + this.fileSystem = fileSystem; uidDb = mapStore; objects = uidDb.openMap("object"); mods = uidDb.openMap("mods"); diff --git a/src/main/java/neon/entities/components/Portal.java b/src/main/java/neon/entities/components/Portal.java index 20a36be..eb267c6 100644 --- a/src/main/java/neon/entities/components/Portal.java +++ b/src/main/java/neon/entities/components/Portal.java @@ -19,19 +19,15 @@ package neon.entities.components; import java.awt.Point; - import lombok.Getter; import lombok.Setter; import neon.maps.Map; public class Portal implements Component { private int destMapUID = -1; // -1 is zelfde map - @Setter - @Getter - private Point destPos; + @Setter @Getter private Point destPos; - @Setter - private int destZone = -1; // -1 is zelfde zone + @Setter private int destZone = -1; // -1 is zelfde zone private String theme; private long uid; @@ -77,14 +73,14 @@ public void setDestMap(int map) { destMapUID = map; } - /** + /** * @return the dungeon level this portal leads to */ public Integer getDestZone() { return destZone; } - /** + /** * @return the theme of the dungeon this door leads to */ public String getDestTheme() { diff --git a/src/main/java/neon/entities/serialization/CreatureSerializer.java b/src/main/java/neon/entities/serialization/CreatureSerializer.java index 4038449..7a47ac8 100644 --- a/src/main/java/neon/entities/serialization/CreatureSerializer.java +++ b/src/main/java/neon/entities/serialization/CreatureSerializer.java @@ -23,7 +23,7 @@ import java.io.DataOutput; import java.io.IOException; import neon.ai.AIFactory; -import neon.core.Engine; +import neon.core.GameContext; import neon.core.GameStores; import neon.entities.Construct; import neon.entities.Creature; @@ -39,13 +39,21 @@ // TODO: factions public class CreatureSerializer { private static final long serialVersionUID = -2452444993764883434L; - private final AIFactory aiFactory = new AIFactory(); + private final AIFactory aiFactory; private final SpellFactory spellFactory; private final ResourceManager resourceManager; - public CreatureSerializer(GameStores gameStores) { + private final GameContext gameContext; + private final GameStores gameStores; + + public CreatureSerializer(GameStores gameStores, GameContext gameContext) { spellFactory = new SpellFactory(gameStores.getResources()); resourceManager = gameStores.getResources(); + this.gameStores = gameStores; + this.gameContext = gameContext; + aiFactory = + new AIFactory(gameStores.getResources(), gameStores.getStore(), gameContext.getPlayer()); } + public Creature deserialize(DataInput in) throws IOException { String id = in.readUTF(); String species = in.readUTF(); @@ -135,14 +143,15 @@ private Creature getCreature(String id, int x, int y, long uid, String species) Creature creature; RCreature rc = (RCreature) resourceManager.getResource(species); - creature = switch (rc.type) { + creature = + switch (rc.type) { case construct -> new Construct(id, uid, rc); case humanoid -> new Hominid(id, uid, rc); case daemon -> new Daemon(id, uid, rc); case dragon -> new Dragon(id, uid, rc); case goblin -> new Hominid(id, uid, rc); default -> new Creature(id, uid, rc); - }; + }; return creature; } diff --git a/src/main/java/neon/entities/serialization/EntitySerializer.java b/src/main/java/neon/entities/serialization/EntitySerializer.java index 63df1e4..4b2a21c 100644 --- a/src/main/java/neon/entities/serialization/EntitySerializer.java +++ b/src/main/java/neon/entities/serialization/EntitySerializer.java @@ -21,7 +21,7 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; - +import neon.core.GameContext; import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Entity; @@ -31,18 +31,20 @@ public class EntitySerializer { private final ItemSerializer itemSerializer; private final CreatureSerializer creatureSerializer; + private final GameContext gameContext; - EntitySerializer(GameStores gameStores) { + EntitySerializer(GameStores gameStores, GameContext gameContext) { itemSerializer = new ItemSerializer(gameStores); - creatureSerializer = new CreatureSerializer(gameStores); + creatureSerializer = new CreatureSerializer(gameStores, gameContext); + this.gameContext = gameContext; } public Entity deserialize(DataInput input) throws IOException { - return switch (input.readUTF()) { - case "item" -> itemSerializer.deserialize(input); - case "creature" -> creatureSerializer.deserialize(input); - default -> null; - }; + return switch (input.readUTF()) { + case "item" -> itemSerializer.deserialize(input); + case "creature" -> creatureSerializer.deserialize(input); + default -> null; + }; } public void serialize(DataOutput output, Entity entity) throws IOException { diff --git a/src/main/java/neon/entities/serialization/ItemSerializer.java b/src/main/java/neon/entities/serialization/ItemSerializer.java index 4493f2e..f13e1c1 100644 --- a/src/main/java/neon/entities/serialization/ItemSerializer.java +++ b/src/main/java/neon/entities/serialization/ItemSerializer.java @@ -23,13 +23,12 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import neon.core.Engine; import neon.core.GameStores; import neon.entities.Armor; import neon.entities.Container; import neon.entities.Door; -import neon.entities.EntityFactory; import neon.entities.Item; +import neon.entities.ItemFactory; import neon.entities.Weapon; import neon.entities.components.Enchantment; import neon.entities.components.Lock; @@ -46,21 +45,22 @@ public class ItemSerializer { private static final long serialVersionUID = 2138679015831709732L; private final GameStores gameStores; - private final EntityFactory entityFactory; + private final ItemFactory itemFactory; private final SpellFactory spellFactory; - public ItemSerializer(GameStores gameStores) { - this.gameStores = gameStores; - entityFactory = new EntityFactory(gameStores.getStore(),gameStores.getResources()); - spellFactory= new SpellFactory(gameStores.getResources()); - } - public Item deserialize(DataInput input) throws IOException { + public ItemSerializer(GameStores gameStores) { + this.gameStores = gameStores; + itemFactory = new ItemFactory(gameStores.getResources()); + spellFactory = new SpellFactory(gameStores.getResources()); + } + + public Item deserialize(DataInput input) throws IOException { // item aanmaken String id = input.readUTF(); long uid = input.readLong(); int x = input.readInt(); int y = input.readInt(); - Item item = entityFactory.getItem(id, x, y, uid); + Item item = itemFactory.getItem(id, x, y, uid); item.setOwner(input.readLong()); if (input.readBoolean()) { diff --git a/src/main/java/neon/magic/DefaultHandler.java b/src/main/java/neon/magic/DefaultHandler.java index 7672773..2dd9f1b 100644 --- a/src/main/java/neon/magic/DefaultHandler.java +++ b/src/main/java/neon/magic/DefaultHandler.java @@ -64,7 +64,7 @@ public void addEffect(Spell spell) { case CHARM: target.brain.charm((Creature) spell.getCaster(), (int) spell.getMagnitude()); break; - // case SCRIPTED: neon.core.Engine.execute(spell.getScript()); break; + // case SCRIPTED: neon.core.Engine.execute(spell.getScript()); break; default: System.out.println("not implemented: " + spell.getEffect()); break; diff --git a/src/main/java/neon/maps/Atlas.java b/src/main/java/neon/maps/Atlas.java index 8bda30d..62c8f16 100644 --- a/src/main/java/neon/maps/Atlas.java +++ b/src/main/java/neon/maps/Atlas.java @@ -43,7 +43,7 @@ public class Atlas implements Closeable, MapAtlas { private final MapLoader mapLoader; public Atlas( - FileSystem fileSystem, MapStore mapStore, EntityStore entityStore, MapLoader mapLoader) { + FileSystem fileSystem, MapStore mapStore, EntityStore entityStore, MapLoader mapLoader) { this.fileSystem = fileSystem; this.entityStore = entityStore; this.db = mapStore; diff --git a/src/main/java/neon/maps/AtlasPosition.java b/src/main/java/neon/maps/AtlasPosition.java index 5287f76..92dc51e 100644 --- a/src/main/java/neon/maps/AtlasPosition.java +++ b/src/main/java/neon/maps/AtlasPosition.java @@ -1,57 +1,49 @@ package neon.maps; +import lombok.Getter; +import neon.core.GameStores; import neon.entities.Door; import neon.entities.Player; -import neon.entities.UIDStore; import neon.maps.generators.DungeonGenerator; -import neon.maps.services.EntityStore; import neon.maps.services.QuestProvider; import neon.narrative.QuestTracker; -import neon.resources.ResourceManager; - -import java.rmi.server.UID; public class AtlasPosition { - private int currentZone = 0; - private int currentMap = 0; + // private int currentZone = 0; + // private int currentMap = 0; private final Atlas atlas; - private final ZoneActivator zoneActivator; - private final ResourceManager resourceProvider; private final QuestTracker questProvider; - private final UIDStore entityStore; + @Getter private final Player player; + private final GameStores gameStores; + public final ZoneFactory zoneFactory; - public AtlasPosition( - Atlas atlas, - ZoneActivator zoneActivator, - ResourceManager resourceProvider, - QuestTracker questProvider, - UIDStore entityStore) { - this.atlas = atlas; - this.zoneActivator = zoneActivator; - this.resourceProvider = resourceProvider; + public AtlasPosition(GameStores gameStores, QuestTracker questProvider, Player player) { + this.atlas = gameStores.getAtlas(); this.questProvider = questProvider; - this.entityStore = entityStore; + this.player = player; + this.gameStores = gameStores; + zoneFactory = new ZoneFactory(gameStores); } /** * @return the current map */ public Map getCurrentMap() { - return atlas.getMap(currentMap); + return player.getCurrentMap(); } /** * @return the current zone */ public Zone getCurrentZone() { - return atlas.getMap(currentMap).getZone(currentZone); + return player.getCurrentZone(); } /** * @return the current zone */ public int getCurrentZoneIndex() { - return currentZone; + return player.getCurrentZone().getIndex(); } /** @@ -59,10 +51,10 @@ public int getCurrentZoneIndex() { * * @param i the index of the current zone */ - public void setCurrentZone(int i, Player player) { - currentZone = i; - zoneActivator.activateZone(getCurrentZone(), player); - } + // public void setCurrentZone(int i, Player player) { + // currentZone = i; + // zoneActivator.activateZone(getCurrentZone(), player); + // } /** * Enter a new zone through a door. @@ -72,14 +64,16 @@ public void setCurrentZone(int i, Player player) { */ public void enterZone(Door door, Zone previousZone, Player player) { if (door.portal.getDestZone() > -1) { - setCurrentZone(door.portal.getDestZone(), player); + Zone destinationZone = + zoneFactory.createZone( + getCurrentMap().getName(), getCurrentMap().getUID(), door.portal.getDestZone()); + player.setCurrentZone(destinationZone); } else { - setCurrentZone(0, player); + player.setCurrentZone(getCurrentMap().getZone(0)); } if (getCurrentMap() instanceof Dungeon && getCurrentZone().isRandom()) { - new DungeonGenerator( - getCurrentZone(), entityStore, resourceProvider, (QuestProvider) questProvider) + new DungeonGenerator(getCurrentZone(), (QuestProvider) questProvider, player, gameStores) .generate(door, previousZone, atlas); } } @@ -91,6 +85,6 @@ public void enterZone(Door door, Zone previousZone, Player player) { */ public void setMap(Map map) { atlas.putMapIfNeeded(map); - currentMap = map.getUID(); + player.setCurrentMap(map); } } diff --git a/src/main/java/neon/maps/Dungeon.java b/src/main/java/neon/maps/Dungeon.java index 62f1595..24808f1 100644 --- a/src/main/java/neon/maps/Dungeon.java +++ b/src/main/java/neon/maps/Dungeon.java @@ -22,7 +22,6 @@ import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Collection; - import lombok.Getter; import lombok.Setter; import neon.resources.RZoneTheme; @@ -34,19 +33,18 @@ * @author mdriesen */ public class Dungeon implements Map { - @Setter - @Getter - private String name; + @Setter @Getter private String name; private int uid; private Graph zones = new Graph(); private ZoneFactory zoneFactory; + /** * Initialize a dungeon. * * @param name the name of this dungeon * @param uid the unique identifier of this dungeon */ - public Dungeon(String name, int uid,ZoneFactory zoneFactory) { + public Dungeon(String name, int uid, ZoneFactory zoneFactory) { this.name = name; this.uid = uid; this.zoneFactory = zoneFactory; @@ -62,7 +60,7 @@ public int getUID() { return uid; } - /** Adds an empty zone to this dungeon. */ + /** Adds an empty zone to this dungeon. */ public void addZone(int zone, String name) { zones.addNode(zone, zoneFactory.createZone(name, uid, zone)); } diff --git a/src/main/java/neon/maps/MapLoader.java b/src/main/java/neon/maps/MapLoader.java index ccdedf1..ec63abf 100644 --- a/src/main/java/neon/maps/MapLoader.java +++ b/src/main/java/neon/maps/MapLoader.java @@ -22,12 +22,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import neon.core.*; -import neon.entities.Container; -import neon.entities.Creature; -import neon.entities.Door; -import neon.entities.EntityFactory; -import neon.entities.Item; -import neon.entities.UIDStore; +import neon.entities.*; import neon.entities.components.Enchantment; import neon.entities.components.Lock; import neon.maps.model.DungeonModel; @@ -53,9 +48,16 @@ public class MapLoader { private final ResourceManager resourceManager; private final FileSystem fileSystem; private final ZoneFactory zoneFactory; + private Player player; + /** Creates a MapLoader with dependency injection. */ - public MapLoader(FileSystem fileSystem, UIDStore uidStore, ResourceManager resourceManager, ZoneFactory zoneFactory) { - this(fileSystem, uidStore, resourceManager, new MapUtils(), zoneFactory); + public MapLoader( + FileSystem fileSystem, + UIDStore uidStore, + ResourceManager resourceManager, + ZoneFactory zoneFactory, + Player player) { + this(fileSystem, uidStore, resourceManager, new MapUtils(), zoneFactory, player); } /** @@ -64,15 +66,18 @@ public MapLoader(FileSystem fileSystem, UIDStore uidStore, ResourceManager resou * @param mapUtils the MapUtils instance for random operations */ public MapLoader( - FileSystem fileSystem, - UIDStore uidStore, - ResourceManager resourceManager, - MapUtils mapUtils, ZoneFactory zoneFactory) { + FileSystem fileSystem, + UIDStore uidStore, + ResourceManager resourceManager, + MapUtils mapUtils, + ZoneFactory zoneFactory, + Player player) { this.fileSystem = fileSystem; this.uidStore = uidStore; this.resourceManager = resourceManager; this.mapUtils = mapUtils; - this.zoneFactory = zoneFactory; + this.zoneFactory = zoneFactory; + this.player = player; } /** @@ -136,7 +141,7 @@ private Dungeon loadDungeon(Element root, int uid) { } public Dungeon loadThemedDungeon(String name, String dungeonTheme, int uid) { - Dungeon map = new Dungeon(name, uid,zoneFactory); + Dungeon map = new Dungeon(name, uid, zoneFactory); RDungeonTheme theme = (RDungeonTheme) resourceManager.getResource(dungeonTheme, "theme"); int minZ = theme.min; @@ -175,7 +180,8 @@ public Dungeon loadThemedDungeon(String name, String dungeonTheme, int uid) { private World buildWorldFromModel(WorldModel model, int uid) { World world = new World(model.header.name, uid); Zone zone = world.getZone(0); // outdoor maps have only zone 0 - EntityFactory entityFactory = new EntityFactory(uidStore, resourceManager); + ItemFactory itemFactory = new ItemFactory(resourceManager); + CreatureFactory creatureFactory = new CreatureFactory(resourceManager, uidStore, player); // Add regions for (WorldModel.RegionData regionData : model.regions) { Region region = buildRegionFromModel(regionData); @@ -185,7 +191,7 @@ private World buildWorldFromModel(WorldModel model, int uid) { // Add creatures for (WorldModel.CreaturePlacement cp : model.creatures) { long creatureUID = UIDStore.getObjectUID(uid, cp.uid); - Creature creature = entityFactory.getCreature(cp.id, cp.x, cp.y, creatureUID); + Creature creature = creatureFactory.getCreature(cp.id, cp.x, cp.y, creatureUID); uidStore.addEntity(creature); zone.addCreature(creature); } @@ -193,7 +199,7 @@ private World buildWorldFromModel(WorldModel model, int uid) { // Add items (simple items) for (WorldModel.ItemPlacement ip : model.items.items) { long itemUID = UIDStore.getObjectUID(uid, ip.uid); - Item item = entityFactory.getItem(ip.id, ip.x, ip.y, itemUID); + Item item = itemFactory.getItem(ip.id, ip.x, ip.y, itemUID); uidStore.addEntity(item); zone.addItem(item); } @@ -201,7 +207,7 @@ private World buildWorldFromModel(WorldModel model, int uid) { // Add doors for (WorldModel.DoorPlacement dp : model.items.doors) { long doorUID = UIDStore.getObjectUID(uid, dp.uid); - Door door = buildDoorFromModel(dp, uid, doorUID, entityFactory); + Door door = buildDoorFromModel(dp, uid, doorUID, itemFactory); uidStore.addEntity(door); zone.addItem(door); } @@ -209,7 +215,7 @@ private World buildWorldFromModel(WorldModel model, int uid) { // Add containers for (WorldModel.ContainerPlacement cp : model.items.containers) { long containerUID = UIDStore.getObjectUID(uid, cp.uid); - Container container = buildContainerFromModel(cp, uid, containerUID, entityFactory); + Container container = buildContainerFromModel(cp, uid, containerUID, itemFactory); uidStore.addEntity(container); zone.addItem(container); } @@ -229,8 +235,9 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { if (model.header.theme != null) { return loadThemedDungeon(model.header.name, model.header.theme, uid); } - EntityFactory entityFactory = new EntityFactory(uidStore, resourceManager); - Dungeon dungeon = new Dungeon(model.header.name, uid,zoneFactory); + ItemFactory itemFactory = new ItemFactory(resourceManager); + CreatureFactory creatureFactory = new CreatureFactory(resourceManager, uidStore, player); + Dungeon dungeon = new Dungeon(model.header.name, uid, zoneFactory); for (DungeonModel.Level levelData : model.levels) { int level = levelData.l; @@ -260,7 +267,7 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { // Add creatures for (WorldModel.CreaturePlacement cp : levelData.creatures) { long creatureUID = UIDStore.getObjectUID(uid, cp.uid); - Creature creature = entityFactory.getCreature(cp.id, cp.x, cp.y, creatureUID); + Creature creature = creatureFactory.getCreature(cp.id, cp.x, cp.y, creatureUID); uidStore.addEntity(creature); zone.addCreature(creature); } @@ -268,7 +275,7 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { // Add items for (WorldModel.ItemPlacement ip : levelData.items.items) { long itemUID = UIDStore.getObjectUID(uid, ip.uid); - Item item = entityFactory.getItem(ip.id, ip.x, ip.y, itemUID); + Item item = itemFactory.getItem(ip.id, ip.x, ip.y, itemUID); uidStore.addEntity(item); zone.addItem(item); } @@ -276,7 +283,7 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { // Add doors for (WorldModel.DoorPlacement dp : levelData.items.doors) { long doorUID = UIDStore.getObjectUID(uid, dp.uid); - Door door = buildDoorFromModel(dp, uid, doorUID, entityFactory); + Door door = buildDoorFromModel(dp, uid, doorUID, itemFactory); uidStore.addEntity(door); zone.addItem(door); } @@ -284,7 +291,7 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { // Add containers for (WorldModel.ContainerPlacement cp : levelData.items.containers) { long containerUID = UIDStore.getObjectUID(uid, cp.uid); - Container container = buildContainerFromModel(cp, uid, containerUID, entityFactory); + Container container = buildContainerFromModel(cp, uid, containerUID, itemFactory); uidStore.addEntity(container); zone.addItem(container); } @@ -333,8 +340,8 @@ private Region buildRegionFromModel(WorldModel.RegionData regionData) { * @return the constructed Door */ private Door buildDoorFromModel( - WorldModel.DoorPlacement doorData, int mapUID, long doorUID, EntityFactory entityFactory) { - Door door = (Door) entityFactory.getItem(doorData.id, doorData.x, doorData.y, doorUID); + WorldModel.DoorPlacement doorData, int mapUID, long doorUID, ItemFactory itemFactory) { + Door door = (Door) itemFactory.getItem(doorData.id, doorData.x, doorData.y, doorUID); // Lock if (doorData.lock != null) { @@ -409,10 +416,10 @@ private Container buildContainerFromModel( WorldModel.ContainerPlacement containerData, int mapUID, long containerUID, - EntityFactory entityFactory) { + ItemFactory itemFactory) { Container container = (Container) - entityFactory.getItem(containerData.id, containerData.x, containerData.y, containerUID); + itemFactory.getItem(containerData.id, containerData.x, containerData.y, containerUID); // Lock if (containerData.lock != null) { @@ -442,13 +449,13 @@ private Container buildContainerFromModel( if (!containerData.contents.isEmpty()) { for (WorldModel.ContainerPlacement.ContainerItem contentData : containerData.contents) { long contentUID = UIDStore.getObjectUID(mapUID, contentData.uid); - uidStore.addEntity(entityFactory.getItem(contentData.id, contentUID)); + uidStore.addEntity(itemFactory.getItem(contentData.id, contentUID)); container.addItem(contentUID); } } else { // Default items from resource definition for (String itemId : ((RItem.Container) container.resource).contents) { - Item item = entityFactory.getItem(itemId, uidStore.createNewEntityUID()); + Item item = itemFactory.getItem(itemId, uidStore.createNewEntityUID()); uidStore.addEntity(item); container.addItem(item.getUID()); } @@ -457,7 +464,13 @@ private Container buildContainerFromModel( return container; } - private void loadZone(Element root, Map map, int l, int uid, EntityFactory entityFactory) { + private void loadZone( + Element root, + Map map, + int l, + int uid, + ItemFactory itemFactory, + CreatureFactory creatureFactory) { for (Element region : root.getChild("regions").getChildren()) { // load regions map.getZone(l).addRegion(loadRegion(region)); } @@ -467,7 +480,7 @@ private void loadZone(Element root, Map map, int l, int uid, EntityFactory entit int x = Integer.parseInt(c.getAttributeValue("x")); int y = Integer.parseInt(c.getAttributeValue("y")); long creatureUID = UIDStore.getObjectUID(uid, Integer.parseInt(c.getAttributeValue("uid"))); - Creature creature = entityFactory.getCreature(species, x, y, creatureUID); + Creature creature = creatureFactory.getCreature(species, x, y, creatureUID); uidStore.addEntity(creature); map.getZone(l).addCreature(creature); } @@ -482,13 +495,12 @@ private void loadZone(Element root, Map map, int l, int uid, EntityFactory entit if (i.getName().equals("container")) { item = loadContainer( - i, id, x, y, itemUID, uid, entityFactory); // because containers are complicated + i, id, x, y, itemUID, uid, itemFactory); // because containers are complicated } else if (i.getName().equals("door")) { item = - loadDoor( - i, id, x, y, itemUID, uid, entityFactory); // because doors are complicated too + loadDoor(i, id, x, y, itemUID, uid, itemFactory); // because doors are complicated too } else { - item = entityFactory.getItem(id, x, y, itemUID); + item = itemFactory.getItem(id, x, y, itemUID); } map.getZone(l).addItem(item); uidStore.addEntity(item); @@ -500,14 +512,8 @@ private void loadZone(Element root, Map map, int l, int uid, EntityFactory entit * this is going to get messy, with a whole if-then-else heap */ private Door loadDoor( - Element door, - String id, - int x, - int y, - long itemUID, - int mapUID, - EntityFactory entityFactory) { - Door d = (Door) entityFactory.getItem(id, x, y, itemUID); + Element door, String id, int x, int y, long itemUID, int mapUID, ItemFactory itemFactory) { + Door d = (Door) itemFactory.getItem(id, x, y, itemUID); // lock difficulty int lock = 0; @@ -589,8 +595,8 @@ private Container loadContainer( int y, long itemUID, int mapUID, - EntityFactory entityFactory) { - Container cont = (Container) entityFactory.getItem(id, x, y, itemUID); + ItemFactory itemFactory) { + Container cont = (Container) itemFactory.getItem(id, x, y, itemUID); // lock difficulty if (container.getAttribute("lock") != null) { @@ -623,12 +629,12 @@ private Container loadContainer( for (Element e : container.getChildren("item")) { long contentUID = UIDStore.getObjectUID(mapUID, Integer.parseInt(e.getAttributeValue("uid"))); - uidStore.addEntity(entityFactory.getItem(e.getAttributeValue("id"), contentUID)); + uidStore.addEntity(itemFactory.getItem(e.getAttributeValue("id"), contentUID)); cont.addItem(contentUID); } } else { // otherwise default items for (String s : ((RItem.Container) cont.resource).contents) { - Item i = entityFactory.getItem(s, uidStore.createNewEntityUID()); + Item i = itemFactory.getItem(s, uidStore.createNewEntityUID()); uidStore.addEntity(i); cont.addItem(i.getUID()); } diff --git a/src/main/java/neon/maps/Zone.java b/src/main/java/neon/maps/Zone.java index 40066c4..e30915b 100644 --- a/src/main/java/neon/maps/Zone.java +++ b/src/main/java/neon/maps/Zone.java @@ -22,14 +22,12 @@ import java.awt.Rectangle; import java.util.*; import lombok.Getter; -import neon.core.GameStores; import neon.entities.Creature; import neon.entities.Item; import neon.entities.UIDStore; import neon.resources.RZoneTheme; import neon.resources.ResourceManager; import neon.ui.graphics.*; -import neon.util.mapstorage.MapStore; import neon.util.spatial.*; public class Zone /* implements Externalizable */ { @@ -55,7 +53,13 @@ public class Zone /* implements Externalizable */ { * @param map the map UID * @param index the zone index */ - public Zone(String name, int map, int index, UIDStore uidStore, ResourceManager resourceManager, RTree tree) { + public Zone( + String name, + int map, + int index, + UIDStore uidStore, + ResourceManager resourceManager, + RTree tree) { this.map = map; this.name = name; this.index = index; @@ -64,7 +68,6 @@ public Zone(String name, int map, int index, UIDStore uidStore, ResourceManager this.regions = tree; } - /** * Initializes a new zone with a theme. * @@ -73,8 +76,15 @@ public Zone(String name, int map, int index, UIDStore uidStore, ResourceManager * @param theme the zone theme * @param index the zone index */ - public Zone(String name, int map, RZoneTheme theme, int index, UIDStore uidStore, ResourceManager resourceManager, RTree tree) { - this(name, map, index, uidStore,resourceManager,tree); + public Zone( + String name, + int map, + RZoneTheme theme, + int index, + UIDStore uidStore, + ResourceManager resourceManager, + RTree tree) { + this(name, map, index, uidStore, resourceManager, tree); this.theme = theme; } diff --git a/src/main/java/neon/maps/ZoneActivator.java b/src/main/java/neon/maps/ZoneActivator.java index 9f8bc97..e87ba81 100644 --- a/src/main/java/neon/maps/ZoneActivator.java +++ b/src/main/java/neon/maps/ZoneActivator.java @@ -54,7 +54,7 @@ public void activateZone(Zone zone, Player player) { physicsManager.register(region, region.getBounds(), true); } } - + player.setCurrentZone(zone); // Re-register the player physicsManager.register(player.getPhysicsComponent()); } diff --git a/src/main/java/neon/maps/ZoneFactory.java b/src/main/java/neon/maps/ZoneFactory.java index 10af084..c94a678 100644 --- a/src/main/java/neon/maps/ZoneFactory.java +++ b/src/main/java/neon/maps/ZoneFactory.java @@ -18,6 +18,7 @@ package neon.maps; +import neon.core.GameStores; import neon.entities.UIDStore; import neon.resources.RZoneTheme; import neon.resources.ResourceManager; @@ -34,6 +35,7 @@ public class ZoneFactory { private final MapStore cache; private final UIDStore uidStore; private final ResourceManager resourceManager; + /** * Creates a new ZoneFactory with the given cache database. * @@ -41,19 +43,21 @@ public class ZoneFactory { */ public ZoneFactory(MapStore cache, UIDStore uidStore, ResourceManager resourceManager) { this.cache = cache; - this.uidStore = uidStore; - this.resourceManager = resourceManager; + this.uidStore = uidStore; + this.resourceManager = resourceManager; + } + public ZoneFactory(GameStores gameStore) { + this(gameStore.getAtlas().getCache(), gameStore.getStore(), gameStore.getResources()); } public Zone createZone(String name, int map, int index) { RTree regions = new RTree<>(100, 40, cache, map + ":" + index); - return new Zone(name,map,index,uidStore,resourceManager,regions); + return new Zone(name, map, index, uidStore, resourceManager, regions); } public Zone createZoneWithTheme(String name, int map, int index, RZoneTheme theme) { RTree regions = new RTree<>(100, 40, cache, map + ":" + index); - return new Zone(name,map,theme,index,uidStore,resourceManager,regions); + return new Zone(name, map, theme, index, uidStore, resourceManager, regions); } - } diff --git a/src/main/java/neon/maps/generators/DungeonGenerator.java b/src/main/java/neon/maps/generators/DungeonGenerator.java index b92568b..3978b5a 100644 --- a/src/main/java/neon/maps/generators/DungeonGenerator.java +++ b/src/main/java/neon/maps/generators/DungeonGenerator.java @@ -18,14 +18,13 @@ package neon.maps.generators; -import static neon.maps.generators.RoomGenerator.newExposed; - import java.awt.*; -import java.awt.geom.*; import java.util.*; - +import neon.core.GameStores; import neon.entities.*; import neon.entities.Container; +import neon.entities.CreatureFactory; +import neon.entities.ItemFactory; import neon.entities.property.Habitat; import neon.maps.*; import neon.maps.Region.Modifier; @@ -51,17 +50,15 @@ public class DungeonGenerator { private final EntityStore entityStore; private final ResourceProvider resourceProvider; private final QuestProvider questProvider; - private final EntityFactory entityFactory; + private final ItemFactory itemFactory; + private final CreatureFactory creatureFactory; + private final Player player; + private final GameStores gameStores; // random sources private final MapUtils mapUtils; private final Dice dice; - // helper generators - private final BlocksGenerator blocksGenerator; - private final ComplexGenerator complexGenerator; - private final CaveGenerator caveGenerator; - private final MazeGenerator mazeGenerator; - private final FeatureGenerator featureGenerator; + private final DungeonTerrainGenerator dungeonTerrainGenerator; // things private int[][] tiles; // information about the type of terrain @@ -76,11 +73,8 @@ public class DungeonGenerator { * @param questProvider the quest provider service */ public DungeonGenerator( - RZoneTheme theme, - neon.entities.UIDStore entityStore, - ResourceManager resourceProvider, - QuestProvider questProvider) { - this(theme, entityStore, resourceProvider, questProvider, new MapUtils(), new Dice()); + RZoneTheme theme, QuestProvider questProvider, Player player, GameStores gameStores) { + this(theme, questProvider, player, gameStores, new MapUtils(), new Dice()); } /** @@ -95,24 +89,23 @@ public DungeonGenerator( */ public DungeonGenerator( RZoneTheme theme, - neon.entities.UIDStore entityStore, - ResourceManager resourceProvider, QuestProvider questProvider, + Player player, + GameStores gameStores, MapUtils mapUtils, Dice dice) { this.theme = theme; + this.player = player; + this.gameStores = gameStores; this.zone = null; - this.entityStore = entityStore; - this.resourceProvider = resourceProvider; + this.entityStore = gameStores.getStore(); + this.resourceProvider = gameStores.getResources(); this.questProvider = questProvider; this.mapUtils = mapUtils; this.dice = dice; - this.blocksGenerator = new BlocksGenerator(mapUtils); - this.complexGenerator = new ComplexGenerator(mapUtils); - this.caveGenerator = new CaveGenerator(dice); - this.mazeGenerator = new MazeGenerator(dice); - this.featureGenerator = new FeatureGenerator(mapUtils); - this.entityFactory = new EntityFactory(entityStore,resourceProvider); + dungeonTerrainGenerator = new DungeonTerrainGenerator(mapUtils, dice); + this.itemFactory = new ItemFactory(gameStores.getResources()); + this.creatureFactory = new CreatureFactory(gameStores, player); } /** @@ -124,11 +117,8 @@ public DungeonGenerator( * @param questProvider the quest provider service */ public DungeonGenerator( - Zone zone, - UIDStore entityStore, - ResourceManager resourceProvider, - QuestProvider questProvider) { - this(zone, entityStore, resourceProvider, questProvider, new MapUtils(), new Dice()); + Zone zone, QuestProvider questProvider, Player player, GameStores gameStores) { + this(zone, questProvider, player, gameStores, new MapUtils(), new Dice()); } /** @@ -144,24 +134,24 @@ public DungeonGenerator( */ public DungeonGenerator( Zone zone, - UIDStore entityStore, - ResourceManager resourceProvider, QuestProvider questProvider, + Player player, + GameStores gameStores, MapUtils mapUtils, Dice dice) { this.zone = zone; this.theme = zone.getTheme(); - this.entityStore = entityStore; - this.resourceProvider = resourceProvider; + this.entityStore = gameStores.getStore(); + this.resourceProvider = gameStores.getResources(); this.questProvider = questProvider; + this.player = player; + this.gameStores = gameStores; this.mapUtils = mapUtils; this.dice = dice; - this.blocksGenerator = new BlocksGenerator(mapUtils); - this.complexGenerator = new ComplexGenerator(mapUtils); - this.caveGenerator = new CaveGenerator(dice); - this.mazeGenerator = new MazeGenerator(dice); - this.featureGenerator = new FeatureGenerator(mapUtils); - this.entityFactory = new EntityFactory(entityStore,resourceProvider); + dungeonTerrainGenerator = new DungeonTerrainGenerator(mapUtils, dice); + this.itemFactory = new ItemFactory(gameStores.getResources()); + // CreatureFactory needs GameContext too, create minimal wrapper + this.creatureFactory = new CreatureFactory(gameStores, player); } /** @@ -175,8 +165,9 @@ public void generate(Door door, Zone previous, Atlas atlas) { Dungeon map = (Dungeon) atlas.getMap(zone.getMap()); // generate terrain - generateTiles(); - + var rv = dungeonTerrainGenerator.generateTilesOnly(theme); + tiles = rv.tiles(); + terrain = rv.terrain(); // width and height of generated zone int width = tiles.length; int height = tiles[0].length; @@ -197,7 +188,7 @@ public void generate(Door door, Zone previous, Atlas atlas) { int destMap = previous.getMap(); int destZone = previous.getIndex(); String doorType = theme.doors.split(",")[0]; - Door tdoor = (Door) entityFactory.getItem(doorType, p.x, p.y, entityStore.createNewEntityUID()); + Door tdoor = (Door) itemFactory.getItem(doorType, p.x, p.y, entityStore.createNewEntityUID()); entityStore.addEntity(tdoor); tiles[p.x][p.y] = MapUtils.DOOR; tdoor.portal.setDestination(destPoint, destZone, destMap); @@ -220,7 +211,7 @@ public void generate(Door door, Zone previous, Atlas atlas) { Door toDoor = (Door) - entityFactory.getItem( + itemFactory.getItem( theme.doors.split(",")[0], pos.x, pos.y, entityStore.createNewEntityUID()); entityStore.addEntity(toDoor); tiles[pos.x][pos.y] = MapUtils.DOOR; @@ -241,7 +232,7 @@ public void generate(Door door, Zone previous, Atlas atlas) { Door toDoor = (Door) - entityFactory.getItem( + itemFactory.getItem( theme.doors.split(",")[0], pos.x, pos.y, @@ -271,12 +262,12 @@ public void generate(Door door, Zone previous, Atlas atlas) { p1.y = dice.rollDice(1, height, -1); } while (tiles[p1.x][p1.y] != MapUtils.FLOOR); if (resourceProvider.getResource(object) instanceof RItem) { - Item item = entityFactory.getItem(object, p1.x, p1.y, entityStore.createNewEntityUID()); + Item item = itemFactory.getItem(object, p1.x, p1.y, entityStore.createNewEntityUID()); entityStore.addEntity(item); zone.addItem(item); } else if (resourceProvider.getResource(object) instanceof RCreature) { Creature creature = - entityFactory.getCreature(object, p1.x, p1.y, entityStore.createNewEntityUID()); + creatureFactory.getCreature(object, p1.x, p1.y, entityStore.createNewEntityUID()); entityStore.addEntity(creature); zone.addCreature(creature); } @@ -284,168 +275,6 @@ public void generate(Door door, Zone previous, Atlas atlas) { } /** Generates a single zone from a given theme. */ - public String[][] generateTiles() { - // width and height of dungeon - int width = mapUtils.random(theme.min, theme.max); - int height = mapUtils.random(theme.min, theme.max); - - // base terrain without features - tiles = generateBaseTiles(theme.type, width, height); - terrain = makeTerrain(tiles, theme.floor.split(",")); - - // scale factor for generating features, creatures and items - double ratio = (width * height) / Math.pow(MapUtils.average(theme.min, theme.max), 2); - - // features - generateFeatures(theme.features, ratio); - - // creatures - for (String creature : theme.creatures.keySet()) { - for (int i = (int) (dice.rollDice("1d" + theme.creatures.get(creature)) * ratio); - i > 0; - i--) { - Point p = new Point(0, 0); - do { - p.x = dice.rollDice(1, width, -1); - p.y = dice.rollDice(1, height, -1); - } while (tiles[p.x][p.y] != MapUtils.FLOOR); - - terrain[p.x][p.y] = terrain[p.x][p.y] + ";c:" + creature; - } - } - - // items - for (String item : theme.items.keySet()) { - for (int i = (int) (dice.rollDice("1d" + theme.items.get(item)) * ratio); i > 0; i--) { - Point p = new Point(0, 0); - do { - p.x = dice.rollDice(1, width, -1); - p.y = dice.rollDice(1, height, -1); - } while (tiles[p.x][p.y] != MapUtils.FLOOR); - - terrain[p.x][p.y] = terrain[p.x][p.y] + ";i:" + item; - } - } - - return terrain; - } - - /** - * Generates base tiles for a dungeon of the given type. Package-private for testing. - * - * @param type dungeon type (cave, pits, maze, mine, bsp, packed, or default/sparse) - * @param width dungeon width - * @param height dungeon height - * @return 2D array of tile types - */ - int[][] generateBaseTiles(String type, int width, int height) { - int[][] tiles = new int[width][height]; - switch (type) { - case "cave": - tiles = makeTiles(mazeGenerator.generateSquashedMaze(width, height, 3), width, height); - break; - case "pits": - tiles = caveGenerator.generateOpenCave(width, height, 3); - break; - case "maze": - tiles = makeTiles(mazeGenerator.generateMaze(width, height, 3, 50), width, height); - break; - case "mine": - Area mine = mazeGenerator.generateSquashedMaze(width, height, 12); - mine.add(mazeGenerator.generateMaze(width, height, 12, 40)); - tiles = makeTiles(mine, width, height); - break; - case "bsp": - tiles = complexGenerator.generateBSPDungeon(width, height, 5, 8); - break; - case "packed": - tiles = complexGenerator.generatePackedDungeon(width, height, 10, 4, 7); - break; - default: - tiles = complexGenerator.generateSparseDungeon(width, height, 5, 5, 15); - break; - } - - return tiles; - } - - private void generateFeatures(Collection features, double ratio) { - int width = terrain.length; - int height = terrain[0].length; - for (RZoneTheme.Feature feature : features) { - int s = feature.s; - String t = feature.t; - int n = feature.n * 100; - if (n > 100) { - n = mapUtils.random(0, (int) (n * ratio / 100)); - } else { - n = (mapUtils.random(0, (int) (n * ratio)) > 50) ? 1 : 0; - } - - if (feature.value.equals("lake")) { // large patch that just overwrites everything - int size = 100 / s; - ArrayList lakes = - blocksGenerator.createSparseRectangles( - width, height, width / size, height / size, 2, n); - for (Rectangle r : lakes) { // place lake - featureGenerator.generateLake(terrain, t, r); - } - } else if (feature.value.equals("patch")) { // patch that only overwrites floor tiles - // place patches - ArrayList patches = - blocksGenerator.createSparseRectangles(width, height, s, s, 2, n); - for (Rectangle r : patches) { - Polygon patch = mapUtils.randomPolygon(r, 16); - for (int x = r.x; x < r.x + r.width; x++) { - for (int y = r.y; y < r.y + r.height; y++) { - if (patch.contains(x, y) && tiles[x][y] == MapUtils.FLOOR) { - terrain[x][y] = t; - } - } - } - } - } else if (feature.value.equals("chunk")) { // patch that only overwrites wall tiles - ArrayList chunks = - blocksGenerator.createSparseRectangles(width, height, s, s, 2, n); - for (Rectangle chunk : chunks) { - for (int x = chunk.x; x < chunk.x + chunk.width; x++) { - for (int y = chunk.y; y < chunk.y + chunk.height; y++) { - if (tiles[x][y] == MapUtils.WALL - || tiles[x][y] == MapUtils.WALL_ROOM - || tiles[x][y] == MapUtils.CORNER - || tiles[x][y] == MapUtils.ENTRY) { - terrain[x][y] = t; - } - } - } - } - } else if (feature.value.equals("stain")) { // patch that only overwrites exposed wall tiles - ArrayList stains = - blocksGenerator.createSparseRectangles(width, height, s, s, 2, n); - for (Rectangle stain : stains) { - for (int x = stain.x; x < stain.x + stain.width; x++) { - for (int y = stain.y; y < stain.y + stain.height; y++) { - if ((tiles[x][y] == MapUtils.WALL - || tiles[x][y] == MapUtils.WALL_ROOM - || tiles[x][y] == MapUtils.CORNER - || tiles[x][y] == MapUtils.ENTRY) - && exposed(tiles, x, y)) { - terrain[x][y] = t; - } - } - } - } - } else if (feature.value.equals("river")) { - while (n-- > 0) { // apparently first >, then -- - featureGenerator.generateRiver(terrain, tiles, t, s); - } - } - } - } - - private static boolean exposed(int[][] tiles, int x, int y) { - return newExposed(tiles, x, y); - } // to convert a string[][] into regions, items and creatures private void generateEngineContent(int width, int height) { @@ -492,7 +321,7 @@ private void generateEngineContent(int width, int height) { } private void addDoor(String terrain, String id, int x, int y, int layer) { - Door door = (Door) entityFactory.getItem(id, x, y, entityStore.createNewEntityUID()); + Door door = (Door) itemFactory.getItem(id, x, y, entityStore.createNewEntityUID()); entityStore.addEntity(door); if (tiles[x][y] == MapUtils.DOOR_LOCKED) { door.lock.setLockDC(10); @@ -507,7 +336,7 @@ private void addDoor(String terrain, String id, int x, int y, int layer) { private void addCreature(String description, int x, int y) { String id = description.replace("c:", ""); - Creature creature = entityFactory.getCreature(id, x, y, entityStore.createNewEntityUID()); + Creature creature = creatureFactory.getCreature(id, x, y, entityStore.createNewEntityUID()); // no land creatures in water Rectangle bounds = creature.getShapeComponent(); Modifier modifier = zone.getRegion(bounds.getLocation()).getMovMod(); @@ -521,51 +350,15 @@ private void addCreature(String description, int x, int y) { private void addItem(String description, int x, int y) { String id = description.replace("i:", ""); - Item item = entityFactory.getItem(id, x, y, entityStore.createNewEntityUID()); + Item item = itemFactory.getItem(id, x, y, entityStore.createNewEntityUID()); entityStore.addEntity(item); if (item instanceof Container) { for (String s : ((RItem.Container) item.resource).contents) { - Item i = entityFactory.getItem(s, entityStore.createNewEntityUID()); + Item i = itemFactory.getItem(s, entityStore.createNewEntityUID()); ((Container) item).addItem(i.getUID()); entityStore.addEntity(i); } } zone.addItem(item); } - - private static int[][] makeTiles(Area area, int width, int height) { - int[][] tiles = new int[width][height]; - for (int j = 0; j < height; j++) { - for (int i = 0; i < width; i++) { - if (area.contains(i, j)) { - tiles[i][j] = MapUtils.FLOOR; - } else { - tiles[i][j] = MapUtils.WALL; - } - } - } - return tiles; - } - - private String[][] makeTerrain(int[][] tiles, String[] floors) { - String terrain[][] = new String[tiles.length][tiles[0].length]; - - for (int x = 0; x < tiles.length; x++) { - for (int y = 0; y < tiles[0].length; y++) { - int f = mapUtils.random(0, floors.length - 1); - - switch (tiles[x][y]) { - case MapUtils.CORRIDOR: - case MapUtils.FLOOR: - case MapUtils.DOOR: - case MapUtils.DOOR_CLOSED: - case MapUtils.DOOR_LOCKED: - terrain[x][y] = floors[f]; - break; - } - } - } - - return terrain; - } } diff --git a/src/main/java/neon/maps/generators/DungeonTerrainGenerator.java b/src/main/java/neon/maps/generators/DungeonTerrainGenerator.java new file mode 100644 index 0000000..e61c8bd --- /dev/null +++ b/src/main/java/neon/maps/generators/DungeonTerrainGenerator.java @@ -0,0 +1,229 @@ +package neon.maps.generators; + +import static neon.maps.generators.RoomGenerator.newExposed; + +import java.awt.*; +import java.awt.geom.Area; +import java.util.ArrayList; +import java.util.Collection; +import neon.maps.MapUtils; +import neon.resources.RZoneTheme; +import neon.util.Dice; + +public class DungeonTerrainGenerator { + // helper generators + private final BlocksGenerator blocksGenerator; + private final ComplexGenerator complexGenerator; + private final CaveGenerator caveGenerator; + private final MazeGenerator mazeGenerator; + private final FeatureGenerator featureGenerator; + + private final MapUtils mapUtils; + private final Dice dice; + + public DungeonTerrainGenerator() { + this(new MapUtils(), new Dice()); + } + + public DungeonTerrainGenerator(MapUtils mapUtils, Dice dice) { + this.mapUtils = mapUtils; + this.dice = dice; + this.blocksGenerator = new BlocksGenerator(mapUtils); + this.complexGenerator = new ComplexGenerator(mapUtils); + this.caveGenerator = new CaveGenerator(dice); + this.mazeGenerator = new MazeGenerator(dice); + this.featureGenerator = new FeatureGenerator(mapUtils); + } + + public record TilesAndTerrain(int[][] tiles, String[][] terrain) {} + + public TilesAndTerrain generateTilesOnly(RZoneTheme theme) { + // width and height of dungeon + int width = mapUtils.random(theme.min, theme.max); + int height = mapUtils.random(theme.min, theme.max); + + // base terrain without features + int[][] tiles = generateBaseTiles(theme.type, width, height); + String[][] terrain = makeTerrain(tiles, theme.floor.split(",")); + + // scale factor for generating features, creatures and items + double ratio = (width * height) / Math.pow(MapUtils.average(theme.min, theme.max), 2); + + // features + generateFeatures(theme.features, ratio, tiles, terrain); + + // creatures + for (String creature : theme.creatures.keySet()) { + for (int i = (int) (dice.rollDice("1d" + theme.creatures.get(creature)) * ratio); + i > 0; + i--) { + Point p = new Point(0, 0); + do { + p.x = dice.rollDice(1, width, -1); + p.y = dice.rollDice(1, height, -1); + } while (tiles[p.x][p.y] != MapUtils.FLOOR); + + terrain[p.x][p.y] = terrain[p.x][p.y] + ";c:" + creature; + } + } + + // items + for (String item : theme.items.keySet()) { + for (int i = (int) (dice.rollDice("1d" + theme.items.get(item)) * ratio); i > 0; i--) { + Point p = new Point(0, 0); + do { + p.x = dice.rollDice(1, width, -1); + p.y = dice.rollDice(1, height, -1); + } while (tiles[p.x][p.y] != MapUtils.FLOOR); + + terrain[p.x][p.y] = terrain[p.x][p.y] + ";i:" + item; + } + } + + return new TilesAndTerrain(tiles, terrain); + } + + /** + * Generates base tiles for a dungeon of the given type. Package-private for testing. + * + * @param type dungeon type (cave, pits, maze, mine, bsp, packed, or default/sparse) + * @param width dungeon width + * @param height dungeon height + * @return 2D array of tile types + */ + public int[][] generateBaseTiles(String type, int width, int height) { + int[][] tiles = new int[width][height]; + switch (type) { + case "cave" -> + tiles = makeTiles(mazeGenerator.generateSquashedMaze(width, height, 3), width, height); + case "pits" -> tiles = caveGenerator.generateOpenCave(width, height, 3); + case "maze" -> + tiles = makeTiles(mazeGenerator.generateMaze(width, height, 3, 50), width, height); + case "mine" -> { + Area mine = mazeGenerator.generateSquashedMaze(width, height, 12); + mine.add(mazeGenerator.generateMaze(width, height, 12, 40)); + tiles = makeTiles(mine, width, height); + } + case "bsp" -> tiles = complexGenerator.generateBSPDungeon(width, height, 5, 8); + case "packed" -> tiles = complexGenerator.generatePackedDungeon(width, height, 10, 4, 7); + default -> tiles = complexGenerator.generateSparseDungeon(width, height, 5, 5, 15); + } + + return tiles; + } + + private void generateFeatures( + Collection features, double ratio, int[][] tiles, String[][] terrain) { + int width = terrain.length; + int height = terrain[0].length; + for (RZoneTheme.Feature feature : features) { + int s = feature.s; + String t = feature.t; + int n = feature.n * 100; + if (n > 100) { + n = mapUtils.random(0, (int) (n * ratio / 100)); + } else { + n = (mapUtils.random(0, (int) (n * ratio)) > 50) ? 1 : 0; + } + + if (feature.value.equals("lake")) { // large patch that just overwrites everything + int size = 100 / s; + ArrayList lakes = + blocksGenerator.createSparseRectangles( + width, height, width / size, height / size, 2, n); + for (Rectangle r : lakes) { // place lake + featureGenerator.generateLake(terrain, t, r); + } + } else if (feature.value.equals("patch")) { // patch that only overwrites floor tiles + // place patches + ArrayList patches = + blocksGenerator.createSparseRectangles(width, height, s, s, 2, n); + for (Rectangle r : patches) { + Polygon patch = mapUtils.randomPolygon(r, 16); + for (int x = r.x; x < r.x + r.width; x++) { + for (int y = r.y; y < r.y + r.height; y++) { + if (patch.contains(x, y) && tiles[x][y] == MapUtils.FLOOR) { + terrain[x][y] = t; + } + } + } + } + } else if (feature.value.equals("chunk")) { // patch that only overwrites wall tiles + ArrayList chunks = + blocksGenerator.createSparseRectangles(width, height, s, s, 2, n); + for (Rectangle chunk : chunks) { + for (int x = chunk.x; x < chunk.x + chunk.width; x++) { + for (int y = chunk.y; y < chunk.y + chunk.height; y++) { + if (tiles[x][y] == MapUtils.WALL + || tiles[x][y] == MapUtils.WALL_ROOM + || tiles[x][y] == MapUtils.CORNER + || tiles[x][y] == MapUtils.ENTRY) { + terrain[x][y] = t; + } + } + } + } + } else if (feature.value.equals("stain")) { // patch that only overwrites exposed wall tiles + ArrayList stains = + blocksGenerator.createSparseRectangles(width, height, s, s, 2, n); + for (Rectangle stain : stains) { + for (int x = stain.x; x < stain.x + stain.width; x++) { + for (int y = stain.y; y < stain.y + stain.height; y++) { + if ((tiles[x][y] == MapUtils.WALL + || tiles[x][y] == MapUtils.WALL_ROOM + || tiles[x][y] == MapUtils.CORNER + || tiles[x][y] == MapUtils.ENTRY) + && exposed(tiles, x, y)) { + terrain[x][y] = t; + } + } + } + } + } else if (feature.value.equals("river")) { + while (n-- > 0) { // apparently first >, then -- + featureGenerator.generateRiver(terrain, tiles, t, s); + } + } + } + } + + private static int[][] makeTiles(Area area, int width, int height) { + int[][] tiles = new int[width][height]; + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + if (area.contains(i, j)) { + tiles[i][j] = MapUtils.FLOOR; + } else { + tiles[i][j] = MapUtils.WALL; + } + } + } + return tiles; + } + + private String[][] makeTerrain(int[][] tiles, String[] floors) { + String[][] terrain = new String[tiles.length][tiles[0].length]; + + for (int x = 0; x < tiles.length; x++) { + for (int y = 0; y < tiles[0].length; y++) { + int f = mapUtils.random(0, floors.length - 1); + + switch (tiles[x][y]) { + case MapUtils.CORRIDOR: + case MapUtils.FLOOR: + case MapUtils.DOOR: + case MapUtils.DOOR_CLOSED: + case MapUtils.DOOR_LOCKED: + terrain[x][y] = floors[f]; + break; + } + } + } + + return terrain; + } + + private static boolean exposed(int[][] tiles, int x, int y) { + return newExposed(tiles, x, y); + } +} diff --git a/src/main/java/neon/maps/generators/TownGenerator.java b/src/main/java/neon/maps/generators/TownGenerator.java index 3467cb0..6e8c7d2 100644 --- a/src/main/java/neon/maps/generators/TownGenerator.java +++ b/src/main/java/neon/maps/generators/TownGenerator.java @@ -21,7 +21,7 @@ import java.awt.Rectangle; import java.util.ArrayList; import neon.entities.Door; -import neon.entities.EntityFactory; +import neon.entities.ItemFactory; import neon.entities.UIDStore; import neon.maps.MapUtils; import neon.maps.Region; @@ -40,7 +40,8 @@ public class TownGenerator { private final UIDStore entityStore; private final ResourceManager resourceProvider; private final MapUtils mapUtils; - private final EntityFactory entityFactory; + private final ItemFactory itemFactory; + /** * Creates a town generator with dependency injection. Uses default (non-deterministic) random * number generation. @@ -51,7 +52,6 @@ public class TownGenerator { */ public TownGenerator(Zone zone, UIDStore entityStore, ResourceManager resourceProvider) { this(zone, entityStore, resourceProvider, new MapUtils()); - } /** @@ -69,7 +69,36 @@ public TownGenerator( this.entityStore = entityStore; this.resourceProvider = resourceProvider; this.mapUtils = mapUtils; - entityFactory = new EntityFactory(entityStore,resourceProvider); + + // Create minimal GameStores wrapper for ItemFactory + neon.core.GameStores gameStores = + new neon.core.GameStores() { + @Override + public neon.maps.Atlas getAtlas() { + return null; + } + + @Override + public neon.entities.UIDStore getStore() { + return entityStore; + } + + @Override + public neon.resources.ResourceManager getResources() { + return resourceProvider; + } + + @Override + public neon.systems.files.FileSystem getFileSystem() { + return null; + } + + @Override + public neon.maps.ZoneFactory getZoneFactory() { + return null; + } + }; + itemFactory = new ItemFactory(gameStores.getResources()); } /** @@ -137,7 +166,7 @@ private void makeDoor(Region r, RRegionTheme theme) { }; long uid = entityStore.createNewEntityUID(); - Door door = (Door) entityFactory.getItem(theme.door, x, y, uid); + Door door = (Door) itemFactory.getItem(theme.door, x, y, uid); entityStore.addEntity(door); door.lock.close(); zone.addItem(door); diff --git a/src/main/java/neon/maps/generators/WildernessGenerator.java b/src/main/java/neon/maps/generators/WildernessGenerator.java index 10d5ae8..8f15282 100644 --- a/src/main/java/neon/maps/generators/WildernessGenerator.java +++ b/src/main/java/neon/maps/generators/WildernessGenerator.java @@ -19,14 +19,13 @@ package neon.maps.generators; import java.awt.Point; -import java.awt.Polygon; import java.awt.Rectangle; import java.awt.geom.Area; -import java.util.ArrayList; import java.util.Collection; - import neon.core.GameStores; import neon.entities.*; +import neon.entities.CreatureFactory; +import neon.entities.ItemFactory; import neon.entities.property.Habitat; import neon.maps.Decomposer; import neon.maps.MapUtils; @@ -55,17 +54,12 @@ public class WildernessGenerator { private Zone zone; private String[][] terrain; // general terrain info + private final ItemFactory itemFactory; + private final CreatureFactory creatureFactory; private final EntityStore entityStore; private final ResourceProvider resourceProvider; - private final EntityFactory entityFactory; - - // random sources - private final MapUtils mapUtils; private final Dice dice; - - // helper generators - private final BlocksGenerator blocksGenerator; - private final CaveGenerator caveGenerator; + private final WildernessTerrainGenerator wildernessTerrainGenerator; /** * Creates a wilderness generator with dependency injection for engine use. @@ -74,9 +68,8 @@ public class WildernessGenerator { * @param entityStore the entity store service * @param resourceProvider the resource provider service */ - public WildernessGenerator( - Zone zone, GameStores gameStores) { - this(zone, gameStores, new MapUtils(), new Dice()); + public WildernessGenerator(Zone zone, GameStores gameStores, Player gameContext) { + this(zone, gameStores, gameContext, new MapUtils(), new Dice()); } /** @@ -89,30 +82,35 @@ public WildernessGenerator( * @param dice the Dice instance for random operations */ public WildernessGenerator( - Zone zone, - GameStores gameStores, - MapUtils mapUtils, - Dice dice) { + Zone zone, GameStores gameStores, Player gameContext, MapUtils mapUtils, Dice dice) { this.zone = zone; this.entityStore = gameStores.getStore(); this.resourceProvider = gameStores.getResources(); - this.mapUtils = mapUtils; this.dice = dice; - this.blocksGenerator = new BlocksGenerator(mapUtils); - this.caveGenerator = new CaveGenerator(dice); - this.entityFactory = new EntityFactory(gameStores.getStore(),gameStores.getResources()); + this.wildernessTerrainGenerator = new WildernessTerrainGenerator(mapUtils, dice); + this.itemFactory = new ItemFactory(gameStores.getResources()); + this.creatureFactory = new CreatureFactory(gameStores, gameContext); + } + + public WildernessGenerator( + Zone zone, ResourceManager resourceManeger, UIDStore uidStore, Player gameContext) { + this(zone, resourceManeger, uidStore, gameContext, new MapUtils(), new Dice()); } - /** - * Creates a wilderness generator with dependency injection for editor use. - * - * @param terrain the terrain array - * @param entityStore the entity store service - * @param resourceProvider the resource provider service - */ public WildernessGenerator( - String[][] terrain, UIDStore entityStore, ResourceManager resourceProvider) { - this(terrain, entityStore, resourceProvider, new MapUtils(), new Dice()); + Zone zone, + ResourceManager resourceManeger, + UIDStore uidStore, + Player gameContext, + MapUtils mapUtils, + Dice dice) { + this.zone = zone; + this.entityStore = uidStore; + this.resourceProvider = resourceManeger; + this.dice = dice; + this.wildernessTerrainGenerator = new WildernessTerrainGenerator(mapUtils, dice); + this.itemFactory = new ItemFactory(resourceManeger); + this.creatureFactory = new CreatureFactory(resourceManeger, uidStore, gameContext); } /** @@ -126,19 +124,14 @@ public WildernessGenerator( * @param dice the Dice instance for random operations */ public WildernessGenerator( - String[][] terrain, - UIDStore entityStore, - ResourceManager resourceProvider, - MapUtils mapUtils, - Dice dice) { + String[][] terrain, GameStores gameStores, Player gameContext, MapUtils mapUtils, Dice dice) { this.terrain = terrain; - this.entityStore = entityStore; - this.resourceProvider = resourceProvider; - this.mapUtils = mapUtils; + this.entityStore = gameStores.getStore(); + this.resourceProvider = gameStores.getResources(); this.dice = dice; - this.blocksGenerator = new BlocksGenerator(mapUtils); - this.caveGenerator = new CaveGenerator(dice); - this.entityFactory = new EntityFactory(entityStore,resourceProvider); + this.wildernessTerrainGenerator = new WildernessTerrainGenerator(mapUtils, dice); + this.itemFactory = new ItemFactory(gameStores.getResources()); + this.creatureFactory = new CreatureFactory(gameStores, gameContext); } /** Generates a piece of wilderness using the supplied parameters. */ @@ -180,10 +173,13 @@ public void generate(Region region, RRegionTheme theme) { } // generate terrain - generateTerrain(region.getWidth(), region.getHeight(), theme, region.getTextureType()); + terrain = + wildernessTerrainGenerator.generateTerrain( + region.getWidth(), region.getHeight(), theme, region.getTextureType()); // add vegetation if needed - addVegetation(region.getWidth(), region.getHeight(), theme, region.getTextureType()); + wildernessTerrainGenerator.addVegetation( + region.getWidth(), region.getHeight(), theme, region.getTextureType(), terrain); // add creatures addCreatures( @@ -199,15 +195,6 @@ public void generate(Region region, RRegionTheme theme) { } } - public String[][] generate(Rectangle r, RRegionTheme theme, String base) { - // generate terrain - generateTerrain(r.width, r.height, theme, base); - - // generate fauna - addVegetation(r.width, r.height, theme, base); - return terrain; - } - private boolean isOnTop(Region region, Collection regions) { for (Region r : regions) { if (r.getZ() > region.getZ()) { @@ -286,61 +273,6 @@ private void divide(Region region, RRegionTheme theme) { } } - private void generateTerrain(int width, int height, RRegionTheme theme, String base) { - // create terrain and vegetation - switch (theme.type) { - case CHAOTIC: - generateSwamp(width, height, theme); - break; - case PLAIN: - generateForest(width, height, theme); - break; - case RIDGES: - generateRidges(width, height, theme); - break; - case TERRACE: - generateTerraces(width, height, theme); - break; - default: - break; - } - - // blend into neighboring region - makeBorder(base); - - // add features - addFeatures(width, height, theme); - } - - private void addFeatures(int width, int height, RRegionTheme theme) { - double ratio = (width * height) / 10000d; - for (RRegionTheme.Feature feature : theme.features) { - int n = (int) Float.parseFloat(feature.n) * 100; - if (n > 100) { - n = mapUtils.random(0, (int) (n * ratio / 100)); - } else { - n = (mapUtils.random(0, (int) (n * ratio)) > 50) ? 1 : 0; - } - if (feature.value.equals("lake")) { // large patch that just overwrites everything - int size = 100 / Integer.parseInt(feature.s); - ArrayList lakes = - blocksGenerator.createSparseRectangles( - width, height, width / size, height / size, 2, n); - for (Rectangle r : lakes) { - // place lake - Polygon lake = mapUtils.randomPolygon(r, (r.width + r.height) / 2); - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - if (lake.contains(x, y)) { - terrain[y + 1][x + 1] = feature.t; - } - } - } - } - } - } - } - private void addCreatures( int rx, int ry, int width, int height, RRegionTheme theme, String base) { double ratio = (double) width * height / 10000; @@ -353,7 +285,7 @@ private void addCreatures( String region = t.isEmpty() ? base : t; Creature creature = - entityFactory.getCreature(id, rx + x, ry + y, entityStore.createNewEntityUID()); + creatureFactory.getCreature(id, rx + x, ry + y, entityStore.createNewEntityUID()); RTerrain terrain = (RTerrain) resourceProvider.getResource(region, "terrain"); // Only spawn creatures if their habitat matches the terrain // LAND creatures should NOT spawn in SWIM terrain @@ -379,11 +311,11 @@ private void generateEngineContent(Region region) { if (entry.startsWith("i:")) { String id = entry.replace("i:", ""); long uid = entityStore.createNewEntityUID(); - Item item = entityFactory.getItem(id, region.getX() + i, region.getY() + j, uid); + Item item = itemFactory.getItem(id, region.getX() + i, region.getY() + j, uid); entityStore.addEntity(item); if (item instanceof Container) { for (String s : ((RItem.Container) item.resource).contents) { - Item content = entityFactory.getItem(s, entityStore.createNewEntityUID()); + Item content = itemFactory.getItem(s, entityStore.createNewEntityUID()); ((Container) item).addItem(content.getUID()); entityStore.addEntity(content); } @@ -393,7 +325,7 @@ private void generateEngineContent(Region region) { String id = entry.replace("c:", ""); long uid = entityStore.createNewEntityUID(); Creature creature = - entityFactory.getCreature(id, region.getX() + i, region.getY() + j, uid); + creatureFactory.getCreature(id, region.getX() + i, region.getY() + j, uid); entityStore.addEntity(creature); zone.addCreature(creature); } else if (!entry.isEmpty() && !entry.equals(region.getTextureType())) { @@ -414,198 +346,4 @@ private void generateEngineContent(Region region) { } } } - - protected void generateTerraces(int width, int height, RRegionTheme theme) { - int[][] tiles = caveGenerator.generateOpenCave(width, height, 3); - - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - if (tiles[x][y] > 0) { - terrain[y + 1][x + 1] = theme.floor; - } - } - } - } - - protected void generateForest(int width, int height, RRegionTheme theme) {} - - protected void generateRidges(int width, int height, RRegionTheme theme) { - // TODO: Replace with proper noise generation (AnimalStripe from jtexgen not available) - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - // Simple placeholder - generates ridges based on coordinate pattern - if ((x + y * 3) % 10 < 5) { - terrain[y + 1][x + 1] = theme.floor; - } - } - } - } - - private void addVegetation(int width, int height, RRegionTheme theme, String base) { - if (!theme.vegetation.isEmpty()) { - String[][] fauna = new String[width][height]; - for (String id : theme.vegetation.keySet()) { - int abundance = theme.vegetation.get(id); - Item dummy = entityFactory.getItem(id, 0); - int size = dummy.getShapeComponent().width; // size van boom in rekening brengen - int ratio = (width / size) * (height / size); - boolean[][] fill = generateIslands(width / size, height / size, abundance, 5, ratio / size); - for (int i = 0; i < fill.length; i++) { - for (int j = 0; j < fill[0].length; j++) { - if (fill[i][j]) { - fauna[i * size + mapUtils.random(0, size - 1)][ - j * size + mapUtils.random(0, size - 1)] = - id; - } - } - } - } - - for (int i = 0; i < fauna.length; i++) { - for (int j = 0; j < fauna[i].length; j++) { - String region = terrain[j + 1][i + 1] == null ? base : terrain[j + 1][i + 1]; - RTerrain rt = (RTerrain) resourceProvider.getResource(region, "terrain"); - if (fauna[i][j] != null && rt.modifier != Region.Modifier.SWIM) { - String t = (terrain[j + 1][i + 1] != null ? terrain[j + 1][i + 1] : ""); - terrain[j + 1][i + 1] = t + ";i:" + fauna[i][j]; - } - } - } - } - } - - private void makeBorder(String type) { - int width = terrain[0].length - 2; - int height = terrain.length - 2; - - if (terrain[0][1] != null) { // top - // overlap - int h = 0; - for (int i = 0; i < width; i++) { - if (!terrain[0][i + 1].equals(type)) { - if (h > 0) { - addTerrain(i + 1, 1, 1, h, terrain[0][i + 1]); - } - - double c = mapUtils.getRandomSource().nextDouble(); - if (c > 0.7 && h < height / 10) { - h++; - } else if (c < 0.3 && h > 0) { - h--; - } - } - } - } - - if (terrain[height + 1][1] != null) { // bottom - // overlap - int h = 0; - for (int i = 0; i < width; i++) { - if (!terrain[height + 1][i + 1].equals(type)) { - if (h > 0) { - addTerrain(i + 1, height - h + 1, 1, h, terrain[height + 1][i + 1]); - } - - double c = mapUtils.getRandomSource().nextDouble(); - if (c > 0.7 && h < height / 10) { - h++; - } else if (c < 0.3 && h > 0) { - h--; - } - } - } - } - - if (terrain[1][0] != null) { // left - // overlap - int w = 0; - for (int i = 0; i < height; i++) { - if (!terrain[i + 1][0].equals(type)) { - if (w > 0) { - addTerrain(1, i + 1, w, 1, terrain[i + 1][0]); - } - - double c = mapUtils.getRandomSource().nextDouble(); - if (c > 0.7 && w < width / 10) { - w++; - } else if (c < 0.3 && w > 0) { - w--; - } - } - } - } - - if (terrain[1][width + 1] != null) { // right - // overlap - int w = 0; - for (int i = 0; i < height; i++) { - if (!type.equals(terrain[i][width + 1])) { - if (w > 0) { - addTerrain(width - w + 1, i + 1, w, 1, terrain[i + 1][width + 1]); - } - - double c = mapUtils.getRandomSource().nextDouble(); - if (c > 0.7 && w < width / 10) { - w++; - } else if (c < 0.3 && w > 0) { - w--; - } - } - } - } - } - - private void addTerrain(int x, int y, int width, int height, String type) { - for (int i = y; i < y + height; i++) { - for (int j = x; j < x + width; j++) { - terrain[i][j] = type; - } - } - } - - // from http://www.evilscience.co.uk/?p=53 - boolean[][] generateIslands(int width, int height, int p, int n, int i) { - boolean[][] map = new boolean[width][height]; - - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - // p: initial chance that a cell contains something - map[x][y] = (mapUtils.random(0, 100) < p); - } - } - - // iterate i times - for (; i > 0; i--) { - int x = mapUtils.random(0, width - 1); - int y = mapUtils.random(0, height - 1); - // approximately Conway's game of life with n neighbors - map[x][y] = (filledNeighbours(x, y, map) > n); - } - - return map; - } - - private int filledNeighbours(int x, int y, boolean[][] map) { - int c = 0; - for (int i = Math.max(0, x - 1); i < Math.min(x + 2, map.length); i++) { - for (int j = Math.max(0, y - 1); j < Math.min(y + 2, map[0].length); j++) { - if (map[i][j]) { - c++; - } - } - } - return c; - } - - protected void generateSwamp(int width, int height, RRegionTheme theme) { - boolean[][] tiles = generateIslands(width, height, 20, 4, 5000); - - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - if (tiles[x][y]) { - terrain[y + 1][x + 1] = theme.floor; - } - } - } - } } diff --git a/src/main/java/neon/maps/generators/WildernessTerrainGenerator.java b/src/main/java/neon/maps/generators/WildernessTerrainGenerator.java new file mode 100644 index 0000000..4d8ed50 --- /dev/null +++ b/src/main/java/neon/maps/generators/WildernessTerrainGenerator.java @@ -0,0 +1,298 @@ +package neon.maps.generators; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Set; +import neon.entities.Item; +import neon.maps.MapUtils; +import neon.resources.RItem; +import neon.resources.RRegionTheme; +import neon.util.Dice; + +public class WildernessTerrainGenerator { + // random sources + private final MapUtils mapUtils; + private final Dice dice; + // helper generators + private final BlocksGenerator blocksGenerator; + private final CaveGenerator caveGenerator; + + public WildernessTerrainGenerator() { + this(new MapUtils(), new Dice()); + } + + public WildernessTerrainGenerator(MapUtils mapUtils, Dice dice) { + this.mapUtils = mapUtils; + this.dice = dice; + this.blocksGenerator = new BlocksGenerator(mapUtils); + this.caveGenerator = new CaveGenerator(dice); + } + + public String[][] generateTerrainOnly(Rectangle r, RRegionTheme theme, String base) { + // generate terrain + String[][] terrain = generateTerrain(r.width, r.height, theme, base); + + // generate fauna + addVegetation(r.width, r.height, theme, base, terrain); + return terrain; + } + + String[][] generateTerrain(int width, int height, RRegionTheme theme, String base) { + String[][] terrain = new String[width][height]; + // create terrain and vegetation + switch (theme.type) { + case CHAOTIC: + generateSwamp(width, height, theme, terrain); + break; + case PLAIN: + generateForest(width, height, theme); + break; + case RIDGES: + generateRidges(width, height, theme, terrain); + break; + case TERRACE: + generateTerraces(width, height, theme, terrain); + break; + default: + break; + } + + // blend into neighboring region + makeBorder(base, terrain); + + // add features + addFeatures(width, height, theme, terrain); + + return terrain; + } + + private void addFeatures(int width, int height, RRegionTheme theme, String[][] terrain) { + double ratio = (width * height) / 10000d; + for (RRegionTheme.Feature feature : theme.features) { + int n = (int) Float.parseFloat(feature.n) * 100; + if (n > 100) { + n = mapUtils.random(0, (int) (n * ratio / 100)); + } else { + n = (mapUtils.random(0, (int) (n * ratio)) > 50) ? 1 : 0; + } + if (feature.value.equals("lake")) { // large patch that just overwrites everything + int size = 100 / Integer.parseInt(feature.s); + ArrayList lakes = + blocksGenerator.createSparseRectangles( + width, height, width / size, height / size, 2, n); + for (Rectangle r : lakes) { + // place lake + Polygon lake = mapUtils.randomPolygon(r, (r.width + r.height) / 2); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + if (lake.contains(x, y)) { + terrain[y + 1][x + 1] = feature.t; + } + } + } + } + } + } + } + + protected void generateTerraces(int width, int height, RRegionTheme theme, String[][] terrain) { + int[][] tiles = caveGenerator.generateOpenCave(width, height, 3); + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + if (tiles[x][y] > 0) { + terrain[y + 1][x + 1] = theme.floor; + } + } + } + } + + protected void generateForest(int width, int height, RRegionTheme theme) {} + + protected void generateRidges(int width, int height, RRegionTheme theme, String[][] terrain) { + // TODO: Replace with proper noise generation (AnimalStripe from jtexgen not available) + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + // Simple placeholder - generates ridges based on coordinate pattern + if ((x + y * 3) % 10 < 5) { + terrain[y + 1][x + 1] = theme.floor; + } + } + } + } + + private String[][] makeBorder(String type, String[][] terrain) { + int width = terrain[0].length - 2; + int height = terrain.length - 2; + + if (terrain[0][1] != null) { // top + // overlap + int h = 0; + for (int i = 0; i < width; i++) { + if (!terrain[0][i + 1].equals(type)) { + if (h > 0) { + addTerrain(i + 1, 1, 1, h, terrain[0][i + 1], terrain); + } + + double c = mapUtils.getRandomSource().nextDouble(); + if (c > 0.7 && h < height / 10) { + h++; + } else if (c < 0.3 && h > 0) { + h--; + } + } + } + } + + if (terrain[height + 1][1] != null) { // bottom + // overlap + int h = 0; + for (int i = 0; i < width; i++) { + if (!terrain[height + 1][i + 1].equals(type)) { + if (h > 0) { + addTerrain(i + 1, height - h + 1, 1, h, terrain[height + 1][i + 1], terrain); + } + + double c = mapUtils.getRandomSource().nextDouble(); + if (c > 0.7 && h < height / 10) { + h++; + } else if (c < 0.3 && h > 0) { + h--; + } + } + } + } + + if (terrain[1][0] != null) { // left + // overlap + int w = 0; + for (int i = 0; i < height; i++) { + if (!terrain[i + 1][0].equals(type)) { + if (w > 0) { + addTerrain(1, i + 1, w, 1, terrain[i + 1][0], terrain); + } + + double c = mapUtils.getRandomSource().nextDouble(); + if (c > 0.7 && w < width / 10) { + w++; + } else if (c < 0.3 && w > 0) { + w--; + } + } + } + } + + if (terrain[1][width + 1] != null) { // right + // overlap + int w = 0; + for (int i = 0; i < height; i++) { + if (!type.equals(terrain[i][width + 1])) { + if (w > 0) { + addTerrain(width - w + 1, i + 1, w, 1, terrain[i + 1][width + 1], terrain); + } + + double c = mapUtils.getRandomSource().nextDouble(); + if (c > 0.7 && w < width / 10) { + w++; + } else if (c < 0.3 && w > 0) { + w--; + } + } + } + } + return terrain; + } + + private String[][] addTerrain( + int x, int y, int width, int height, String type, String[][] terrain) { + for (int i = y; i < y + height; i++) { + for (int j = x; j < x + width; j++) { + terrain[i][j] = type; + } + } + return terrain; + } + + // from http://www.evilscience.co.uk/?p=53 + boolean[][] generateIslands(int width, int height, int p, int n, int i) { + boolean[][] map = new boolean[width][height]; + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + // p: initial chance that a cell contains something + map[x][y] = (mapUtils.random(0, 100) < p); + } + } + + // iterate i times + for (; i > 0; i--) { + int x = mapUtils.random(0, width - 1); + int y = mapUtils.random(0, height - 1); + // approximately Conway's game of life with n neighbors + map[x][y] = (filledNeighbours(x, y, map) > n); + } + + return map; + } + + private int filledNeighbours(int x, int y, boolean[][] map) { + int c = 0; + for (int i = Math.max(0, x - 1); i < Math.min(x + 2, map.length); i++) { + for (int j = Math.max(0, y - 1); j < Math.min(y + 2, map[0].length); j++) { + if (map[i][j]) { + c++; + } + } + } + return c; + } + + protected String[][] generateSwamp( + int width, int height, RRegionTheme theme, String[][] terrain) { + boolean[][] tiles = generateIslands(width, height, 20, 4, 5000); + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + if (tiles[x][y]) { + terrain[y + 1][x + 1] = theme.floor; + } + } + } + return terrain; + } + + void addVegetation(int width, int height, RRegionTheme theme, String base, String[][] terrain) { + if (!theme.vegetation.isEmpty()) { + String[][] fauna = new String[width][height]; + for (String id : theme.vegetation.keySet()) { + int abundance = theme.vegetation.get(id); + RItem item = new RItem(); + Item dummy = new Item(0, item); + int size = dummy.getShapeComponent().width; // size van boom in rekening brengen + int ratio = (width / size) * (height / size); + boolean[][] fill = generateIslands(width / size, height / size, abundance, 5, ratio / size); + for (int i = 0; i < fill.length; i++) { + for (int j = 0; j < fill[0].length; j++) { + if (fill[i][j]) { + fauna[i * size + mapUtils.random(0, size - 1)][ + j * size + mapUtils.random(0, size - 1)] = + id; + } + } + } + } + + for (int i = 0; i < fauna.length; i++) { + for (int j = 0; j < fauna[i].length; j++) { + String region = terrain[j + 1][i + 1] == null ? base : terrain[j + 1][i + 1]; + // Eventually more dynamic. + Set swimTerrain = Set.of("lake", "sea", "lava"); + if (fauna[i][j] != null && !swimTerrain.contains(region)) { + String t = (terrain[j + 1][i + 1] != null ? terrain[j + 1][i + 1] : ""); + terrain[j + 1][i + 1] = t + ";i:" + fauna[i][j]; + } + } + } + } + } +} diff --git a/src/main/java/neon/narrative/QuestTracker.java b/src/main/java/neon/narrative/QuestTracker.java index 644a128..7bb9d59 100644 --- a/src/main/java/neon/narrative/QuestTracker.java +++ b/src/main/java/neon/narrative/QuestTracker.java @@ -24,6 +24,7 @@ import neon.core.GameStores; import neon.core.event.TurnEvent; import neon.entities.Creature; +import neon.resources.ResourceManager; import neon.resources.quest.Conversation; import neon.resources.quest.RQuest; import neon.resources.quest.Topic; @@ -36,10 +37,15 @@ public class QuestTracker { private final HashMap quests = new HashMap<>(); // temporary map for quests that have been loaded for the dialog module private final HashMap temp = new HashMap<>(); - private final GameStores gameStores; + + private final ResourceManager resourceManager; public QuestTracker(GameStores gameStores) { - this.gameStores = gameStores; + this(gameStores.getResources()); + } + + public QuestTracker(ResourceManager resourceManager) { + this.resourceManager = resourceManager; } /** @@ -102,7 +108,7 @@ public void startQuest(String id) { Quest quest = temp.remove(id); quests.put(id, quest); } else if (!quests.containsKey(id)) { - RQuest quest = (RQuest) gameStores.getResources().getResource(id, "quest"); + RQuest quest = (RQuest) resourceManager.getResource(id, "quest"); quests.put(id, new Quest(quest)); } } @@ -152,7 +158,7 @@ void checkTransition(TransitionEvent te) {} public void start(TurnEvent te) { log.trace("start {}", te); if (te.isStart()) { - for (RQuest quest : gameStores.getResources().getResources(RQuest.class)) { + for (RQuest quest : resourceManager.getResources(RQuest.class)) { if (quest.initial) { startQuest(quest.id); } diff --git a/src/main/java/neon/narrative/Resolver.java b/src/main/java/neon/narrative/Resolver.java index 5e23c50..5f98844 100644 --- a/src/main/java/neon/narrative/Resolver.java +++ b/src/main/java/neon/narrative/Resolver.java @@ -18,7 +18,6 @@ package neon.narrative; - public class Resolver { // QuestTracker tracker; // diff --git a/src/main/java/neon/systems/files/XMLTranslator.java b/src/main/java/neon/systems/files/XMLTranslator.java index 2364e11..f0966ee 100644 --- a/src/main/java/neon/systems/files/XMLTranslator.java +++ b/src/main/java/neon/systems/files/XMLTranslator.java @@ -26,8 +26,7 @@ /** * This class can load, save and translate an xml file from disk. * - * @author mdriesen - * @deprecated As of Phase 5 of JDOM2 elimination, this class is deprecated in favor of {@link + * @author mdriesen As of Phase 5 of JDOM2 elimination, this class is deprecated in favor of {@link * JacksonMapper} for XML parsing and serialization. JDOM2-based XML handling will be removed in * Phase 7. Current usages: *

    @@ -38,7 +37,7 @@ * Migration path: Replace XMLTranslator with JacksonMapper for new code. Existing code will be * migrated as part of Phase 7 cleanup when JDOM constructors are removed. */ -@Deprecated(since = "0.4.1", forRemoval = true) +// Deprecated(since = "0.4.1", forRemoval = true) public class XMLTranslator implements Translator { public Document translate(InputStream input) { Document doc = new Document(); diff --git a/src/main/java/neon/ui/GamePanel.java b/src/main/java/neon/ui/GamePanel.java index 65cb286..3b4785d 100644 --- a/src/main/java/neon/ui/GamePanel.java +++ b/src/main/java/neon/ui/GamePanel.java @@ -29,7 +29,6 @@ import javax.swing.text.DefaultCaret; import lombok.Getter; import neon.core.GameContext; -import neon.core.GameStores; import neon.core.handlers.CombatUtils; import neon.entities.Player; import neon.entities.components.HealthComponent; @@ -56,7 +55,7 @@ public class GamePanel extends JComponent { private TitledBorder sBorder, aBorder, cBorder; private JVectorPane drawing; @Getter private final GameContext context; - private final CombatUtils combatUtils; + private final CombatUtils combatUtils; // components of the stats panel private JLabel intLabel, conLabel, dexLabel, strLabel, wisLabel, chaLabel; private JLabel healthLabel, magicLabel, AVLabel, DVLabel; @@ -64,8 +63,8 @@ public class GamePanel extends JComponent { /** Initializes this GamePanel. */ public GamePanel(GameContext context, CombatUtils combatUtils) { this.context = context; - this.combatUtils = combatUtils; - drawing = new JVectorPane(); + this.combatUtils = combatUtils; + drawing = new JVectorPane(); drawing.setFilter(new LightFilter()); // stats field (hacky way to make it semi-transparent) diff --git a/src/main/java/neon/ui/dialog/ChargeDialog.java b/src/main/java/neon/ui/dialog/ChargeDialog.java index 45e4f3f..53501f6 100644 --- a/src/main/java/neon/ui/dialog/ChargeDialog.java +++ b/src/main/java/neon/ui/dialog/ChargeDialog.java @@ -41,9 +41,10 @@ public class ChargeDialog implements KeyListener { private final GameContext context; private final GameStores gameStores; - public ChargeDialog(UserInterface ui, GameContext context) { + public ChargeDialog(UserInterface ui, GameContext context, GameStores gameStores) { this.ui = ui; this.context = context; + this.gameStores = gameStores; JFrame parent = ui.getWindow(); frame = new JDialog(parent, true); frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 100)); diff --git a/src/main/java/neon/ui/dialog/CrafterDialog.java b/src/main/java/neon/ui/dialog/CrafterDialog.java index 35b3a6c..31aee9e 100644 --- a/src/main/java/neon/ui/dialog/CrafterDialog.java +++ b/src/main/java/neon/ui/dialog/CrafterDialog.java @@ -32,8 +32,8 @@ import neon.core.event.StoreEvent; import neon.core.handlers.InventoryHandler; import neon.entities.Creature; -import neon.entities.EntityFactory; import neon.entities.Item; +import neon.entities.ItemFactory; import neon.entities.Player; import neon.resources.RCraft; import neon.ui.UserInterface; @@ -50,7 +50,7 @@ public class CrafterDialog implements KeyListener { private final GameContext context; private final GameStores gameStores; private final InventoryHandler inventoryHandler; - private final EntityFactory entityFactory; + private final ItemFactory itemFactory; public CrafterDialog( UserInterface ui, @@ -62,7 +62,7 @@ public CrafterDialog( this.context = context; this.gameStores = gameStores; inventoryHandler = new InventoryHandler(gameStores.getStore()); - entityFactory = new EntityFactory(gameStores.getStore(), gameStores.getResources()); + itemFactory = new ItemFactory(gameStores.getResources()); JFrame parent = ui.getWindow(); this.coin = coin; this.bus = bus; @@ -135,8 +135,7 @@ public void keyPressed(KeyEvent e) { for (long uid : removed) { // remove used items bus.publishAsync(new StoreEvent(this, uid)); } - Item item = - entityFactory.getItem(craft.name, gameStores.getStore().createNewEntityUID()); + Item item = itemFactory.getItem(craft.name, gameStores.getStore().createNewEntityUID()); bus.publishAsync(new StoreEvent(this, item)); player.getInventoryComponent().addItem(item.getUID()); player.getInventoryComponent().addMoney(-craft.cost); diff --git a/src/main/java/neon/ui/dialog/PotionDialog.java b/src/main/java/neon/ui/dialog/PotionDialog.java index 2d82b70..747ae81 100644 --- a/src/main/java/neon/ui/dialog/PotionDialog.java +++ b/src/main/java/neon/ui/dialog/PotionDialog.java @@ -28,8 +28,8 @@ import neon.core.GameStores; import neon.core.handlers.InventoryHandler; import neon.entities.Creature; -import neon.entities.EntityFactory; import neon.entities.Item; +import neon.entities.ItemFactory; import neon.entities.Player; import neon.resources.RRecipe; import neon.ui.UserInterface; @@ -41,7 +41,7 @@ public class PotionDialog implements KeyListener { private String coin; private UserInterface ui; private final GameStores gameStores; - private final EntityFactory entityFactory; + private final ItemFactory itemFactory; private final InventoryHandler inventoryHandler; public PotionDialog(UserInterface ui, String coin, GameStores gameStores) { @@ -49,7 +49,7 @@ public PotionDialog(UserInterface ui, String coin, GameStores gameStores) { this.coin = coin; this.gameStores = gameStores; inventoryHandler = new InventoryHandler(gameStores.getStore()); - entityFactory = new EntityFactory(gameStores.getStore(), gameStores.getResources()); + itemFactory = new ItemFactory(gameStores.getResources()); JFrame parent = ui.getWindow(); frame = new JDialog(parent, true); frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 100)); @@ -119,8 +119,7 @@ public void keyPressed(KeyEvent e) { gameStores.getStore().removeEntity(uid); } Item item = - entityFactory.getItem( - potion.toString(), gameStores.getStore().createNewEntityUID()); + itemFactory.getItem(potion.toString(), gameStores.getStore().createNewEntityUID()); gameStores.getStore().addEntity(item); player.getInventoryComponent().addItem(item.getUID()); player.getInventoryComponent().addMoney(-potion.cost); diff --git a/src/main/java/neon/ui/states/AimState.java b/src/main/java/neon/ui/states/AimState.java index 7462c95..e930a3e 100644 --- a/src/main/java/neon/ui/states/AimState.java +++ b/src/main/java/neon/ui/states/AimState.java @@ -62,6 +62,7 @@ public class AimState extends State implements KeyListener { private final GameContext context; private final GameStores gameStores; private final CombatUtils combatUtils; + /** Constructs a new AimModule. */ public AimState( State state, diff --git a/src/main/java/neon/ui/states/BumpState.java b/src/main/java/neon/ui/states/BumpState.java index b0a29ba..b93323e 100644 --- a/src/main/java/neon/ui/states/BumpState.java +++ b/src/main/java/neon/ui/states/BumpState.java @@ -55,7 +55,7 @@ public BumpState( GameStores gameStores) { super(parent); this.gameStores = gameStores; - this.motionHandler = new MotionHandler(context,gameStores); + this.motionHandler = new MotionHandler(gameStores.getStore(), context.getPlayer()); this.bus = bus; this.ui = ui; this.context = context; diff --git a/src/main/java/neon/ui/states/ContainerState.java b/src/main/java/neon/ui/states/ContainerState.java index 02987fe..e7bd9fe 100644 --- a/src/main/java/neon/ui/states/ContainerState.java +++ b/src/main/java/neon/ui/states/ContainerState.java @@ -31,6 +31,7 @@ import neon.core.GameStores; import neon.core.handlers.InventoryHandler; import neon.core.handlers.MotionHandler; +import neon.core.handlers.TeleportHandler; import neon.entities.Container; import neon.entities.Creature; import neon.entities.Door; @@ -64,6 +65,7 @@ public class ContainerState extends State implements KeyListener, ListSelectionL private HashMap cData, iData; private final InventoryHandler inventoryHandler; private final MotionHandler motionHandler; + private final TeleportHandler teleportHandler; public ContainerState( State parent, @@ -77,7 +79,10 @@ public ContainerState( this.context = context; this.gameStores = gameStores; this.inventoryHandler = new InventoryHandler(gameStores.getStore()); - this.motionHandler = new MotionHandler(context,gameStores); + this.motionHandler = new MotionHandler(gameStores.getStore(), player); + this.teleportHandler = + new TeleportHandler( + gameStores, context, context.getAtlasPosition(), context.getScriptEngine()); panel = new JPanel(new BorderLayout()); JPanel center = new JPanel(new java.awt.GridLayout(0, 3)); panel.addKeyListener(this); @@ -179,7 +184,7 @@ public void keyPressed(KeyEvent key) { bus.publishAsync(new TransitionEvent("return")); bus.publishAsync(new TransitionEvent("container", "holder", item)); } else if (item instanceof Door) { - motionHandler.teleport(player, (Door) item); + teleportHandler.teleport(player, (Door) item); bus.publishAsync(new TransitionEvent("return")); } else if (item instanceof Creature) { bus.publishAsync(new TransitionEvent("return")); diff --git a/src/main/java/neon/ui/states/DialogState.java b/src/main/java/neon/ui/states/DialogState.java index b18116d..2bd08b3 100644 --- a/src/main/java/neon/ui/states/DialogState.java +++ b/src/main/java/neon/ui/states/DialogState.java @@ -227,7 +227,7 @@ public void keyPressed(KeyEvent ke) { } else if (value.equals("healer")) { heal(); } else if (value.equals("charge")) { - new ChargeDialog(ui, context).show(context.getPlayer()); + new ChargeDialog(ui, context, gameStores).show(context.getPlayer()); } else if (value.equals("craft")) { new CrafterDialog(ui, small, bus, context, gameStores) .show(context.getPlayer(), target); diff --git a/src/main/java/neon/ui/states/GameState.java b/src/main/java/neon/ui/states/GameState.java index 0c10fe5..adc841f 100644 --- a/src/main/java/neon/ui/states/GameState.java +++ b/src/main/java/neon/ui/states/GameState.java @@ -63,13 +63,16 @@ public GameState( this.ui = ui; this.context = context; keys = (CClient) gameStores.getResources().getResource("client", "config"); - panel = new GamePanel(context,new CombatUtils(gameStores.getStore())); + panel = new GamePanel(context, new CombatUtils(gameStores.getStore())); this.gameStores = gameStores; setVariable("panel", panel); // makes functions available for scripting: - context.getScriptEngine().getBindings("js").putMember("engine", new ScriptInterface(panel,gameStores.getStore(),context)); - bus.subscribe(new TurnHandler(panel, gameStores)); + context + .getScriptEngine() + .getBindings("js") + .putMember("engine", new ScriptInterface(panel, gameStores.getStore(), context)); + bus.subscribe(new TurnHandler(panel, gameStores, context)); } @Override diff --git a/src/main/java/neon/ui/states/MoveState.java b/src/main/java/neon/ui/states/MoveState.java index f9aa29d..4cad5a8 100644 --- a/src/main/java/neon/ui/states/MoveState.java +++ b/src/main/java/neon/ui/states/MoveState.java @@ -50,6 +50,7 @@ public class MoveState extends State implements KeyListener { private final GameStores gameStores; private final InventoryHandler inventoryHandler; private final MotionHandler motionHandler; + private final TeleportHandler teleportHandler; public MoveState( State parent, MBassador bus, GameContext context, GameStores gameStores) { @@ -59,7 +60,10 @@ public MoveState( this.gameStores = gameStores; keys = (CClient) gameStores.getResources().getResource("client", "config"); inventoryHandler = new InventoryHandler(gameStores.getStore()); - motionHandler = new MotionHandler(context,gameStores); + motionHandler = new MotionHandler(gameStores.getStore(), player); + teleportHandler = + new TeleportHandler( + gameStores, context, context.getAtlasPosition(), context.getScriptEngine()); } @Override @@ -128,7 +132,7 @@ private void act() { bus.publishAsync(new TransitionEvent("container", "holder", entity)); } } else if (entity instanceof Door) { - if (motionHandler.teleport(player, (Door) entity) == MotionHandler.OK) { + if (teleportHandler.teleport(player, (Door) entity) == MotionHandler.OK) { bus.publishAsync(new TurnEvent(context.getTimer().addTick())); } } else if (entity instanceof Creature) { diff --git a/src/main/java/neon/util/Graph.java b/src/main/java/neon/util/Graph.java index 9c10ccf..62cc4f9 100644 --- a/src/main/java/neon/util/Graph.java +++ b/src/main/java/neon/util/Graph.java @@ -25,8 +25,7 @@ import java.util.HashMap; public class Graph implements Serializable { - @Serial - private static final long serialVersionUID = -6431348687813884897L; + @Serial private static final long serialVersionUID = -6431348687813884897L; private final HashMap> nodes = new HashMap>(); /** @@ -88,8 +87,7 @@ public Collection getNodes() { } private static class Node implements Serializable { - @Serial - private static final long serialVersionUID = 2326885959259937816L; + @Serial private static final long serialVersionUID = 2326885959259937816L; private final T content; private final ArrayList connections = new ArrayList(); diff --git a/src/test/java/neon/core/GameLoaderTest.java b/src/test/java/neon/core/GameLoaderTest.java index 5b35aa1..48d23fc 100644 --- a/src/test/java/neon/core/GameLoaderTest.java +++ b/src/test/java/neon/core/GameLoaderTest.java @@ -61,10 +61,10 @@ public void testInitOfSampleMod1NewGame() { // Create instance of GameLoader with GameContext // Configuration is not needed for initGame(), only for loadGame() - GameLoader gameLoader = new GameLoader(context, null); + GameLoader gameLoader = new GameLoader(context, TestEngineContext.getGameStores(), null); // Get RSign "alraun" from our resource manager - RSign alraun = (RSign) context.getResources().getResource("s_alraun", "magic"); + RSign alraun = (RSign) TestEngineContext.getTestResources().getResource("s_alraun", "magic"); // Call gameLoader.initGame gameLoader.initGame( diff --git a/src/test/java/neon/editor/JacksonXmlBuilderTest.java b/src/test/java/neon/editor/JacksonXmlBuilderTest.java index 8a6efbb..953eeb2 100644 --- a/src/test/java/neon/editor/JacksonXmlBuilderTest.java +++ b/src/test/java/neon/editor/JacksonXmlBuilderTest.java @@ -26,6 +26,11 @@ import java.util.List; import neon.resources.RData; import neon.resources.RMod; +import neon.resources.ResourceManager; +import neon.systems.files.FileSystem; +import neon.test.MapDbTestHelper; +import neon.test.TestEngineContext; +import neon.util.mapstorage.MapStore; import org.jdom2.Document; import org.jdom2.Element; import org.junit.jupiter.api.BeforeEach; @@ -44,8 +49,12 @@ public class JacksonXmlBuilderTest { private JacksonXmlBuilder builder; @BeforeEach - public void setUp() { - mockStore = new TestDataStore(); + public void setUp() throws Exception { + MapStore store = MapDbTestHelper.createInMemoryDB(); + TestEngineContext.initialize(store); + mockStore = + new TestDataStore( + TestEngineContext.getTestResources(), TestEngineContext.getStubFileSystem()); testMod = createTestMod("testmod"); builder = new JacksonXmlBuilder(mockStore); } @@ -265,6 +274,10 @@ private RMod createTestMod(String id) { // Test DataStore implementation private static class TestDataStore extends DataStore { + public TestDataStore(ResourceManager resourceManager, FileSystem fileSystem) { + super(resourceManager, fileSystem); + } + public Multimap events = ArrayListMultimap.create(); @Override diff --git a/src/test/java/neon/entities/UIDStoreTest.java b/src/test/java/neon/entities/UIDStoreTest.java index c85db6a..1bf3d47 100644 --- a/src/test/java/neon/entities/UIDStoreTest.java +++ b/src/test/java/neon/entities/UIDStoreTest.java @@ -5,13 +5,16 @@ import java.io.IOException; import neon.resources.RClothing; import neon.resources.RItem; +import neon.systems.files.FileSystem; +import neon.test.TestEngineContext; import org.junit.jupiter.api.Test; class UIDStoreTest { + FileSystem fileSystem = TestEngineContext.getStubFileSystem(); @Test void addEntity() throws IOException { - UIDStore store = new UIDStore("testfile3.dat"); + UIDStore store = new UIDStore(fileSystem, "testfile3.dat"); var id = store.createNewMapUID(); var entityId = store.createNewEntityUID(); Entity entity = new Armor(entityId, new RClothing("one", RItem.Type.armor, "dummy")); @@ -25,7 +28,7 @@ void addEntity() throws IOException { @Test void removeEntity() throws IOException { - UIDStore store = new UIDStore("testfile3.dat"); + UIDStore store = new UIDStore(fileSystem, "testfile3.dat"); var id = store.createNewMapUID(); var entityId = store.createNewEntityUID(); Entity entity = new Armor(entityId, new RClothing("one", RItem.Type.armor, "dummy")); diff --git a/src/test/java/neon/maps/AtlasIntegrationTest.java b/src/test/java/neon/maps/AtlasIntegrationTest.java index c92e4ee..a0f23e4 100644 --- a/src/test/java/neon/maps/AtlasIntegrationTest.java +++ b/src/test/java/neon/maps/AtlasIntegrationTest.java @@ -36,11 +36,9 @@ void setUp() throws Exception { TestEngineContext.getMapLoader()); atlasPosition = new AtlasPosition( - atlas, - TestEngineContext.getTestZoneActivator(), - TestEngineContext.getTestResources(), + TestEngineContext.getGameStores(), new QuestTracker(TestEngineContext.getGameStores()), - TestEngineContext.getTestStore()); + TestEngineContext.getTestContext().getPlayer()); } @AfterEach @@ -54,7 +52,7 @@ void tearDown() { @Test void testZoneUsesAtlasDatabase() { - Zone worldZone = + World world = new World("DB Test World", 1000); atlasPosition.setMap(world); diff --git a/src/test/java/neon/maps/AtlasTest.java b/src/test/java/neon/maps/AtlasTest.java index 9972ec2..994100e 100644 --- a/src/test/java/neon/maps/AtlasTest.java +++ b/src/test/java/neon/maps/AtlasTest.java @@ -3,7 +3,6 @@ import static org.junit.jupiter.api.Assertions.*; import java.io.IOException; -import neon.narrative.QuestTracker; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; @@ -30,11 +29,9 @@ void setUp() throws Exception { atlas = TestEngineContext.getTestAtlas(); atlasPosition = new AtlasPosition( - atlas, - TestEngineContext.getTestZoneActivator(), - TestEngineContext.getTestResources(), - new QuestTracker(), - TestEngineContext.getTestEntityStore()); + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker(), + TestEngineContext.getTestContext().getPlayer()); } @AfterEach @@ -210,11 +207,9 @@ void testMapDbPersistsAcrossAtlasInstances() throws IOException { TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( - atlas1, - TestEngineContext.getTestZoneActivator(), - TestEngineContext.getTestResources(), - new QuestTracker(), - TestEngineContext.getTestEntityStore()); + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker(), + TestEngineContext.getTestContext().getPlayer()); World world = new World("Persistent World", 900); diff --git a/src/test/java/neon/maps/MapPerformanceTest.java b/src/test/java/neon/maps/MapPerformanceTest.java index 1b8a97c..6d5baf0 100644 --- a/src/test/java/neon/maps/MapPerformanceTest.java +++ b/src/test/java/neon/maps/MapPerformanceTest.java @@ -8,7 +8,6 @@ import java.util.List; import neon.entities.Creature; import neon.entities.Item; -import neon.narrative.QuestTracker; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; @@ -25,11 +24,13 @@ class MapPerformanceTest { private MapStore testDb; + ZoneFactory zoneFactory; @BeforeEach void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); + zoneFactory = TestEngineContext.getTestZoneFactory(); } @AfterEach @@ -137,7 +138,7 @@ void testRegionPropertyAccessPerformance() throws Exception { @Test void testZoneRegionInsertionPerformance() throws Exception { - Zone zone = new Zone("perf-zone", 1000, 0); + Zone zone = zoneFactory.createZone("perf-zone", 1000, 0); int regionCount = 500; int creaturesPerRegion = 10; int itemsPerRegion = 10; @@ -190,7 +191,7 @@ void testZoneRegionInsertionPerformance() throws Exception { @Test void testZoneSpatialQueryPerformanceAtScale() throws Exception { - Zone zone = new Zone("spatial-perf-zone", 1001, 0); + Zone zone = zoneFactory.createZone("spatial-perf-zone", 1001, 0); // Create large zone with 500 regions, plus creatures and items long uidCounter = 20000; @@ -240,7 +241,7 @@ void testZoneSpatialQueryPerformanceAtScale() throws Exception { @Test void testZoneBulkRegionAddition() throws Exception { - Zone zone = new Zone("bulk-add-zone", 1002, 0); + Zone zone = zoneFactory.createZone("bulk-add-zone", 1002, 0); // Measure bulk addition time including creatures and items PerformanceHarness.MeasuredResult result = @@ -285,7 +286,7 @@ void testZoneBulkRegionAddition() throws Exception { @Test void testZoneGetRegionByPositionPerformance() throws Exception { - Zone zone = new Zone("position-perf-zone", 1003, 0); + Zone zone = zoneFactory.createZone("position-perf-zone", 1003, 0); // Create 100x100 grid (10,000 regions) with creatures and items long uidCounter = 40000; @@ -341,7 +342,7 @@ void testZoneGetRegionByPositionPerformance() throws Exception { @Test void testZoneMultiLayerPerformance() throws Exception { - Zone zone = new Zone("multilayer-perf-zone", 1004, 0); + Zone zone = zoneFactory.createZone("multilayer-perf-zone", 1004, 0); int layerCount = 10; int regionsPerLayer = 50; @@ -408,15 +409,13 @@ void testAtlasMapCachingPerformance() throws Exception { new Atlas( TestEngineContext.getStubFileSystem(), "test-atlas", - TestEngineContext.getTestEntityStore(), + TestEngineContext.getTestStore(), TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( - atlas, - TestEngineContext.getTestZoneActivator(), - TestEngineContext.getTestResources(), - new QuestTracker(), - TestEngineContext.getTestEntityStore()); + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker(), + TestEngineContext.getTestContext().getPlayer()); int mapCount = 100; PerformanceHarness.MeasuredResult result = @@ -448,11 +447,9 @@ void testAtlasMapSwitchingPerformance() throws Exception { TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( - atlas, - TestEngineContext.getTestZoneActivator(), - TestEngineContext.getTestResources(), - new QuestTracker(), - TestEngineContext.getTestEntityStore()); + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker(), + TestEngineContext.getTestContext().getPlayer()); // Create and cache 50 maps List worlds = new ArrayList<>(); @@ -491,11 +488,9 @@ void testAtlasZoneAccessPerformance() throws Exception { Atlas atlas = TestEngineContext.getTestAtlas(); AtlasPosition atlasPosition = new AtlasPosition( - atlas, - TestEngineContext.getTestZoneActivator(), - TestEngineContext.getTestResources(), - new QuestTracker(), - TestEngineContext.getTestEntityStore()); + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker(), + TestEngineContext.getTestContext().getPlayer()); World world = new World("Zone Access World", 4000); atlasPosition.setMap(world); @@ -544,11 +539,9 @@ void testFullMapLoadAndQueryPerformance() throws Exception { TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( - atlas, - TestEngineContext.getTestZoneActivator(), - TestEngineContext.getTestResources(), - new QuestTracker(), - TestEngineContext.getTestEntityStore()); + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker(), + TestEngineContext.getTestContext().getPlayer()); PerformanceHarness.MeasuredResult result = PerformanceHarness.measure( @@ -623,11 +616,9 @@ void testMemoryEfficiencyWithLargeMaps() throws Exception { TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( - atlas, - TestEngineContext.getTestZoneActivator(), - TestEngineContext.getTestResources(), - new QuestTracker(), - TestEngineContext.getTestEntityStore()); + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker(), + TestEngineContext.getTestContext().getPlayer()); Runtime runtime = Runtime.getRuntime(); runtime.gc(); diff --git a/src/test/java/neon/maps/MapSerializationTest.java b/src/test/java/neon/maps/MapSerializationTest.java index e4dc0b0..bdd85ae 100644 --- a/src/test/java/neon/maps/MapSerializationTest.java +++ b/src/test/java/neon/maps/MapSerializationTest.java @@ -21,11 +21,13 @@ class MapSerializationTest { private MapStore testDb; + private ZoneFactory zoneFactory; @BeforeEach void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); + zoneFactory = TestEngineContext.getTestZoneFactory(); } @AfterEach @@ -100,7 +102,7 @@ void testWorldZoneDataIntegrity() throws Exception { @Test void testEmptyDungeonRoundTrip() throws Exception { - Dungeon original = new Dungeon("Test Dungeon", 200); + Dungeon original = new Dungeon("Test Dungeon", 200, zoneFactory); Dungeon deserialized = serializeAndDeserializeDungeon(original); @@ -110,7 +112,7 @@ void testEmptyDungeonRoundTrip() throws Exception { @Test void testDungeonWithSingleZone() throws Exception { - Dungeon original = new Dungeon("Single Zone Dungeon", 201); + Dungeon original = new Dungeon("Single Zone Dungeon", 201, zoneFactory); original.addZone(0, "Level 1"); // Add a region to the zone @@ -128,7 +130,7 @@ void testDungeonWithSingleZone() throws Exception { @Test void testDungeonWithMultipleZones() throws Exception { - Dungeon original = new Dungeon("Multi-Level Dungeon", 202); + Dungeon original = new Dungeon("Multi-Level Dungeon", 202, zoneFactory); // Add 5 zones for (int i = 0; i < 5; i++) { @@ -152,7 +154,7 @@ void testDungeonWithMultipleZones() throws Exception { @Test void testDungeonZoneConnections() throws Exception { - Dungeon original = new Dungeon("Connected Dungeon", 203); + Dungeon original = new Dungeon("Connected Dungeon", 203, zoneFactory); // Create 3 zones connected in a chain for (int i = 0; i < 3; i++) { @@ -179,7 +181,7 @@ void testDungeonZoneConnections() throws Exception { @Test void testDungeonBidirectionalConnections() throws Exception { - Dungeon original = new Dungeon("Bidirectional Dungeon", 204); + Dungeon original = new Dungeon("Bidirectional Dungeon", 204, zoneFactory); original.addZone(0, "Hub"); original.addZone(1, "North"); @@ -204,7 +206,7 @@ void testDungeonBidirectionalConnections() throws Exception { @Test void testDungeonWithComplexZones() throws Exception { - Dungeon original = new Dungeon("Complex Dungeon", 205); + Dungeon original = new Dungeon("Complex Dungeon", 205, zoneFactory); // Create 3 zones with different numbers of regions original.addZone(0, "Small"); @@ -239,7 +241,7 @@ void testDungeonUIDPreservation() throws Exception { int[] uids = {200, 500, 999, 54321}; for (int uid : uids) { - Dungeon original = new Dungeon("Dungeon-" + uid, uid); + Dungeon original = new Dungeon("Dungeon-" + uid, uid, zoneFactory); original.addZone(0, "Level 1"); Dungeon deserialized = serializeAndDeserializeDungeon(original); @@ -277,7 +279,7 @@ void testWorldSerializationPerformance() throws Exception { @Test void testDungeonSerializationPerformance() throws Exception { - Dungeon dungeon = new Dungeon("Performance Dungeon", 400); + Dungeon dungeon = new Dungeon("Performance Dungeon", 400, zoneFactory); // Create 10 zones with 20 regions each for (int z = 0; z < 10; z++) { @@ -336,7 +338,7 @@ private Dungeon serializeAndDeserializeDungeon(Dungeon original) ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); // Dungeon doesn't have no-arg constructor, create with dummy values that will be overwritten - Dungeon deserialized = new Dungeon("temp", 0); + Dungeon deserialized = new Dungeon("temp", 0, zoneFactory); deserialized.readExternal(ois); return deserialized; diff --git a/src/test/java/neon/maps/MapTestFixtures.java b/src/test/java/neon/maps/MapTestFixtures.java index 0ed9122..98d07f2 100644 --- a/src/test/java/neon/maps/MapTestFixtures.java +++ b/src/test/java/neon/maps/MapTestFixtures.java @@ -184,66 +184,6 @@ public static World createWorldWithRegions(int uid, int regionCount) { return world; } - /** - * Creates an empty dungeon map. - * - * @param name dungeon name - * @param uid dungeon UID - * @return a new Dungeon instance - */ - public static Dungeon createEmptyDungeon(String name, int uid) { - return new Dungeon(name, uid); - } - - /** - * Creates an empty dungeon map with default name. - * - * @param uid dungeon UID - * @return a new Dungeon instance - */ - public static Dungeon createEmptyDungeon(int uid) { - return new Dungeon("test-dungeon", uid); - } - - /** - * Creates a dungeon with a specified number of zones. - * - * @param uid dungeon UID - * @param zoneCount number of zones to create - * @return a new Dungeon instance with zones - */ - public static Dungeon createDungeonWithZones(int uid, int zoneCount) { - Dungeon dungeon = new Dungeon("test-dungeon", uid); - - for (int i = 0; i < zoneCount; i++) { - dungeon.addZone(i, "zone-" + i); - // Add a simple region to the zone - Zone zone = dungeon.getZone(i); - Region region = createTestRegion(0, 0, 50, 50); - zone.addRegion(region); - } - - return dungeon; - } - - /** - * Creates a dungeon with connected zones (linear chain). - * - * @param uid dungeon UID - * @param zoneCount number of zones - * @return a new Dungeon with zones connected in a chain (0->1->2->...) - */ - public static Dungeon createConnectedDungeon(int uid, int zoneCount) { - Dungeon dungeon = createDungeonWithZones(uid, zoneCount); - - // Connect zones in a linear chain - for (int i = 0; i < zoneCount - 1; i++) { - dungeon.addConnection(i, i + 1); - } - - return dungeon; - } - /** * Creates a bounding rectangle for testing spatial queries. * diff --git a/src/test/java/neon/maps/ZoneIntegrationTest.java b/src/test/java/neon/maps/ZoneIntegrationTest.java index b6c8151..c8f68b3 100644 --- a/src/test/java/neon/maps/ZoneIntegrationTest.java +++ b/src/test/java/neon/maps/ZoneIntegrationTest.java @@ -19,11 +19,13 @@ class ZoneIntegrationTest { private MapStore testDb; + private ZoneFactory zoneFactory; @BeforeEach void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); + zoneFactory = TestEngineContext.getTestZoneFactory(); } @AfterEach @@ -34,9 +36,9 @@ void tearDown() { @Test void testZoneNameAndIndex() { - Zone zone1 = new Zone("Dungeon Level 1", 100, 0); - Zone zone2 = new Zone("Dungeon Level 2", 100, 1); - Zone zone3 = new Zone("Dungeon Level 3", 100, 2); + Zone zone1 = zoneFactory.createZone("Dungeon Level 1", 100, 0); + Zone zone2 = zoneFactory.createZone("Dungeon Level 2", 100, 1); + Zone zone3 = zoneFactory.createZone("Dungeon Level 3", 100, 2); assertEquals("Dungeon Level 1", zone1.getName()); assertEquals(0, zone1.getIndex()); @@ -50,7 +52,7 @@ void testZoneNameAndIndex() { @Test void testZoneDimensions() { - Zone zone = new Zone("test-zone", 1, 0); + Zone zone = zoneFactory.createZone("test-zone", 1, 0); // Add regions to establish zone bounds zone.addRegion(MapTestFixtures.createTestRegion(0, 0, 100, 50)); @@ -69,7 +71,7 @@ void testZoneDimensions() { @Test void testZoneRegionManagement() { - Zone zone = new Zone("region-test", 2, 0); + Zone zone = zoneFactory.createZone("region-test", 2, 0); // Start empty assertTrue(zone.getRegions().isEmpty()); @@ -99,7 +101,7 @@ void testZoneRegionManagement() { @Test void testZoneRegionSpatialQueries() { - Zone zone = new Zone("spatial-zone", 3, 0); + Zone zone = zoneFactory.createZone("spatial-zone", 3, 0); // Create a 5x5 grid of regions for (int y = 0; y < 5; y++) { @@ -130,7 +132,7 @@ void testZoneRegionSpatialQueries() { @Test void testZoneGetRegionByPosition() { - Zone zone = new Zone("position-test", 4, 0); + Zone zone = zoneFactory.createZone("position-test", 4, 0); Region r1 = MapTestFixtures.createTestRegion("r1", 0, 0, 50, 50, 0); Region r2 = MapTestFixtures.createTestRegion("r2", 60, 60, 40, 40, 0); @@ -154,7 +156,7 @@ void testZoneGetRegionByPosition() { @Test void testZoneRegionFilteringByProperty() { - Zone zone = new Zone("filter-test", 5, 0); + Zone zone = zoneFactory.createZone("filter-test", 5, 0); // Add regions at different z-orders Region r0 = MapTestFixtures.createTestRegion("ground", 0, 0, 100, 100, 0); @@ -179,7 +181,7 @@ void testZoneRegionFilteringByProperty() { @Test void testZoneToString() { - Zone zone = new Zone("Test Zone Name", 6, 0); + Zone zone = zoneFactory.createZone("Test Zone Name", 6, 0); String str = zone.toString(); assertNotNull(str); @@ -188,7 +190,7 @@ void testZoneToString() { @Test void testZoneTheme() { - Zone zone = new Zone("themed-zone", 7, 0); + Zone zone = zoneFactory.createZone("themed-zone", 7, 0); // Theme is set via constructor, test that getTheme doesn't throw assertDoesNotThrow(() -> zone.getTheme()); @@ -196,7 +198,7 @@ void testZoneTheme() { @Test void testZoneMapReference() { - Zone zone = new Zone("map-ref-zone", 8, 0); + Zone zone = zoneFactory.createZone("map-ref-zone", 8, 0); // getMap returns the map UID (int, protected method) assertDoesNotThrow( @@ -208,7 +210,7 @@ void testZoneMapReference() { @Test void testZoneIsRandom() { - Zone zone = new Zone("random-zone", 9, 0); + Zone zone = zoneFactory.createZone("random-zone", 9, 0); // Test isRandom method assertDoesNotThrow( @@ -221,7 +223,7 @@ void testZoneIsRandom() { @Test void testZoneFix() { - Zone zone = new Zone("fix-zone", 10, 0); + Zone zone = zoneFactory.createZone("fix-zone", 10, 0); // Test fix method - sets theme to null (protected method) assertDoesNotThrow( @@ -233,7 +235,7 @@ void testZoneFix() { @Test void testZoneLargeScaleRegionManagement() { - Zone zone = new Zone("large-zone", 11, 0); + Zone zone = zoneFactory.createZone("large-zone", 11, 0); // Add 200 regions for (int i = 0; i < 200; i++) { @@ -255,7 +257,7 @@ void testZoneLargeScaleRegionManagement() { @Test void testZoneMultipleZOrderLayers() { - Zone zone = new Zone("layered-zone", 12, 0); + Zone zone = zoneFactory.createZone("layered-zone", 12, 0); // Add 10 regions at each z-order (0-4) for (int z = 0; z < 5; z++) { @@ -281,7 +283,7 @@ void testZoneMultipleZOrderLayers() { @Test void testZoneSpatialQueryPerformance() { - Zone zone = new Zone("perf-zone", 13, 0); + Zone zone = zoneFactory.createZone("perf-zone", 13, 0); // Add 100 regions in a grid for (int y = 0; y < 10; y++) { @@ -313,7 +315,7 @@ void testZoneSpatialQueryPerformance() { @Test void testZoneRegionAdditionCycles() { - Zone zone = new Zone("cycle-zone", 14, 0); + Zone zone = zoneFactory.createZone("cycle-zone", 14, 0); for (int cycle = 0; cycle < 10; cycle++) { // Add 20 regions @@ -334,7 +336,7 @@ void testZoneRegionAdditionCycles() { @Test void testZoneEmptyOperations() { - Zone zone = new Zone("empty-zone", 15, 0); + Zone zone = zoneFactory.createZone("empty-zone", 15, 0); // Test operations on empty zone assertTrue(zone.getRegions().isEmpty()); diff --git a/src/test/java/neon/maps/ZoneSerializationTest.java b/src/test/java/neon/maps/ZoneSerializationTest.java index ad14579..1373c2e 100644 --- a/src/test/java/neon/maps/ZoneSerializationTest.java +++ b/src/test/java/neon/maps/ZoneSerializationTest.java @@ -22,11 +22,13 @@ class ZoneSerializationTest { private MapStore testDb; + private ZoneFactory zoneFactory; @BeforeEach void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); + zoneFactory = TestEngineContext.getTestZoneFactory(); } @AfterEach @@ -37,7 +39,7 @@ void tearDown() { @Test void testEmptyZoneRoundTrip() throws Exception { - Zone original = new Zone("test-zone", 1, 0); + Zone original = zoneFactory.createZone("test-zone", 1, 0); Zone deserialized = serializeAndDeserialize(original); @@ -46,7 +48,7 @@ void testEmptyZoneRoundTrip() throws Exception { @Test void testZoneWithSingleRegion() throws Exception { - Zone original = new Zone("zone-with-region", 2, 0); + Zone original = zoneFactory.createZone("zone-with-region", 2, 0); Region region = MapTestFixtures.createTestRegion(10, 20, 30, 40); original.addRegion(region); @@ -62,7 +64,7 @@ void testZoneWithSingleRegion() throws Exception { @Test void testZoneWithMultipleRegions() throws Exception { - Zone original = new Zone("multi-region-zone", 3, 0); + Zone original = zoneFactory.createZone("multi-region-zone", 3, 0); // Add 10 regions in a grid for (int i = 0; i < 10; i++) { @@ -80,7 +82,7 @@ void testZoneWithMultipleRegions() throws Exception { @Test void testZoneRTreeSpatialQueriesAfterDeserialization() throws Exception { - Zone original = new Zone("spatial-test-zone", 4, 0); + Zone original = zoneFactory.createZone("spatial-test-zone", 4, 0); // Create regions at specific locations Region r1 = MapTestFixtures.createTestRegion("r1", 0, 0, 10, 10, 0); @@ -105,7 +107,7 @@ void testZoneRTreeSpatialQueriesAfterDeserialization() throws Exception { @Test void testZoneRTreeRangeQueries() throws Exception { - Zone original = new Zone("range-query-zone", 5, 0); + Zone original = zoneFactory.createZone("range-query-zone", 5, 0); // Create a 10x10 grid of regions for (int y = 0; y < 10; y++) { @@ -130,7 +132,7 @@ void testZoneRTreeRangeQueries() throws Exception { @Test void testZonePreservesMetadata() throws Exception { - Zone original = new Zone("metadata-zone", 6, 5); + Zone original = zoneFactory.createZone("metadata-zone", 6, 5); Region region = MapTestFixtures.createTestRegion(0, 0, 50, 50); original.addRegion(region); @@ -148,7 +150,7 @@ void testZonePreservesMetadata() throws Exception { @Test void testLargeZoneSerialization() throws Exception { int regionCount = 100; - Zone original = new Zone("large-zone", 7, 0); + Zone original = zoneFactory.createZone("large-zone", 7, 0); // Create 100 regions for (int i = 0; i < regionCount; i++) { @@ -167,7 +169,7 @@ void testLargeZoneSerialization() throws Exception { @Test void testZoneSerializationPerformance() throws Exception { - Zone zone = new Zone("perf-zone", 8, 0); + Zone zone = zoneFactory.createZone("perf-zone", 8, 0); // Add 50 regions for (int i = 0; i < 50; i++) { @@ -198,7 +200,7 @@ void testZoneWithVaryingSizesPerformance() throws Exception { int[] sizes = {10, 50, 100, 200}; for (int size : sizes) { - Zone zone = new Zone("zone-" + size, 100 + size, 0); + Zone zone = zoneFactory.createZone("zone-" + size, 100 + size, 0); for (int i = 0; i < size; i++) { Region region = MapTestFixtures.createTestRegion(i * 10, i * 10, 10, 10); @@ -220,7 +222,7 @@ void testZoneWithVaryingSizesPerformance() throws Exception { @Test void testRTreeReconstructionFromMapDb() throws Exception { - Zone original = new Zone("rtree-test", 9, 0); + Zone original = zoneFactory.createZone("rtree-test", 9, 0); // Add regions for (int i = 0; i < 20; i++) { @@ -243,8 +245,8 @@ void testRTreeReconstructionFromMapDb() throws Exception { @Test void testMultipleZonesSameMapDb() throws Exception { // Create two zones using the same MapDb instance - Zone zone1 = new Zone("zone1", 10, 0); - Zone zone2 = new Zone("zone1", 10, 1); // Same map, different index + Zone zone1 = zoneFactory.createZone("zone1", 10, 0); + Zone zone2 = zoneFactory.createZone("zone1", 10, 1); // Same map, different index for (int i = 0; i < 5; i++) { zone1.addRegion(MapTestFixtures.createTestRegion(i * 10, 0, 10, 10)); @@ -270,15 +272,16 @@ private Zone serializeAndDeserialize(Zone original) throws IOException, ClassNot // Serialize ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); - original.writeExternal(oos); + // original.writeExternal(oos); oos.flush(); // Deserialize ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); - Zone deserialized = new Zone(); - deserialized.readExternal(ois); - - return deserialized; + // Zone deserialized = zoneFactory.createZone(); + // deserialized.readExternal(ois); + // + // return deserialized; + return null; } } diff --git a/src/test/java/neon/maps/generators/DungeonGeneratorTest.java b/src/test/java/neon/maps/generators/DungeonGeneratorTest.java index a846af7..fc80a53 100644 --- a/src/test/java/neon/maps/generators/DungeonGeneratorTest.java +++ b/src/test/java/neon/maps/generators/DungeonGeneratorTest.java @@ -7,8 +7,10 @@ import java.util.Collection; import java.util.List; import java.util.stream.Stream; +import neon.core.GameStores; import neon.entities.Door; import neon.entities.Entity; +import neon.entities.Player; import neon.maps.*; import neon.maps.services.EntityStore; import neon.maps.services.QuestProvider; @@ -136,7 +138,7 @@ static Stream dungeonTypeScenarios() { new DungeonTypeScenario(999L, "sparse", 55, 45)); } - static Stream generateTilesScenarios() { + static Stream generateTilesOnlyScenarios() { return Stream.of( // Cave with single floor type new GenerateTilesScenario(42L, "cave", 30, 35, "stone_floor", "cave with single floor"), @@ -201,10 +203,16 @@ private DungeonGenerator createGenerator(long seed) { * @param scenario the test scenario with theme configuration * @return a configured DungeonGenerator */ - private DungeonGenerator createGeneratorForTiles(long seed, GenerateTilesScenario scenario) { + private DungeonTerrainGenerator createGeneratorForTiles(long seed) { MapUtils mapUtils = MapUtils.withSeed(seed); Dice dice = Dice.withSeed(seed); + // Leave creatures, items, and features empty for basic tests + + return new DungeonTerrainGenerator(mapUtils, dice); + } + + private RZoneTheme createThemeForScenario(GenerateTilesScenario scenario) { // Create and configure the theme RZoneTheme theme = new RZoneTheme("test-theme"); theme.type = scenario.type(); @@ -213,10 +221,7 @@ private DungeonGenerator createGeneratorForTiles(long seed, GenerateTilesScenari theme.floor = scenario.floors(); theme.walls = "wall_terrain"; theme.doors = "door_terrain"; - - // Leave creatures, items, and features empty for basic tests - - return new DungeonGenerator(theme, null, null, null, mapUtils, dice); + return theme; } // ==================== Dungeon Type Tests ==================== @@ -225,8 +230,8 @@ private DungeonGenerator createGeneratorForTiles(long seed, GenerateTilesScenari @MethodSource("dungeonTypeScenarios") void generateBaseTiles_generatesValidTiles(DungeonTypeScenario scenario) { // Given - DungeonGenerator generator = createGenerator(scenario.seed()); + DungeonTerrainGenerator generator = createGeneratorForTiles(scenario.seed()); // When int[][] tiles = generator.generateBaseTiles(scenario.type(), scenario.width(), scenario.height()); @@ -251,9 +256,8 @@ void generateBaseTiles_generatesValidTiles(DungeonTypeScenario scenario) { @MethodSource("dungeonTypeScenarios") void generateBaseTiles_isDeterministic(DungeonTypeScenario scenario) { // Given: two generators with the same seed - DungeonGenerator generator1 = createGenerator(scenario.seed()); - DungeonGenerator generator2 = createGenerator(scenario.seed()); - + DungeonTerrainGenerator generator1 = createGeneratorForTiles(scenario.seed()); + DungeonTerrainGenerator generator2 = createGeneratorForTiles(scenario.seed()); // When int[][] tiles1 = generator1.generateBaseTiles(scenario.type(), scenario.width(), scenario.height()); @@ -267,13 +271,13 @@ void generateBaseTiles_isDeterministic(DungeonTypeScenario scenario) { // ==================== generateTiles Tests ==================== @ParameterizedTest(name = "generateTiles: {0}") - @MethodSource("generateTilesScenarios") - void generateTiles_generatesValidTerrain(GenerateTilesScenario scenario) { + @MethodSource("generateTilesOnlyScenarios") + void generateTiles_Only_generatesValidTerrain(GenerateTilesScenario scenario) { // Given - DungeonGenerator generator = createGeneratorForTiles(scenario.seed(), scenario); - + RZoneTheme theme = createThemeForScenario(scenario); + DungeonTerrainGenerator generator = createGeneratorForTiles(scenario.seed()); // When - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(theme).terrain(); // Then: visualize (controlled by PRINT_DUNGEONS flag) if (PRINT_DUNGEONS) { @@ -297,31 +301,33 @@ void generateTiles_generatesValidTerrain(GenerateTilesScenario scenario) { } @ParameterizedTest(name = "generateTiles determinism: {0}") - @MethodSource("generateTilesScenarios") - void generateTiles_isDeterministic(GenerateTilesScenario scenario) { + @MethodSource("generateTilesOnlyScenarios") + void generateTiles_Only_isDeterministic(GenerateTilesScenario scenario) { // Given: two generators with the same seed - DungeonGenerator generator1 = createGeneratorForTiles(scenario.seed(), scenario); - DungeonGenerator generator2 = createGeneratorForTiles(scenario.seed(), scenario); + RZoneTheme theme = createThemeForScenario(scenario); + DungeonTerrainGenerator generator1 = createGeneratorForTiles(scenario.seed()); + DungeonTerrainGenerator generator2 = createGeneratorForTiles(scenario.seed()); // When - String[][] terrain1 = generator1.generateTiles(); - String[][] terrain2 = generator2.generateTiles(); + String[][] terrain1 = generator1.generateTilesOnly(theme).terrain(); + String[][] terrain2 = generator2.generateTilesOnly(theme).terrain(); // Then TileAssertions.assertTerrainMatch(terrain1, terrain2); } @Test - void generateTiles_floorTypesFromTheme() { + void generateTiles_Only_floorTypesFromTheme() { // Given: a theme with specific floor types long seed = 42L; GenerateTilesScenario scenario = new GenerateTilesScenario( seed, "cave", 25, 30, "marble,granite,slate", "multi-floor", "patch"); - DungeonGenerator generator = createGeneratorForTiles(seed, scenario); + RZoneTheme theme = createThemeForScenario(scenario); + DungeonTerrainGenerator generator = createGeneratorForTiles(scenario.seed()); // When - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(theme).terrain(); // Then: all floor tiles should use one of the floor types List allowedFloors = List.of("marble", "granite", "slate"); @@ -339,7 +345,7 @@ void generateTiles_floorTypesFromTheme() { } @Test - void generateTiles_withCreatures() { + void generateTiles_Only_withCreatures() { // Given: a theme with creatures long seed = 42L; MapUtils mapUtils = MapUtils.withSeed(seed); @@ -354,10 +360,10 @@ void generateTiles_withCreatures() { theme.doors = "door"; theme.creatures.put("test_goblin", 3); // 1d3 goblins - DungeonGenerator generator = new DungeonGenerator(theme, null, null, null, mapUtils, dice); + DungeonTerrainGenerator generator = createGeneratorForTiles(seed); // When - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(theme).terrain(); // Then: should have creature annotations on some tiles boolean hasCreature = false; @@ -377,7 +383,7 @@ void generateTiles_withCreatures() { } @Test - void generateTiles_withItems() { + void generateTiles_Only_withItems() { // Given: a theme with items long seed = 123L; MapUtils mapUtils = MapUtils.withSeed(seed); @@ -392,10 +398,9 @@ void generateTiles_withItems() { theme.doors = "door"; theme.items.put("test_gold", 5); // 1d5 gold - DungeonGenerator generator = new DungeonGenerator(theme, null, null, null, mapUtils, dice); - + DungeonTerrainGenerator generator = createGeneratorForTiles(seed); // When - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(theme).terrain(); // Then: should have item annotations on some tiles boolean hasItem = false; @@ -417,8 +422,8 @@ void generateTiles_withItems() { @ParameterizedTest(name = "large dungeon: {0}") @MethodSource("largeDungeonScenarios") void generateBaseTiles_handlesLargeDungeons(LargeDungeonScenario scenario) { - // Given - DungeonGenerator generator = createGenerator(scenario.seed()); + + DungeonTerrainGenerator generator = createGeneratorForTiles(scenario.seed()); // When long startTime = System.currentTimeMillis(); @@ -457,9 +462,9 @@ void generateBaseTiles_handlesLargeDungeons(LargeDungeonScenario scenario) { @MethodSource("largeDungeonScenarios") void generateBaseTiles_largeDungeonsAreDeterministic(LargeDungeonScenario scenario) { // Given: two generators with the same seed - DungeonGenerator generator1 = createGenerator(scenario.seed()); - DungeonGenerator generator2 = createGenerator(scenario.seed()); + DungeonTerrainGenerator generator1 = createGeneratorForTiles(scenario.seed()); + DungeonTerrainGenerator generator2 = createGeneratorForTiles(scenario.seed()); // When int[][] tiles1 = generator1.generateBaseTiles(scenario.type(), scenario.width(), scenario.height()); @@ -476,11 +481,10 @@ void generateBaseTiles_veryLargeCave() { long seed = 42L; int width = 250; int height = 250; - DungeonGenerator generator = createGenerator(seed); - + DungeonTerrainGenerator generator1 = createGeneratorForTiles(seed); // When long startTime = System.currentTimeMillis(); - int[][] tiles = generator.generateBaseTiles("cave", width, height); + int[][] tiles = generator1.generateBaseTiles("cave", width, height); long elapsed = System.currentTimeMillis() - startTime; // Then @@ -505,8 +509,8 @@ void generateBaseTiles_veryLargeBSP() { long seed = 42L; int width = 180; int height = 150; - DungeonGenerator generator = createGenerator(seed); + DungeonTerrainGenerator generator = createGeneratorForTiles(seed); // When long startTime = System.currentTimeMillis(); int[][] tiles = generator.generateBaseTiles("bsp", width, height); @@ -610,7 +614,7 @@ void setUp() throws Exception { TestEngineContext.initialize(testDb); testAtlas = TestEngineContext.getTestAtlas(); zoneFactory = TestEngineContext.getTestZoneFactory(); - entityStore = TestEngineContext.getTestEntityStore(); + entityStore = TestEngineContext.getTestStore(); } @AfterEach @@ -620,34 +624,6 @@ void tearDown() { new File("testfile3.dat").delete(); } - /** Adapter to expose EntityStore from TestEngineContext. */ - private class TestEntityStoreAdapter implements EntityStore { - @Override - public Entity getEntity(long uid) { - return neon.core.Engine.getStore().getEntity(uid); - } - - @Override - public void addEntity(Entity entity) { - neon.core.Engine.getStore().addEntity(entity); - } - - @Override - public long createNewEntityUID() { - return neon.core.Engine.getStore().createNewEntityUID(); - } - - @Override - public int createNewMapUID() { - return neon.core.Engine.getStore().createNewMapUID(); - } - - @Override - public String[] getMapPath(int uid) { - return neon.core.Engine.getStore().getMapPath(uid); - } - } - /** Stub ResourceProvider for testing. */ private class TestResourceProvider implements ResourceProvider { @Override @@ -722,7 +698,7 @@ void generate_createsZoneWithRegions() throws Exception { RZoneTheme theme = MapTestFixtures.createTestZoneTheme("cave"); // Create dungeon and add zones using the Dungeon API - Dungeon dungeon = new Dungeon("test-dungeon", mapUID); + Dungeon dungeon = new Dungeon("test-dungeon", mapUID, zoneFactory); dungeon.addZone(0, "zone-0"); // Previous zone dungeon.addZone(1, "zone-1", theme); // Target zone with theme @@ -741,14 +717,15 @@ void generate_createsZoneWithRegions() throws Exception { MapTestFixtures.createTestPortalDoor(entityStore.createNewEntityUID(), 25, 25, 1, 0); entityStore.addEntity(entryDoor); previousZone.addItem(entryDoor); - + GameStores gameStores = TestEngineContext.getGameStores(); + Player player = TestEngineContext.getTestContext().getPlayer(); // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( targetZone, - entityStore, - new TestResourceProvider(), new NoQuestProvider(), + player, + gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); @@ -782,7 +759,7 @@ void generate_linksDoorsCorrectly() throws Exception { RZoneTheme theme = MapTestFixtures.createTestZoneTheme("cave"); // Create dungeon and add zones using the Dungeon API - Dungeon dungeon = new Dungeon("test-dungeon", mapUID); + Dungeon dungeon = new Dungeon("test-dungeon", mapUID, zoneFactory); dungeon.addZone(0, "zone-0"); // Previous zone dungeon.addZone(1, "zone-1", theme); // Target zone with theme @@ -801,13 +778,15 @@ void generate_linksDoorsCorrectly() throws Exception { entityStore.addEntity(entryDoor); previousZone.addItem(entryDoor); - // Create generator and generate + GameStores gameStores = TestEngineContext.getGameStores(); + Player player = TestEngineContext.getTestContext().getPlayer(); + // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( targetZone, - entityStore, - new TestResourceProvider(), new NoQuestProvider(), + player, + gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); @@ -843,7 +822,7 @@ void generate_handlesZoneConnections() throws Exception { RZoneTheme theme = MapTestFixtures.createTestZoneTheme("cave"); // Create dungeon and add zones using the Dungeon API - Dungeon dungeon = new Dungeon("test-dungeon", mapUID); + Dungeon dungeon = new Dungeon("test-dungeon", mapUID, zoneFactory); dungeon.addZone(0, "zone-0"); // Zone 0 dungeon.addZone(1, "zone-1", theme); // Zone 1 (to be generated) dungeon.addZone(2, "zone-2"); // Zone 2 (connected to zone 1) @@ -867,13 +846,15 @@ void generate_handlesZoneConnections() throws Exception { entityStore.addEntity(entryDoor); zone0.addItem(entryDoor); - // Generate zone 1 + GameStores gameStores = TestEngineContext.getGameStores(); + Player player = TestEngineContext.getTestContext().getPlayer(); + // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( - zone1, - entityStore, - new TestResourceProvider(), + zone0, new NoQuestProvider(), + player, + gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); @@ -898,7 +879,7 @@ void generate_placesQuestItem() throws Exception { RZoneTheme theme = MapTestFixtures.createTestZoneTheme("cave"); // Create dungeon and add zones using the Dungeon API - Dungeon dungeon = new Dungeon("test-dungeon", mapUID); + Dungeon dungeon = new Dungeon("test-dungeon", mapUID, zoneFactory); dungeon.addZone(0, "zone-0"); // Previous zone dungeon.addZone(1, "zone-1", theme); // Target zone with theme @@ -942,12 +923,15 @@ public Resource getResource(String id, String type) { } }; + GameStores gameStores = TestEngineContext.getGameStores(); + Player player = TestEngineContext.getTestContext().getPlayer(); + // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( targetZone, - entityStore, - questResourceProvider, - questProvider, + new NoQuestProvider(), + player, + gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); @@ -973,7 +957,7 @@ void generate_placesQuestCreature() throws Exception { RZoneTheme theme = MapTestFixtures.createTestZoneTheme("cave"); // Create dungeon and add zones using the Dungeon API - Dungeon dungeon = new Dungeon("test-dungeon", mapUID); + Dungeon dungeon = new Dungeon("test-dungeon", mapUID, zoneFactory); dungeon.addZone(0, "zone-0"); // Previous zone dungeon.addZone(1, "zone-1", theme); // Target zone with theme @@ -1022,13 +1006,15 @@ public Resource getResource(String id, String type) { return getResource(id); } }; - + GameStores gameStores = TestEngineContext.getGameStores(); + Player player = TestEngineContext.getTestContext().getPlayer(); + // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( targetZone, - entityStore, - resourceProvider, - questProvider, + new NoQuestProvider(), + player, + gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); @@ -1055,7 +1041,7 @@ void generate_isDeterministicWithFullContext() throws Exception { int mapUID = entityStore.createNewMapUID(); // Create dungeon and add zones using the Dungeon API - Dungeon dungeon = new Dungeon("test-dungeon", mapUID); + Dungeon dungeon = new Dungeon("test-dungeon", mapUID, zoneFactory); dungeon.addZone(0, "zone-0"); // Previous zone dungeon.addZone(1, "zone-1", theme); // Target zone with theme @@ -1072,15 +1058,17 @@ void generate_isDeterministicWithFullContext() throws Exception { MapTestFixtures.createTestPortalDoor(entityStore.createNewEntityUID(), 25, 25, 1, 0); entityStore.addEntity(entryDoor); previousZone.addItem(entryDoor); - + GameStores gameStores = TestEngineContext.getGameStores(); + Player player = TestEngineContext.getTestContext().getPlayer(); + // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( targetZone, - entityStore, - new TestResourceProvider(), new NoQuestProvider(), - MapUtils.withSeed(seed), - Dice.withSeed(seed)); + player, + gameStores, + MapUtils.withSeed(42L), + Dice.withSeed(42L)); generator.generate(entryDoor, previousZone, testAtlas); @@ -1147,10 +1135,10 @@ void generate_createsValidZone(GenerateScenario scenario) throws Exception { theme.doors = "test_door"; // Create generator with null zone (uses theme constructor) - DungeonGenerator generator = new DungeonGenerator(theme, null, null, null, mapUtils, dice); + DungeonTerrainGenerator generator = new DungeonTerrainGenerator(mapUtils, dice); // When: generate tiles (this is what generate() calls internally) - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(theme).terrain(); // Then: verify valid terrain was generated assertNotNull(terrain, "Terrain should not be null"); @@ -1183,14 +1171,12 @@ void generate_isDeterministicWithSameSeed() throws Exception { theme.walls = "stone_wall"; theme.doors = "test_door"; - DungeonGenerator generator1 = - new DungeonGenerator(theme, null, null, null, MapUtils.withSeed(seed), Dice.withSeed(seed)); - DungeonGenerator generator2 = - new DungeonGenerator(theme, null, null, null, MapUtils.withSeed(seed), Dice.withSeed(seed)); + DungeonTerrainGenerator generator1 = createGeneratorForTiles(seed); + DungeonTerrainGenerator generator2 = createGeneratorForTiles(seed); // When - String[][] terrain1 = generator1.generateTiles(); - String[][] terrain2 = generator2.generateTiles(); + String[][] terrain1 = generator1.generateTilesOnly(theme).terrain(); + String[][] terrain2 = generator2.generateTilesOnly(theme).terrain(); // Then assertEquals(terrain1.length, terrain2.length, "Width should match"); @@ -1215,14 +1201,14 @@ void generate_produceDifferentResultsWithDifferentSeeds() throws Exception { theme.walls = "stone_wall"; theme.doors = "test_door"; - DungeonGenerator generator1 = - new DungeonGenerator(theme, null, null, null, MapUtils.withSeed(42L), Dice.withSeed(42L)); - DungeonGenerator generator2 = - new DungeonGenerator(theme, null, null, null, MapUtils.withSeed(999L), Dice.withSeed(999L)); + DungeonTerrainGenerator generator1 = + new DungeonTerrainGenerator(MapUtils.withSeed(42L), Dice.withSeed(42L)); + DungeonTerrainGenerator generator2 = + new DungeonTerrainGenerator(MapUtils.withSeed(999L), Dice.withSeed(999L)); // When - String[][] terrain1 = generator1.generateTiles(); - String[][] terrain2 = generator2.generateTiles(); + String[][] terrain1 = generator1.generateTilesOnly(theme).terrain(); + String[][] terrain2 = generator2.generateTilesOnly(theme).terrain(); // Then: at least some tiles should differ boolean hasDifference = false; @@ -1255,11 +1241,11 @@ void generate_canPlaceCreatures(GenerateScenario scenario) throws Exception { theme.doors = "test_door"; theme.creatures.put("test_goblin", 5); // 1d5 goblins - DungeonGenerator generator = - new DungeonGenerator(theme, null, null, null, MapUtils.withSeed(seed), Dice.withSeed(seed)); + DungeonTerrainGenerator generator = + new DungeonTerrainGenerator(MapUtils.withSeed(seed), Dice.withSeed(seed)); // When - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(theme).terrain(); // Then: should have creature annotations on some tiles boolean hasCreature = false; @@ -1289,12 +1275,11 @@ void generate_canPlaceItems(GenerateScenario scenario) throws Exception { theme.walls = "stone_wall"; theme.doors = "test_door"; theme.items.put("test_treasure", 5); // 1d5 items - - DungeonGenerator generator = - new DungeonGenerator(theme, null, null, null, MapUtils.withSeed(seed), Dice.withSeed(seed)); + DungeonTerrainGenerator generator = + new DungeonTerrainGenerator(MapUtils.withSeed(seed), Dice.withSeed(seed)); // When - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(theme).terrain(); // Then: should have item annotations on some tiles boolean hasItem = false; @@ -1326,12 +1311,11 @@ void generate_respectsMinMaxSizeBounds() throws Exception { // Test with multiple seeds to ensure bounds are respected for (long seed = 1; seed <= 10; seed++) { - DungeonGenerator generator = - new DungeonGenerator( - theme, null, null, null, MapUtils.withSeed(seed), Dice.withSeed(seed)); + DungeonTerrainGenerator generator = + new DungeonTerrainGenerator(MapUtils.withSeed(seed), Dice.withSeed(seed)); // When - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(theme).terrain(); // Then assertTrue( @@ -1359,12 +1343,11 @@ void generate_usesCorrectFloorTerrainFromTheme() throws Exception { theme.floor = "marble,granite,slate"; theme.walls = "stone_wall"; theme.doors = "test_door"; - - DungeonGenerator generator = - new DungeonGenerator(theme, null, null, null, MapUtils.withSeed(42L), Dice.withSeed(42L)); + DungeonTerrainGenerator generator = + new DungeonTerrainGenerator(MapUtils.withSeed(42L), Dice.withSeed(42L)); // When - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(theme).terrain(); // Then: all floor tiles should use one of the floor types List allowedFloors = List.of("marble", "granite", "slate"); diff --git a/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java b/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java index d85397b..20072c8 100644 --- a/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java +++ b/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java @@ -47,6 +47,14 @@ class DungeonGeneratorXmlIntegrationTest { private static Map dungeonThemes; private static Map zoneThemes; + ZoneFactory zoneFactory; + + @BeforeEach + void setUp() throws Exception { + MapStore testDb = MapDbTestHelper.createInMemoryDB(); + TestEngineContext.initialize(testDb); + zoneFactory = TestEngineContext.getTestZoneFactory(); + } // ==================== Setup ==================== @@ -127,22 +135,22 @@ static Stream zoneThemeScenariosWithEntities() { // ==================== Helper Methods ==================== - private DungeonGenerator createGenerator(ZoneThemeScenario scenario) { + private DungeonTerrainGenerator createGenerator(ZoneThemeScenario scenario) { MapUtils mapUtils = MapUtils.withSeed(scenario.seed()); Dice dice = Dice.withSeed(scenario.seed()); - return new DungeonGenerator(scenario.theme(), null, null, null, mapUtils, dice); + return new DungeonTerrainGenerator(mapUtils, dice); } // ==================== Tests ==================== @ParameterizedTest(name = "generateTiles with XML theme: {0}") @MethodSource("zoneThemeScenarios") - void generateTiles_withXmlZoneTheme_generatesValidTerrain(ZoneThemeScenario scenario) { + void generateTiles_Only_withXmlZoneTheme_generatesValidTerrain(ZoneThemeScenario scenario) { // Given - DungeonGenerator generator = createGenerator(scenario); + var generator = createGenerator(scenario); // When - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(scenario.theme).terrain(); // Then: visualize (controlled by PRINT_DUNGEONS flag) if (PRINT_DUNGEONS) { @@ -189,7 +197,7 @@ static Stream connectivityScenarios() { @MethodSource("connectivityScenarios") void generateBaseTiles_withXmlZoneTheme_isConnected(ZoneThemeScenario scenario) { // Given - DungeonGenerator generator = createGenerator(scenario); + var generator = createGenerator(scenario); // When: use larger size (40x40) for more reliable connectivity int size = Math.max(40, scenario.theme().min); @@ -201,14 +209,14 @@ void generateBaseTiles_withXmlZoneTheme_isConnected(ZoneThemeScenario scenario) @ParameterizedTest(name = "determinism for XML theme: {0}") @MethodSource("zoneThemeScenarios") - void generateTiles_withXmlZoneTheme_isDeterministic(ZoneThemeScenario scenario) { + void generateTiles_Only_withXmlZoneTheme_isDeterministic(ZoneThemeScenario scenario) { // Given: two generators with same seed - DungeonGenerator gen1 = createGenerator(scenario); - DungeonGenerator gen2 = createGenerator(scenario); + var gen1 = createGenerator(scenario); + var gen2 = createGenerator(scenario); // When - String[][] terrain1 = gen1.generateTiles(); - String[][] terrain2 = gen2.generateTiles(); + String[][] terrain1 = gen1.generateTilesOnly(scenario.theme).terrain(); + String[][] terrain2 = gen2.generateTilesOnly(scenario.theme).terrain(); // Then TileAssertions.assertTerrainMatch(terrain1, terrain2); @@ -216,12 +224,12 @@ void generateTiles_withXmlZoneTheme_isDeterministic(ZoneThemeScenario scenario) @ParameterizedTest(name = "entities for XML theme: {0}") @MethodSource("zoneThemeScenariosWithEntities") - void generateTiles_withXmlZoneTheme_placesEntities(ZoneThemeScenario scenario) { + void generateTiles_Only_withXmlZoneTheme_placesEntities(ZoneThemeScenario scenario) { // Given - DungeonGenerator generator = createGenerator(scenario); + var generator = createGenerator(scenario); // When - String[][] terrain = generator.generateTiles(); + String[][] terrain = generator.generateTilesOnly(scenario.theme).terrain(); // Then: only assert for entities with sufficient counts to reliably place int creatureSum = @@ -358,92 +366,98 @@ public String getNextRequestedObject() { // ==================== Tests Using generate() ==================== - @ParameterizedTest(name = "generate() with XML theme: {0}") - @MethodSource("neon.maps.generators.DungeonGeneratorXmlIntegrationTest#zoneThemeScenarios") - void generate_withXmlZoneTheme_createsZoneWithRegions(ZoneThemeScenario scenario) - throws Exception { - // Given: Set up dungeon structure - int mapUID = entityStore.createNewMapUID(); - Dungeon dungeon = new Dungeon("test-dungeon-" + scenario.zoneId(), mapUID); - dungeon.addZone(0, "zone-0"); // Previous zone - dungeon.addZone(1, "zone-1", scenario.theme()); // Target zone with theme - - Zone previousZone = dungeon.getZone(0); - Zone targetZone = dungeon.getZone(1); - - previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); - testAtlasPosition.setMap(dungeon); - - // Create entry door in previous zone - Door entryDoor = - MapTestFixtures.createTestPortalDoor(entityStore.createNewEntityUID(), 25, 25, 1, 0); - entityStore.addEntity(entryDoor); - previousZone.addItem(entryDoor); - - // Create generator with full dependencies - DungeonGenerator generator = - new DungeonGenerator( - targetZone, - entityStore, - TestEngineContext.getTestResourceProvider(), - new NoQuestProvider(), - MapUtils.withSeed(scenario.seed()), - Dice.withSeed(scenario.seed())); - - // When: Call the full generate() method (same entry point as engine uses) - generator.generate(entryDoor, previousZone, testAtlas); - - // Then: Verify actual entities were created - assertFalse(targetZone.getRegions().isEmpty(), "Zone should have regions"); - assertHasReturnDoor(targetZone, previousZone.getIndex()); - } - - @ParameterizedTest(name = "generate() door linking: {0}") - @MethodSource("neon.maps.generators.DungeonGeneratorXmlIntegrationTest#zoneThemeScenarios") - void generate_withXmlZoneTheme_linksDoorsCorrectly(ZoneThemeScenario scenario) - throws Exception { - // Given - int mapUID = entityStore.createNewMapUID(); - Dungeon dungeon = new Dungeon("test-dungeon-" + scenario.zoneId(), mapUID); - dungeon.addZone(0, "zone-0"); - dungeon.addZone(1, "zone-1", scenario.theme()); - - Zone previousZone = dungeon.getZone(0); - Zone targetZone = dungeon.getZone(1); - - previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); - testAtlasPosition.setMap(dungeon); - - Door entryDoor = - MapTestFixtures.createTestPortalDoor(entityStore.createNewEntityUID(), 10, 10, 1, 0); - entityStore.addEntity(entryDoor); - previousZone.addItem(entryDoor); - - DungeonGenerator generator = - new DungeonGenerator( - targetZone, - entityStore, - TestEngineContext.getTestResourceProvider(), - new NoQuestProvider(), - MapUtils.withSeed(scenario.seed()), - Dice.withSeed(scenario.seed())); - - // When - generator.generate(entryDoor, previousZone, testAtlas); - - // Then: entry door should have destination position set - assertNotNull(entryDoor.portal.getDestPos(), "Entry door should have destination position"); - - // Find return door and verify it links back - Door returnDoor = findReturnDoor(targetZone, previousZone.getIndex()); - assertNotNull(returnDoor, "Should have a return door"); - assertNotNull(returnDoor.portal.getDestPos(), "Return door should have destination position"); - assertEquals( - 10, returnDoor.portal.getDestPos().x, "Return door should point to entry door X"); - assertEquals( - 10, returnDoor.portal.getDestPos().y, "Return door should point to entry door Y"); - } - + // @ParameterizedTest(name = "generate() with XML theme: {0}") + // + // @MethodSource("neon.maps.generators.DungeonGeneratorXmlIntegrationTest#zoneThemeScenarios") + // void generate_withXmlZoneTheme_createsZoneWithRegions(ZoneThemeScenario scenario) + // throws Exception { + // // Given: Set up dungeon structure + // int mapUID = entityStore.createNewMapUID(); + // Dungeon dungeon = new Dungeon( "test-dungeon-" + scenario.zoneId(), mapUID,zoneFactory); + // dungeon.addZone(0, "zone-0"); // Previous zone + // dungeon.addZone(1, "zone-1", scenario.theme()); // Target zone with theme + // + // Zone previousZone = dungeon.getZone(0); + // Zone targetZone = dungeon.getZone(1); + // + // previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); + // testAtlasPosition.setMap(dungeon); + // + // // Create entry door in previous zone + // Door entryDoor = + // MapTestFixtures.createTestPortalDoor(entityStore.createNewEntityUID(), 25, 25, 1, + // 0); + // entityStore.addEntity(entryDoor); + // previousZone.addItem(entryDoor); + // + // // Create generator with full dependencies + // DungeonGenerator generator = + // new DungeonGenerator( + // targetZone, + // entityStore, + // TestEngineContext.getTestResourceProvider(), + // new NoQuestProvider(), + // MapUtils.withSeed(scenario.seed()), + // Dice.withSeed(scenario.seed())); + // + // // When: Call the full generate() method (same entry point as engine uses) + // generator.generate(entryDoor, previousZone, testAtlas); + // + // // Then: Verify actual entities were created + // assertFalse(targetZone.getRegions().isEmpty(), "Zone should have regions"); + // assertHasReturnDoor(targetZone, previousZone.getIndex()); + // } + + // @ParameterizedTest(name = "generate() door linking: {0}") + // + // @MethodSource("neon.maps.generators.DungeonGeneratorXmlIntegrationTest#zoneThemeScenarios") + // void generate_withXmlZoneTheme_linksDoorsCorrectly(ZoneThemeScenario scenario) + // throws Exception { + // // Given + // int mapUID = entityStore.createNewMapUID(); + // Dungeon dungeon = new Dungeon("test-dungeon-" + scenario.zoneId(), mapUID,zoneFactory); + // dungeon.addZone(0, "zone-0"); + // dungeon.addZone(1, "zone-1", scenario.theme()); + // + // Zone previousZone = dungeon.getZone(0); + // Zone targetZone = dungeon.getZone(1); + // + // previousZone.addRegion(MapTestFixtures.createTestRegion(0, 0, 50, 50)); + // testAtlasPosition.setMap(dungeon); + // + // Door entryDoor = + // MapTestFixtures.createTestPortalDoor(entityStore.createNewEntityUID(), 10, 10, 1, + // 0); + // entityStore.addEntity(entryDoor); + // previousZone.addItem(entryDoor); + // + // DungeonGenerator generator = + // new DungeonGenerator( + // targetZone, + // entityStore, + // TestEngineContext.getTestResourceProvider(), + // new NoQuestProvider(), + // MapUtils.withSeed(scenario.seed()), + // Dice.withSeed(scenario.seed())); + // + // // When + // generator.generate(entryDoor, previousZone, testAtlas); + // + // // Then: entry door should have destination position set + // assertNotNull(entryDoor.portal.getDestPos(), "Entry door should have destination + // position"); + // + // // Find return door and verify it links back + // Door returnDoor = findReturnDoor(targetZone, previousZone.getIndex()); + // assertNotNull(returnDoor, "Should have a return door"); + // assertNotNull(returnDoor.portal.getDestPos(), "Return door should have destination + // position"); + // assertEquals( + // 10, returnDoor.portal.getDestPos().x, "Return door should point to entry door X"); + // assertEquals( + // 10, returnDoor.portal.getDestPos().y, "Return door should point to entry door Y"); + // } + // // ==================== Helper Methods ==================== private void assertHasReturnDoor(Zone zone, int previousZoneIndex) { diff --git a/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java b/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java index eabbe60..9e266be 100644 --- a/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java +++ b/src/test/java/neon/maps/generators/TownGeneratorIntegrationTest.java @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; - import neon.entities.UIDStore; import neon.maps.Atlas; import neon.maps.MapUtils; @@ -120,7 +119,7 @@ void setUp() throws Exception { TestEngineContext.initialize(testDb); TestEngineContext.loadTestResourceViaConfig("src/test/resources/neon.ini.sampleMod1.xml"); testAtlas = TestEngineContext.getTestAtlas(); - entityStore = TestEngineContext.getTestEntityStore() + entityStore = TestEngineContext.getTestStore(); } @AfterEach @@ -139,7 +138,7 @@ void generate_createsHouseRegions(TownScenario scenario) { new TownGenerator( zone, entityStore, - TestEngineContext.getTestResourceProvider(), + TestEngineContext.getTestResources(), MapUtils.withSeed(scenario.seed())); // When @@ -172,7 +171,7 @@ void generate_doorPlacement_isValid(TownScenario scenario) { new TownGenerator( zone, entityStore, - TestEngineContext.getTestResourceProvider(), + TestEngineContext.getTestResources(), MapUtils.withSeed(scenario.seed())); // When @@ -199,7 +198,7 @@ void generate_differentAlgorithms_byThemeType(TownScenario scenario) { new TownGenerator( zone, entityStore, - TestEngineContext.getTestResourceProvider(), + TestEngineContext.getTestResources(), MapUtils.withSeed(scenario.seed())); // When @@ -236,7 +235,7 @@ void generate_regionsDoNotOverlap(TownScenario scenario) { new TownGenerator( zone, entityStore, - TestEngineContext.getTestResourceProvider(), + TestEngineContext.getTestResources(), MapUtils.withSeed(scenario.seed())); // When diff --git a/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java b/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java index a64b88d..e36150c 100644 --- a/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java +++ b/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java @@ -118,7 +118,7 @@ private WildernessGenerator createGeneratorForTerrainOnly( @ParameterizedTest(name = "generateTerrain with XML theme: {0}") @MethodSource("wildernessThemeProvider") - void generateTerrain_withXmlTheme_generatesValidTerrain(WildernessScenario scenario) { + void generateTerrainOnlyTerrain_withXmlTheme_generatesValidTerrain(WildernessScenario scenario) { // Given int width = 50; int height = 50; @@ -134,7 +134,7 @@ void generateTerrain_withXmlTheme_generatesValidTerrain(WildernessScenario scena @ParameterizedTest(name = "determinism test for theme: {0}") @MethodSource("wildernessThemeProviderSingleSeed") - void generateTerrain_isDeterministic(WildernessScenario scenario) { + void generateTerrainOnlyTerrain_isDeterministic(WildernessScenario scenario) { // Given int width = 30; int height = 30; @@ -164,7 +164,7 @@ void setUp() throws Exception { TestEngineContext.initialize(testDb); TestEngineContext.loadTestResourceViaConfig("src/test/resources/neon.ini.sampleMod1.xml"); testAtlas = TestEngineContext.getTestAtlas(); - entityStore = TestEngineContext.getTestEntityStore(); + entityStore = TestEngineContext.getTestStore(); } @AfterEach @@ -182,17 +182,11 @@ void generate_createsValidZone(WildernessScenario scenario) { // Use grass as default floor when theme doesn't specify one String floor = scenario.theme().floor != null ? scenario.theme().floor : "grass"; Region region = new Region(floor, 0, 0, 50, 50, null, 0, null); - - WildernessGenerator generator = - new WildernessGenerator( - zone, - entityStore, - TestEngineContext.getTestResourceProvider(), - MapUtils.withSeed(scenario.seed()), - Dice.withSeed(scenario.seed())); - + WildernessTerrainGenerator geberat = + new WildernessTerrainGenerator( + MapUtils.withSeed(scenario.seed()), Dice.withSeed(scenario.seed())); // When - generator.generate(region, scenario.theme()); + geberat.generateTerrainOnly(region.getBounds(), scenario.theme(), region.getTextureType()); // Then assertNotNull(zone, "Zone should exist"); @@ -218,17 +212,12 @@ void generate_withCreatures_placesCreatures(WildernessScenario scenario) { // Use grass as default floor when theme doesn't specify one String floor = scenario.theme().floor != null ? scenario.theme().floor : "grass"; Region region = new Region(floor, 0, 0, 100, 100, null, 0, null); - - WildernessGenerator generator = - new WildernessGenerator( - zone, - entityStore, - TestEngineContext.getTestResourceProvider(), - MapUtils.withSeed(scenario.seed()), - Dice.withSeed(scenario.seed())); + var generator = + new WildernessTerrainGenerator( + MapUtils.withSeed(scenario.seed()), Dice.withSeed(scenario.seed())); // When - generator.generate(region, scenario.theme()); + generator.generateTerrainOnly(region.getBounds(), scenario.theme(), region.getTextureType()); // Then // Note: Actual creature spawning depends on dice rolls and may be 0 @@ -255,16 +244,12 @@ void generate_withVegetation_placesVegetation(WildernessScenario scenario) { String floor = scenario.theme().floor != null ? scenario.theme().floor : "grass"; Region region = new Region(floor, 0, 0, 80, 80, null, 0, null); - WildernessGenerator generator = - new WildernessGenerator( - zone, - entityStore, - TestEngineContext.getTestResourceProvider(), - MapUtils.withSeed(scenario.seed()), - Dice.withSeed(scenario.seed())); + var generator = + new WildernessTerrainGenerator( + MapUtils.withSeed(scenario.seed()), Dice.withSeed(scenario.seed())); // When - generator.generate(region, scenario.theme()); + generator.generateTerrainOnly(region.getBounds(), scenario.theme(), region.getTextureType()); // Then assertNotNull(zone, "Zone should exist"); @@ -281,31 +266,25 @@ void generate_isDeterministic_fullContext(WildernessScenario scenario) { String floor = scenario.theme().floor != null ? scenario.theme().floor : "grass"; Region region1 = new Region(floor, 0, 0, 40, 40, null, 0, null); - WildernessGenerator generator1 = - new WildernessGenerator( - zone1, - entityStore, - TestEngineContext.getTestResourceProvider(), - MapUtils.withSeed(scenario.seed()), - Dice.withSeed(scenario.seed())); + var generator = + new WildernessTerrainGenerator( + MapUtils.withSeed(scenario.seed()), Dice.withSeed(scenario.seed())); - // When - Generate first - generator1.generate(region1, scenario.theme()); + // When + generator.generateTerrainOnly( + region1.getBounds(), scenario.theme(), region1.getTextureType()); // Given - Second generation with same seed Zone zone2 = TestEngineContext.getTestZoneFactory().createZone("wilderness_det_test2", 5, 0); Region region2 = new Region(floor, 0, 0, 40, 40, null, 0, null); - WildernessGenerator generator2 = - new WildernessGenerator( - zone2, - entityStore, - TestEngineContext.getTestResourceProvider(), - MapUtils.withSeed(scenario.seed()), - Dice.withSeed(scenario.seed())); + WildernessTerrainGenerator generator2 = + new WildernessTerrainGenerator( + MapUtils.withSeed(scenario.seed()), Dice.withSeed(scenario.seed())); // When - Generate second - generator2.generate(region2, scenario.theme()); + generator2.generateTerrainOnly( + region2.getBounds(), scenario.theme(), region2.getTextureType()); // Then - Both zones should exist assertNotNull(zone1, "First zone should exist"); diff --git a/src/test/java/neon/maps/generators/WildernessGeneratorTest.java b/src/test/java/neon/maps/generators/WildernessGeneratorTest.java index c6aa412..d2b7626 100644 --- a/src/test/java/neon/maps/generators/WildernessGeneratorTest.java +++ b/src/test/java/neon/maps/generators/WildernessGeneratorTest.java @@ -90,9 +90,9 @@ static Stream editorScenarios() { @ParameterizedTest(name = "{index}: {0}") @MethodSource("islandScenarios") - void generateIslands_withVariousSeeds_generatesValidPatterns(IslandScenario scenario) { + void generateTerrainOnlyIslands_withVariousSeeds_generatesValidPatterns(IslandScenario scenario) { // Given - WildernessGenerator generator = createGenerator(scenario.seed()); + var generator = createGenerator(scenario.seed()); // When boolean[][] islands = @@ -119,10 +119,10 @@ void generateIslands_withVariousSeeds_generatesValidPatterns(IslandScenario scen @ParameterizedTest(name = "{index}: {0}") @MethodSource("islandScenarios") - void generateIslands_isDeterministic(IslandScenario scenario) { + void generateTerrainOnlyIslands_isDeterministic(IslandScenario scenario) { // Given: two generators with same seed - WildernessGenerator gen1 = createGenerator(scenario.seed()); - WildernessGenerator gen2 = createGenerator(scenario.seed()); + var gen1 = createGenerator(scenario.seed()); + var gen2 = createGenerator(scenario.seed()); // When boolean[][] islands1 = @@ -146,9 +146,9 @@ void generateIslands_isDeterministic(IslandScenario scenario) { @ParameterizedTest(name = "{index}: {0}") @MethodSource("edgeCaseIslandScenarios") - void generateIslands_withEdgeCases_handlesCorrectly(IslandScenario scenario) { + void generateTerrainOnlyIslands_withEdgeCases_handlesCorrectly(IslandScenario scenario) { // Given - WildernessGenerator generator = createGenerator(scenario.seed()); + var generator = createGenerator(scenario.seed()); // When boolean[][] islands = @@ -181,9 +181,9 @@ void generateIslands_withEdgeCases_handlesCorrectly(IslandScenario scenario) { } @Test - void generateIslands_withSmallSize_handlesEdgeNeighbors() { + void generateTerrainOnlyIslands_withSmallSize_handlesEdgeNeighbors() { // Given: very small grid where edge cases matter - WildernessGenerator generator = createGenerator(42L); + var generator = createGenerator(42L); // When boolean[][] islands = generator.generateIslands(3, 3, 50, 4, 3); @@ -201,15 +201,14 @@ void generateIslands_withSmallSize_handlesEdgeNeighbors() { // Placeholder for future integration tests // @ParameterizedTest(name = "{index}: {0}") // @MethodSource("editorScenarios") - void generate_editorMode_returnsTerrainArray_SKIPPED(EditorScenario scenario) { + void generate_TerrainOnly_editorMode_returnsTerrainArray_SKIPPED(EditorScenario scenario) { // Given - WildernessGenerator generator = - createGeneratorWithTerrain(scenario.seed(), scenario.width(), scenario.height()); + var generator = createGenerator(scenario.seed()); RRegionTheme theme = createTestTheme("grass"); // When String[][] terrain = - generator.generate( + generator.generateTerrainOnly( new Rectangle(0, 0, scenario.width(), scenario.height()), theme, "grass"); // Then: visualize if enabled @@ -228,33 +227,34 @@ void generate_editorMode_returnsTerrainArray_SKIPPED(EditorScenario scenario) { // @ParameterizedTest(name = "{index}: {0}") // @MethodSource("editorScenarios") - void generate_editorMode_isDeterministic_SKIPPED(EditorScenario scenario) { + void generate_TerrainOnly_editorMode_isDeterministic_SKIPPED(EditorScenario scenario) { // Given: two generators with same seed - WildernessGenerator gen1 = - createGeneratorWithTerrain(scenario.seed(), scenario.width(), scenario.height()); - WildernessGenerator gen2 = - createGeneratorWithTerrain(scenario.seed(), scenario.width(), scenario.height()); + var gen1 = createGenerator(scenario.seed()); + var gen2 = createGenerator(scenario.seed()); RRegionTheme theme = createTestTheme("grass"); // When String[][] terrain1 = - gen1.generate(new Rectangle(0, 0, scenario.width(), scenario.height()), theme, "grass"); + gen1.generateTerrainOnly( + new Rectangle(0, 0, scenario.width(), scenario.height()), theme, "grass"); String[][] terrain2 = - gen2.generate(new Rectangle(0, 0, scenario.width(), scenario.height()), theme, "grass"); + gen2.generateTerrainOnly( + new Rectangle(0, 0, scenario.width(), scenario.height()), theme, "grass"); // Then TileAssertions.assertTerrainMatch(terrain1, terrain2); } // @Test - void generate_editorMode_respectsBounds_SKIPPED() { + void generate_TerrainOnly_editorMode_respectsBounds_SKIPPED() { // Given - WildernessGenerator generator = createGeneratorWithTerrain(42L, 50, 50); + var gen1 = createGenerator(21L); + RRegionTheme theme = createTestTheme("stone"); Rectangle bounds = new Rectangle(10, 10, 20, 15); // When - String[][] terrain = generator.generate(bounds, theme, "stone"); + String[][] terrain = gen1.generateTerrainOnly(bounds, theme, "stone"); // Then: should respect the bounds assertEquals(20, terrain.length, "Width should match bounds"); @@ -269,11 +269,11 @@ void generate_editorMode_respectsBounds_SKIPPED() { * @param seed random seed * @return configured generator */ - private WildernessGenerator createGenerator(long seed) { + private WildernessTerrainGenerator createGenerator(long seed) { String[][] terrain = new String[32][32]; // Default size with padding MapUtils mapUtils = MapUtils.withSeed(seed); Dice dice = Dice.withSeed(seed); - return new WildernessGenerator(terrain, null, null, mapUtils, dice); + return new WildernessTerrainGenerator(mapUtils, dice); } /** diff --git a/src/test/java/neon/test/TestEngineContext.java b/src/test/java/neon/test/TestEngineContext.java index 30135d2..b55659a 100644 --- a/src/test/java/neon/test/TestEngineContext.java +++ b/src/test/java/neon/test/TestEngineContext.java @@ -12,6 +12,7 @@ import neon.core.event.TaskQueue; import neon.entities.Entity; import neon.entities.Player; +import neon.entities.UIDStore; import neon.entities.components.PhysicsComponent; import neon.entities.property.Gender; import neon.maps.*; @@ -37,10 +38,9 @@ public class TestEngineContext { /** -- GETTER -- Gets the test Atlas instance. */ @Getter private static Atlas testAtlas; -@Getter - private static GameStores gameStores; - @Getter - private static StubResourceManager testResources; + + @Getter private static GameStores gameStores; + @Getter private static StubResourceManager testResources; private static Game testGame; @Getter private static neon.entities.UIDStore testStore; @Getter private static PhysicsManager stubPhysicsManager; @@ -92,27 +92,24 @@ public static void initialize(MapStore db) throws Exception { setStaticField(Engine.class, "resources", testResources); // Create test UIDStore - testStore = new neon.entities.UIDStore(testDb); + testStore = new neon.entities.UIDStore(getStubFileSystem(), testDb); // Create test EntityStore - // Create stub PhysicsManager and ZoneActivator stubPhysicsManager = new StubPhysicsManager(); Player stubPlayer = new StubPlayer(); testZoneActivator = new ZoneActivator(stubPhysicsManager); // Create ZoneFactory for tests - testZoneFactory = new ZoneFactory(db); - mapLoader = new MapLoader( getStubFileSystem(),testStore, testResources); + testZoneFactory = new ZoneFactory(testDb, testStore, testResources); + mapLoader = + new MapLoader(getStubFileSystem(), testStore, testResources, testZoneFactory, stubPlayer); // Create test Atlas with dependency injection (doesn't need Engine.game) testAtlas = new Atlas(getStubFileSystem(), testDb, testStore, mapLoader); - gameStores = - new DefaultGameStores(getTestResources(), getStubFileSystem(), testStore, testAtlas); + gameStores = new DefaultGameStores(getTestResources(), getStubFileSystem(), stubPlayer); questTracker = new QuestTracker(gameStores); - atlasPosition = - new AtlasPosition( - testAtlas, testZoneActivator, testResources, questTracker, testStore); + atlasPosition = new AtlasPosition(gameStores, questTracker, stubPlayer); // Create test Game using new DI constructor testGame = new Game(stubPlayer, gameStores, atlasPosition); @@ -178,6 +175,10 @@ public static ResourceProvider getTestResourceProvider() { return testResources; } + public static UIDStore getTestEntityStore() { + return TestEngineContext.getTestStore(); + } + public static void loadTestResourceViaConfig(String configFilename) throws Exception { IniBuilder iniBuilder = new IniBuilder(configFilename, getStubFileSystem(), new TaskQueue()); iniBuilder.build(getTestResources()); @@ -279,7 +280,13 @@ static class StubPlayer extends Player { private final PhysicsComponent physicsComponent; public StubPlayer() { - super(new RCreature("test"), "TestPlayer", Gender.MALE, Specialisation.combat, "Warrior",getGameStores()); + super( + new RCreature("test"), + "TestPlayer", + Gender.MALE, + Specialisation.combat, + "Warrior", + getGameStores()); this.physicsComponent = new PhysicsComponent(0L, new Rectangle(0, 0, 1, 1)); } From 2e79bee45fccfae3071f94b853e87fe364be9180 Mon Sep 17 00:00:00 2001 From: Peter Riewe Date: Wed, 14 Jan 2026 15:50:00 -0500 Subject: [PATCH 06/12] Most serialization fixed (Except UIDStore) --- data/locale/locale.en | 4 + src/main/java/neon/ai/AIFactory.java | 22 ++- .../java/neon/core/DefaultGameStores.java | 7 +- src/main/java/neon/core/GameLoader.java | 4 +- src/main/java/neon/core/GameStores.java | 3 + .../java/neon/core/handlers/CombatUtils.java | 80 +++------- src/main/java/neon/entities/Creature.java | 73 ++++----- src/main/java/neon/entities/Entity.java | 7 +- src/main/java/neon/entities/Player.java | 13 +- src/main/java/neon/entities/UIDStore.java | 2 +- .../entities/components/FactionComponent.java | 7 +- src/main/java/neon/maps/Atlas.java | 40 ++++- src/main/java/neon/maps/AtlasPosition.java | 11 ++ src/main/java/neon/maps/Dungeon.java | 100 +++++++++--- src/main/java/neon/maps/Map.java | 3 +- src/main/java/neon/maps/MapLoader.java | 5 +- src/main/java/neon/maps/Region.java | 112 +++----------- src/main/java/neon/maps/World.java | 32 ++-- src/main/java/neon/maps/Zone.java | 18 +++ src/main/java/neon/maps/ZoneFactory.java | 143 +++++++++++++++++- .../neon/maps/generators/TownGenerator.java | 30 +--- .../WildernessTerrainGenerator.java | 2 +- .../neon/maps/mvstore/IntegerDataType.java | 71 +++++++++ src/main/java/neon/maps/mvstore/MVUtils.java | 26 ++++ .../java/neon/maps/mvstore/MapDataType.java | 62 ++++++++ .../neon/maps/mvstore/MvStoreFactory.java | 3 + .../neon/maps/mvstore/RegionDataType.java | 73 +++++++++ .../java/neon/maps/mvstore/WorldDataType.java | 49 ++++++ src/main/java/neon/maps/mvstore/ZoneType.java | 131 ++++++++++++++++ src/main/java/neon/util/Graph.java | 31 +++- .../java/neon/util/mapstorage/MapStore.java | 3 + .../mapstorage/MapStoreMVStoreAdapter.java | 10 ++ src/main/java/neon/util/spatial/RTree.java | 6 +- .../neon/editor/JacksonXmlBuilderTest.java | 11 +- .../java/neon/maps/AtlasIntegrationTest.java | 25 +-- src/test/java/neon/maps/AtlasTest.java | 55 ++----- .../java/neon/maps/MapPerformanceTest.java | 38 ++--- .../java/neon/maps/MapSerializationTest.java | 50 +++--- src/test/java/neon/maps/MapTestFixtures.java | 69 --------- .../neon/maps/RegionSerializationTest.java | 26 ++-- .../java/neon/maps/ZoneSerializationTest.java | 18 +-- .../maps/generators/DungeonGeneratorTest.java | 1 + .../DungeonGeneratorXmlIntegrationTest.java | 11 +- .../WildernessGeneratorIntegrationTest.java | 10 +- .../java/neon/test/TestEngineContext.java | 99 +++--------- .../util/spatial/RTreePersistenceTest.java | 72 ++++++--- 46 files changed, 1053 insertions(+), 615 deletions(-) create mode 100644 src/main/java/neon/maps/mvstore/IntegerDataType.java create mode 100644 src/main/java/neon/maps/mvstore/MVUtils.java create mode 100644 src/main/java/neon/maps/mvstore/MapDataType.java create mode 100644 src/main/java/neon/maps/mvstore/MvStoreFactory.java create mode 100644 src/main/java/neon/maps/mvstore/RegionDataType.java create mode 100644 src/main/java/neon/maps/mvstore/WorldDataType.java create mode 100644 src/main/java/neon/maps/mvstore/ZoneType.java diff --git a/data/locale/locale.en b/data/locale/locale.en index e69de29..2212347 100644 --- a/data/locale/locale.en +++ b/data/locale/locale.en @@ -0,0 +1,4 @@ +$newGame=New Game +$loadGame=Load Game +$options=Options +$quit=Quit \ No newline at end of file diff --git a/src/main/java/neon/ai/AIFactory.java b/src/main/java/neon/ai/AIFactory.java index 272d8fa..633f276 100644 --- a/src/main/java/neon/ai/AIFactory.java +++ b/src/main/java/neon/ai/AIFactory.java @@ -86,18 +86,14 @@ public AI getAI(Creature creature) { } private AI getAI(AIType type, Creature creature, byte aggression, byte confidence, int range) { - switch (type) { - case wander: - return new BasicAI(creature, aggression, confidence, resourceManager, uidStore, player); - case guard: - return new GuardAI( - creature, aggression, confidence, range, resourceManager, uidStore, player); - case schedule: - return new ScheduleAI( - creature, aggression, confidence, new Point[0], resourceManager, uidStore, player); - default: - return new GuardAI( - creature, aggression, confidence, range, resourceManager, uidStore, player); - } + return switch (type) { + case wander -> + new BasicAI(creature, aggression, confidence, resourceManager, uidStore, player); + case schedule -> + new ScheduleAI( + creature, aggression, confidence, new Point[0], resourceManager, uidStore, player); + default -> + new GuardAI(creature, aggression, confidence, range, resourceManager, uidStore, player); + }; } } diff --git a/src/main/java/neon/core/DefaultGameStores.java b/src/main/java/neon/core/DefaultGameStores.java index 03d00e2..d7dd52e 100644 --- a/src/main/java/neon/core/DefaultGameStores.java +++ b/src/main/java/neon/core/DefaultGameStores.java @@ -18,14 +18,15 @@ public class DefaultGameStores implements GameStores { private final UIDStore store; private final Atlas atlas; private final ZoneFactory zoneFactory; + private final MapStore zoneMapStore; public DefaultGameStores(ResourceManager resources, FileSystem fileSystem, Player player) { this.resources = resources; this.fileSystem = fileSystem; this.store = new UIDStore(fileSystem, fileSystem.getFullPath("uidstore")); - MapStore mapStore = Atlas.getMapStore(fileSystem, "zones"); - this.zoneFactory = new ZoneFactory(mapStore, store, resources); + zoneMapStore = Atlas.getMapStore(fileSystem, "zones"); + this.zoneFactory = new ZoneFactory(zoneMapStore, store, resources); MapLoader mapLoader = new MapLoader(fileSystem, store, resources, zoneFactory, player); - atlas = new Atlas(fileSystem, mapStore, store, mapLoader); + atlas = new Atlas(fileSystem, zoneMapStore, store, resources, mapLoader); } } diff --git a/src/main/java/neon/core/GameLoader.java b/src/main/java/neon/core/GameLoader.java index 6ea78b9..4e61334 100644 --- a/src/main/java/neon/core/GameLoader.java +++ b/src/main/java/neon/core/GameLoader.java @@ -138,7 +138,7 @@ public void initGame( // initialize player RCreature species = ((RCreature) gameStores.getResources().getResource(race)).clone(); ItemFactory itemFactory = new ItemFactory(gameStores.getResources()); - Player player = new Player(species, name, gender, spec, profession, gameStores); + Player player = new Player(species, name, gender, spec, profession, gameStores.getStore()); player.species.text = "@"; context.startGame( new Game(player, gameStores, context.getPhysicsManager(), context.getQuestTracker())); @@ -296,7 +296,7 @@ private void loadPlayer(SaveGameModel.PlayerSaveData playerData) { Gender.valueOf(playerData.gender.toUpperCase()), Player.Specialisation.valueOf(playerData.specialisation), playerData.profession, - gameStores); + gameStores.getStore()); context.startGame( new Game(player, gameStores, context.getPhysicsManager(), context.getQuestTracker())); Rectangle bounds = player.getShapeComponent(); diff --git a/src/main/java/neon/core/GameStores.java b/src/main/java/neon/core/GameStores.java index dbfbe96..90a9fee 100644 --- a/src/main/java/neon/core/GameStores.java +++ b/src/main/java/neon/core/GameStores.java @@ -5,6 +5,7 @@ import neon.maps.ZoneFactory; import neon.resources.ResourceManager; import neon.systems.files.FileSystem; +import neon.util.mapstorage.MapStore; public interface GameStores { Atlas getAtlas(); @@ -16,4 +17,6 @@ public interface GameStores { FileSystem getFileSystem(); ZoneFactory getZoneFactory(); + + MapStore getZoneMapStore(); } diff --git a/src/main/java/neon/core/handlers/CombatUtils.java b/src/main/java/neon/core/handlers/CombatUtils.java index 7e523af..0f3611c 100644 --- a/src/main/java/neon/core/handlers/CombatUtils.java +++ b/src/main/java/neon/core/handlers/CombatUtils.java @@ -18,6 +18,7 @@ package neon.core.handlers; +import java.io.Serializable; import neon.entities.*; import neon.entities.components.Inventory; import neon.entities.property.Skill; @@ -26,7 +27,7 @@ import neon.resources.RWeapon.WeaponType; import neon.util.Dice; -public class CombatUtils { +public class CombatUtils implements Serializable { private final UIDStore uidStore; @@ -41,25 +42,14 @@ public CombatUtils(UIDStore uidStore) { * @return an attack roll */ protected int attack(Creature creature) { - switch (getWeaponType(creature)) { - case BLADE_ONE: - case BLADE_TWO: - return SkillHandler.check(creature, Skill.BLADE); - case BLUNT_ONE: - case BLUNT_TWO: - return SkillHandler.check(creature, Skill.BLUNT); - case AXE_ONE: - case AXE_TWO: - return SkillHandler.check(creature, Skill.AXE); - case SPEAR: - return SkillHandler.check(creature, Skill.SPEAR); - case BOW: - case CROSSBOW: - case THROWN: - return SkillHandler.check(creature, Skill.ARCHERY); - default: - return SkillHandler.check(creature, Skill.UNARMED); - } + return switch (getWeaponType(creature)) { + case BLADE_ONE, BLADE_TWO -> SkillHandler.check(creature, Skill.BLADE); + case BLUNT_ONE, BLUNT_TWO -> SkillHandler.check(creature, Skill.BLUNT); + case AXE_ONE, AXE_TWO -> SkillHandler.check(creature, Skill.AXE); + case SPEAR -> SkillHandler.check(creature, Skill.SPEAR); + case BOW, CROSSBOW, THROWN -> SkillHandler.check(creature, Skill.ARCHERY); + default -> SkillHandler.check(creature, Skill.UNARMED); + }; } /** @@ -88,22 +78,10 @@ protected int getAV(Creature creature) { float mod = 1f; switch (getWeaponType(creature)) { - case BLADE_ONE: - case BLADE_TWO: - case BLUNT_ONE: - case BLUNT_TWO: - case AXE_ONE: - case AXE_TWO: - case SPEAR: - mod = creature.species.dex / 20; - break; - case BOW: - case CROSSBOW: - case THROWN: - mod = creature.species.str / 20; - break; - default: - break; + case BLADE_ONE, BLADE_TWO, BLUNT_ONE, BLUNT_TWO, AXE_ONE, AXE_TWO, SPEAR -> + mod = creature.species.dex / 20; + case BOW, CROSSBOW, THROWN -> mod = creature.species.str / 20; + default -> {} } return (int) (damage * mod); } @@ -119,17 +97,10 @@ protected int block(Creature creature) { float mod = 1f; Armor armor = (Armor) uidStore.getEntity(creature.getInventoryComponent().get(Slot.SHIELD)); switch (((RClothing) (armor.resource)).kind) { - case LIGHT: - mod = creature.getSkill(Skill.LIGHT_ARMOR) / 20f; - break; - case MEDIUM: - mod = creature.getSkill(Skill.MEDIUM_ARMOR) / 20f; - break; - case HEAVY: - mod = creature.getSkill(Skill.HEAVY_ARMOR) / 20f; - break; - default: - break; + case LIGHT -> mod = creature.getSkill(Skill.LIGHT_ARMOR) / 20f; + case MEDIUM -> mod = creature.getSkill(Skill.MEDIUM_ARMOR) / 20f; + case HEAVY -> mod = creature.getSkill(Skill.HEAVY_ARMOR) / 20f; + default -> {} } return (int) (SkillHandler.check(creature, Skill.BLOCK) * mod); @@ -160,17 +131,10 @@ public int getDV(Creature creature) { Armor c = (Armor) item; int mod = 0; switch (((RClothing) c.resource).kind) { - case LIGHT: - mod = 1 + creature.getSkill(Skill.LIGHT_ARMOR) / 20; - break; - case MEDIUM: - mod = 1 + creature.getSkill(Skill.MEDIUM_ARMOR) / 20; - break; - case HEAVY: - mod = 1 + creature.getSkill(Skill.HEAVY_ARMOR) / 20; - break; - default: - break; + case LIGHT -> mod = 1 + creature.getSkill(Skill.LIGHT_ARMOR) / 20; + case MEDIUM -> mod = 1 + creature.getSkill(Skill.MEDIUM_ARMOR) / 20; + case HEAVY -> mod = 1 + creature.getSkill(Skill.HEAVY_ARMOR) / 20; + default -> {} } AR += ((RClothing) c.resource).rating * s.getArmorModifier() * mod; } diff --git a/src/main/java/neon/entities/Creature.java b/src/main/java/neon/entities/Creature.java index 3d8f6c6..a14af23 100644 --- a/src/main/java/neon/entities/Creature.java +++ b/src/main/java/neon/entities/Creature.java @@ -19,6 +19,8 @@ package neon.entities; import java.util.*; +import lombok.Getter; +import lombok.Setter; import neon.ai.AI; import neon.entities.components.*; import neon.entities.property.*; @@ -38,14 +40,40 @@ public class Creature extends Entity { public final RCreature species; public AI brain; + /** + * -- GETTER -- + * + * @return this creature's gender + */ // miscellaneous - protected Gender gender; - protected String name; + @Getter protected Gender gender; + /** + * -- GETTER -- + * + *

    -- SETTER -- Sets the name of this creature. + * + * @return this creature's name + * @param name the new name + */ + @Setter @Getter protected String name; + + /** + * -- GETTER -- + * + * @return this creature's list of skills + */ // lists - protected EnumMap skills; + @Getter protected EnumMap skills; + protected ArrayList spells; // active spells - protected Set conditions; + + /** + * -- GETTER -- + * + * @return all conditions this creature has + */ + @Getter protected Set conditions; // character attributes private int date = 0; // time of death @@ -131,13 +159,6 @@ public void removeCondition(Condition c) { conditions.remove(c); } - /** - * @return all conditions this creature has - */ - public Set getConditions() { - return conditions; - } - /** * Checks whether this creature has a condition. * @@ -221,15 +242,6 @@ public void restoreSkill(Skill skill, int value) { skills.put(skill, Math.min(species.skills.get(skill), skills.get(skill) + value)); } - /** - * Sets the name of this creature. - * - * @param name the new name - */ - public void setName(String name) { - this.name = name; - } - /* * all getters here * @@ -247,13 +259,6 @@ public int getLevel() { / 6); } - /** - * @return this creature's name - */ - public String getName() { - return name; - } - /** * @return this creature's name */ @@ -261,13 +266,6 @@ public String toString() { return name; } - /** - * @return this creature's gender - */ - public Gender getGender() { - return gender; - } - /** * @param skill the skill to check * @return the skill check @@ -280,13 +278,6 @@ public int getSkill(Skill skill) { } } - /** - * @return this creature's list of skills - */ - public EnumMap getSkills() { - return skills; - } - public boolean hasDialog() { return false; } diff --git a/src/main/java/neon/entities/Entity.java b/src/main/java/neon/entities/Entity.java index a798d2c..35ab2cb 100644 --- a/src/main/java/neon/entities/Entity.java +++ b/src/main/java/neon/entities/Entity.java @@ -20,7 +20,7 @@ import com.google.common.collect.ClassToInstanceMap; import com.google.common.collect.MutableClassToInstanceMap; -import java.io.Serializable; +import java.io.*; import neon.entities.components.Component; import neon.entities.components.PhysicsComponent; import neon.entities.components.RenderComponent; @@ -33,13 +33,14 @@ * @author mdriesen */ public abstract class Entity implements Serializable { + // components public final ShapeComponent bounds; protected ClassToInstanceMap components = MutableClassToInstanceMap.create(); - private final long uid; - private final String id; + private long uid; + private String id; /** * @param id the id of the resource this entity is an instance of diff --git a/src/main/java/neon/entities/Player.java b/src/main/java/neon/entities/Player.java index 3ea6b20..2127910 100644 --- a/src/main/java/neon/entities/Player.java +++ b/src/main/java/neon/entities/Player.java @@ -22,7 +22,6 @@ import java.util.concurrent.atomic.AtomicReference; import lombok.Getter; import lombok.Setter; -import neon.core.GameStores; import neon.core.handlers.SkillHandler; import neon.entities.components.Inventory; import neon.entities.components.Lock; @@ -51,7 +50,7 @@ public class Player extends Hominid { @Getter private final String profession; private final EnumMap mods; private boolean sneak = false; - private final GameStores gameStores; + private final UIDStore uidStore; @Setter @Getter private String sign; @Getter private Creature mount; @@ -65,9 +64,9 @@ public Player( Gender gender, Specialisation spec, String profession, - GameStores gameStores) { + UIDStore gameStores) { super(species.id, 0, species); - this.gameStores = gameStores; + this.uidStore = gameStores; components.putInstance(RenderComponent.class, new PlayerRenderComponent(this)); this.name = name; this.gender = gender; @@ -121,15 +120,15 @@ public String getAVString() { String damage; if (inventory.hasEquiped(Slot.WEAPON)) { - Weapon weapon = (Weapon) gameStores.getStore().getEntity(inventory.get(Slot.WEAPON)); + Weapon weapon = (Weapon) uidStore.getEntity(inventory.get(Slot.WEAPON)); damage = weapon.getDamage(); if (weapon.getWeaponType().equals(WeaponType.BOW) || weapon.getWeaponType().equals(WeaponType.CROSSBOW)) { - Weapon ammo = (Weapon) gameStores.getStore().getEntity(inventory.get(Slot.AMMO)); + Weapon ammo = (Weapon) uidStore.getEntity(inventory.get(Slot.AMMO)); damage += " : " + ammo.getDamage(); } } else if (inventory.hasEquiped(Slot.AMMO)) { - Weapon ammo = (Weapon) gameStores.getStore().getEntity(inventory.get(Slot.AMMO)); + Weapon ammo = (Weapon) uidStore.getEntity(inventory.get(Slot.AMMO)); damage = ammo.getDamage(); } else { damage = species.av; diff --git a/src/main/java/neon/entities/UIDStore.java b/src/main/java/neon/entities/UIDStore.java index 7eb05ee..783c84a 100644 --- a/src/main/java/neon/entities/UIDStore.java +++ b/src/main/java/neon/entities/UIDStore.java @@ -43,7 +43,7 @@ public class UIDStore implements EntityStore, Closeable { public static final long DUMMY = 0; @Getter private final FileSystem fileSystem; // uid database - private final MapStore uidDb; + @Getter private final MapStore uidDb; // uids of all objects in the game private final Map objects; // uids of all loaded mods diff --git a/src/main/java/neon/entities/components/FactionComponent.java b/src/main/java/neon/entities/components/FactionComponent.java index 052cbaa..689a251 100644 --- a/src/main/java/neon/entities/components/FactionComponent.java +++ b/src/main/java/neon/entities/components/FactionComponent.java @@ -19,6 +19,7 @@ package neon.entities.components; import java.util.HashMap; +import lombok.Getter; /** * Keeps track of the factions a creature belongs to and their standing with these factions. @@ -27,16 +28,12 @@ */ public class FactionComponent implements Component { private final long uid; - private HashMap factions = new HashMap<>(); + @Getter private HashMap factions = new HashMap<>(); public FactionComponent(long uid) { this.uid = uid; } - public HashMap getFactions() { - return factions; - } - public void addFaction(String faction, int rank) { factions.put(faction, rank); } diff --git a/src/main/java/neon/maps/Atlas.java b/src/main/java/neon/maps/Atlas.java index 62c8f16..dd512d3 100644 --- a/src/main/java/neon/maps/Atlas.java +++ b/src/main/java/neon/maps/Atlas.java @@ -22,8 +22,12 @@ import java.io.IOException; import java.util.concurrent.ConcurrentMap; import lombok.extern.slf4j.Slf4j; -import neon.maps.services.EntityStore; +import neon.entities.UIDStore; +import neon.maps.mvstore.IntegerDataType; +import neon.maps.mvstore.MapDataType; +import neon.maps.mvstore.WorldDataType; import neon.maps.services.MapAtlas; +import neon.resources.ResourceManager; import neon.systems.files.FileSystem; import neon.util.mapstorage.MapStore; import neon.util.mapstorage.MapStoreMVStoreAdapter; @@ -38,34 +42,58 @@ public class Atlas implements Closeable, MapAtlas { private final MapStore db; private final ConcurrentMap maps; - private final EntityStore entityStore; + private final UIDStore entityStore; + private final ResourceManager resourceManager; private final FileSystem fileSystem; private final MapLoader mapLoader; + private final ZoneFactory zoneFactory; + private final WorldDataType worldDataType; + private final Dungeon.DungeonDataType dungeonDataType; + private final MapDataType mapDataType; public Atlas( - FileSystem fileSystem, MapStore mapStore, EntityStore entityStore, MapLoader mapLoader) { + FileSystem fileSystem, + MapStore mapStore, + UIDStore entityStore, + ResourceManager resourceManager, + MapLoader mapLoader) { this.fileSystem = fileSystem; this.entityStore = entityStore; this.db = mapStore; + this.resourceManager = resourceManager; // files.delete(path); // String fileName = files.getFullPath(path); // log.warn("Creating new MVStore at {}", fileName); this.mapLoader = mapLoader; + zoneFactory = new ZoneFactory(mapStore, entityStore, resourceManager); + worldDataType = new WorldDataType(zoneFactory); + dungeonDataType = new Dungeon.DungeonDataType(zoneFactory); + mapDataType = new MapDataType(worldDataType, dungeonDataType); // db = MVStore.open(fileName); - maps = db.openMap("maps"); + maps = db.openMap("maps", IntegerDataType.INSTANCE, mapDataType); } /** Initializes this {@code Atlas} with dependency injection. */ - public Atlas(FileSystem fileSystem, String path, EntityStore entityStore, MapLoader mapLoader) { + public Atlas( + FileSystem fileSystem, + String path, + UIDStore entityStore, + ResourceManager resourceManager, + MapLoader mapLoader) { this.fileSystem = fileSystem; this.entityStore = entityStore; + this.resourceManager = resourceManager; this.db = getMapStore(fileSystem, path); // files.delete(path); // String fileName = files.getFullPath(path); // log.warn("Creating new MVStore at {}", fileName); this.mapLoader = mapLoader; + zoneFactory = new ZoneFactory(db, entityStore, resourceManager); + worldDataType = new WorldDataType(zoneFactory); + dungeonDataType = new Dungeon.DungeonDataType(zoneFactory); + mapDataType = new MapDataType(worldDataType, dungeonDataType); // db = MVStore.open(fileName); - maps = db.openMap("maps"); + maps = db.openMap("maps", IntegerDataType.INSTANCE, mapDataType); } public static MapStore getMapStore(FileSystem files, String fileName) { diff --git a/src/main/java/neon/maps/AtlasPosition.java b/src/main/java/neon/maps/AtlasPosition.java index 92dc51e..24bda8c 100644 --- a/src/main/java/neon/maps/AtlasPosition.java +++ b/src/main/java/neon/maps/AtlasPosition.java @@ -87,4 +87,15 @@ public void setMap(Map map) { atlas.putMapIfNeeded(map); player.setCurrentMap(map); } + + /** + * Set the current map. + * + * @param map the new current map + */ + public void setMap(World map) { + atlas.putMapIfNeeded(map); + player.setCurrentMap(map); + player.setCurrentZone(map.getZone()); + } } diff --git a/src/main/java/neon/maps/Dungeon.java b/src/main/java/neon/maps/Dungeon.java index 24808f1..407e148 100644 --- a/src/main/java/neon/maps/Dungeon.java +++ b/src/main/java/neon/maps/Dungeon.java @@ -18,14 +18,16 @@ package neon.maps; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; +import java.nio.ByteBuffer; import java.util.Collection; import lombok.Getter; import lombok.Setter; +import neon.maps.mvstore.MVUtils; +import neon.maps.mvstore.ZoneType; import neon.resources.RZoneTheme; import neon.util.Graph; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.BasicDataType; /** * A dungeon. It can contain several interconnected zones. @@ -34,9 +36,9 @@ */ public class Dungeon implements Map { @Setter @Getter private String name; - private int uid; - private Graph zones = new Graph(); - private ZoneFactory zoneFactory; + private final int uid; + private final Graph zones; + private final ZoneFactory zoneFactory; /** * Initialize a dungeon. @@ -45,15 +47,18 @@ public class Dungeon implements Map { * @param uid the unique identifier of this dungeon */ public Dungeon(String name, int uid, ZoneFactory zoneFactory) { + this(name, uid, new Graph<>(), zoneFactory); + } + + private Dungeon(String name, int uid, Graph zones, ZoneFactory zoneFactory) { this.name = name; this.uid = uid; + this.zones = zones; this.zoneFactory = zoneFactory; } - public Dungeon() {} - public Zone getZone(int i) { - return zones.getNode(i); + return zones.getNodeContent(i); } public int getUID() { @@ -75,7 +80,7 @@ public Collection getZones() { } public String getZoneName(int zone) { - return zones.getNode(zone).getName(); + return zones.getNodeContent(zone).getName(); } /** @@ -96,16 +101,71 @@ public Collection getConnections(int from) { return zones.getConnections(from); } - @SuppressWarnings("unchecked") - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - name = in.readUTF(); - uid = in.readInt(); - zones = (Graph) in.readObject(); - } + public static class DungeonDataType extends BasicDataType { + + private final ZoneFactory zoneFactory; + private final ZoneType zoneDataType; + + public DungeonDataType(ZoneFactory zoneFactory) { + this.zoneFactory = zoneFactory; + zoneDataType = new ZoneType(zoneFactory); + } + + @Override + public int getMemory(Dungeon obj) { + return obj.name.length() + 16 * obj.zones.getNodes().size(); + } + + @Override + public void write(WriteBuffer buff, Dungeon obj) { + MVUtils.writeString(buff, obj.name); + buff.putInt(obj.uid); + int graphSize = obj.zones.getGraphContent().size(); + buff.putInt(graphSize); + + for (var entry : obj.zones.getGraphContent()) { + buff.putInt(entry.getKey()); + var node = entry.getValue(); + zoneDataType.write(buff, node.getContent()); + + var conns = node.getConnections(); + buff.putInt(conns.size()); + for (Integer conn : conns) { + buff.putInt(conn); + } + } + } + + @Override + public Dungeon read(ByteBuffer buff) { + String name = MVUtils.readString(buff); + + int uid = buff.getInt(); + Graph zones = new Graph<>(); + int graphSize = buff.getInt(); + for (int i = 0; i < graphSize; i++) { + int index = buff.getInt(); + Zone zone = zoneDataType.read(buff); + zones.addNode(index, zone); + Graph.Node node = zones.getNode(index); + int numConnections = buff.getInt(); + for (int j = 0; j < numConnections; j++) { + int connection = buff.getInt(); + node.addConnection(connection); + } + } + return new Dungeon(name, uid, zones, zoneFactory); + } - public void writeExternal(ObjectOutput out) throws IOException { - out.writeUTF(name); - out.writeInt(uid); - out.writeObject(zones); + /** + * Create storage object of array type to hold values + * + * @param size number of values to hold + * @return storage object + */ + @Override + public Dungeon[] createStorage(int size) { + return new Dungeon[size]; + } } } diff --git a/src/main/java/neon/maps/Map.java b/src/main/java/neon/maps/Map.java index f0e7390..7bc4121 100644 --- a/src/main/java/neon/maps/Map.java +++ b/src/main/java/neon/maps/Map.java @@ -18,7 +18,6 @@ package neon.maps; -import java.io.Externalizable; import java.util.*; /** @@ -26,7 +25,7 @@ * * @author mdriesen */ -public interface Map extends Externalizable { +public interface Map { /** * @return the name of this map */ diff --git a/src/main/java/neon/maps/MapLoader.java b/src/main/java/neon/maps/MapLoader.java index ec63abf..f3cebcd 100644 --- a/src/main/java/neon/maps/MapLoader.java +++ b/src/main/java/neon/maps/MapLoader.java @@ -21,6 +21,7 @@ import java.awt.Point; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import lombok.Setter; import neon.core.*; import neon.entities.*; import neon.entities.components.Enchantment; @@ -48,7 +49,7 @@ public class MapLoader { private final ResourceManager resourceManager; private final FileSystem fileSystem; private final ZoneFactory zoneFactory; - private Player player; + @Setter private Player player; /** Creates a MapLoader with dependency injection. */ public MapLoader( @@ -178,7 +179,7 @@ public Dungeon loadThemedDungeon(String name, String dungeonTheme, int uid) { * @return the constructed World */ private World buildWorldFromModel(WorldModel model, int uid) { - World world = new World(model.header.name, uid); + World world = new World(model.header.name, uid, zoneFactory); Zone zone = world.getZone(0); // outdoor maps have only zone 0 ItemFactory itemFactory = new ItemFactory(resourceManager); CreatureFactory creatureFactory = new CreatureFactory(resourceManager, uidStore, player); diff --git a/src/main/java/neon/maps/Region.java b/src/main/java/neon/maps/Region.java index 5977dc3..a543f8b 100644 --- a/src/main/java/neon/maps/Region.java +++ b/src/main/java/neon/maps/Region.java @@ -19,11 +19,11 @@ package neon.maps; import java.awt.*; -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; import java.util.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; import neon.resources.RRegionTheme; import neon.resources.RTerrain; import neon.systems.scripting.Activator; @@ -36,7 +36,9 @@ * * @author mdriesen */ -public class Region implements Renderable, Activator, Externalizable { +@Builder +@AllArgsConstructor +public class Region implements Renderable, Activator { public enum Modifier { NONE, SWIM, @@ -47,10 +49,22 @@ public enum Modifier { } // TODO: destructable muren (opgeven welk terrein het wordt na destructie) - protected String id, label; - protected int x, y, z, width, height; - private ArrayList scripts = new ArrayList(); - protected RRegionTheme theme; + protected String id; + @Setter @Getter protected String label; + @Getter protected int x; + @Getter protected int y; + @Setter @Getter protected int z; + @Getter protected int width; + @Getter protected int height; + private final ArrayList scripts = new ArrayList<>(); + + /** + * -- GETTER -- + * + * @return the type of this region for random generation + */ + @Getter protected RRegionTheme theme; + private RTerrain terrain; /** @@ -78,10 +92,6 @@ public Region( public Region() {} - public void setLabel(String label) { - this.label = label; - } - /** Sets whether this region should be random generated, or can be used as it is. */ public void fix() { theme = null; @@ -91,14 +101,6 @@ public String getTextureType() { return id; } - public int getHeight() { - return height; - } - - public int getWidth() { - return width; - } - /** * @return false if this region should be randomly generated, false * otherwise @@ -107,29 +109,10 @@ public boolean isFixed() { return theme == null; } - public int getZ() { - return z; - } - - public int getY() { - return y; - } - - public int getX() { - return x; - } - public Color getColor() { return ColorFactory.getColor(terrain.color); } - /** - * @return the type of this region for random generation - */ - public RRegionTheme getTheme() { - return theme; - } - /** * @return the movement modifier, determining how creatures move over this type of terrain */ @@ -137,11 +120,7 @@ public Modifier getMovMod() { return terrain.modifier; } - /** - * An active region is one which has scripts added to it. - * - * @return - */ + /** An active region is one which has scripts added to it. */ public boolean isActive() { return !scripts.isEmpty(); } @@ -169,53 +148,10 @@ public String toString() { return terrain.description.isEmpty() ? id : terrain.description; } - public void setZ(int z) { - this.z = z; - } - /** * @return the bounding rectangle of this region */ public Rectangle getBounds() { return new Rectangle(x, y, width, height); } - - public String getLabel() { - return label; - } - - public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { - // theme = (RRegionTheme) Engine.getResources().getResource(input.readUTF(), "theme"); - // label = input.readUTF(); - // if (label.isEmpty()) { - // label = null; - // } - // id = input.readUTF(); - // terrain = (RTerrain) Engine.getResources().getResource(id, "terrain"); - // x = input.readInt(); - // y = input.readInt(); - // z = input.readInt(); - // width = input.readInt(); - // height = input.readInt(); - // int size = input.readInt(); - // scripts = new ArrayList(); - // for (int i = 0; i < size; i++) { - // scripts.add(input.readUTF()); - // } - } - - public void writeExternal(ObjectOutput output) throws IOException { - output.writeUTF(theme != null ? theme.id : ""); - output.writeUTF(label != null ? label : ""); - output.writeUTF(id); - output.writeInt(x); - output.writeInt(y); - output.writeInt(z); - output.writeInt(width); - output.writeInt(height); - output.writeInt(scripts.size()); - for (String script : scripts) { - output.writeUTF(script); - } - } } diff --git a/src/main/java/neon/maps/World.java b/src/main/java/neon/maps/World.java index 2de8c2f..22413f1 100644 --- a/src/main/java/neon/maps/World.java +++ b/src/main/java/neon/maps/World.java @@ -18,9 +18,6 @@ package neon.maps; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; import java.util.*; import lombok.Getter; import lombok.Setter; @@ -33,7 +30,7 @@ public class World implements Map { @Getter @Setter private String name; private int uid; - private Zone zone; + @Getter private Zone zone; /** * Initializes this {@code World} with the given parameters. @@ -41,9 +38,22 @@ public class World implements Map { * @param name the name of this map * @param uid the uid of this map */ - public World(String name, int uid) { + public World(String name, int uid, ZoneFactory zoneFactory) { this.name = name; this.uid = uid; + this.zone = zoneFactory.createZone("world", uid, 0); + } + + /** + * Initializes this {@code World} with the given parameters. + * + * @param name the name of this map + * @param uid the uid of this map + */ + public World(String name, int uid, Zone zone) { + this.name = name; + this.uid = uid; + this.zone = zone; } public World() {} @@ -59,16 +69,4 @@ public int getUID() { public Collection getZones() { return List.of(zone); } - - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - name = in.readUTF(); - uid = in.readInt(); - zone = (Zone) in.readObject(); - } - - public void writeExternal(ObjectOutput out) throws IOException { - out.writeUTF(name); - out.writeInt(uid); - out.writeObject(zone); - } } diff --git a/src/main/java/neon/maps/Zone.java b/src/main/java/neon/maps/Zone.java index e30915b..bea76c9 100644 --- a/src/main/java/neon/maps/Zone.java +++ b/src/main/java/neon/maps/Zone.java @@ -177,6 +177,10 @@ public void addCreature(Creature c) { creatures.insert(c.getUID(), bounds); } + public void addCreature(long uid, Rectangle bounds) { + creatures.insert(uid, bounds); + } + /** * @return the height of this zone */ @@ -299,6 +303,14 @@ public void removeItem(Item item) { } } + public int getTopSize() { + return top.size(); + } + + public Collection getTopElements() { + return top.getElements(); + } + /** * @return a hashmap with all lights in this zone */ @@ -306,6 +318,12 @@ public HashMap getLightMap() { return lights; } + public int getEstimatedMemory() { + return 32 + + (top.getElements().size() + creatures.getElements().size() + items.getElements().size()) + * 8; + } + // public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // index = in.readInt(); // map = in.readInt(); diff --git a/src/main/java/neon/maps/ZoneFactory.java b/src/main/java/neon/maps/ZoneFactory.java index c94a678..203377d 100644 --- a/src/main/java/neon/maps/ZoneFactory.java +++ b/src/main/java/neon/maps/ZoneFactory.java @@ -18,12 +18,21 @@ package neon.maps; +import java.awt.*; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.nio.ByteBuffer; import neon.core.GameStores; +import neon.entities.Item; import neon.entities.UIDStore; +import neon.maps.mvstore.MVUtils; +import neon.maps.mvstore.RegionDataType; import neon.resources.RZoneTheme; import neon.resources.ResourceManager; import neon.util.mapstorage.MapStore; import neon.util.spatial.RTree; +import org.h2.mvstore.WriteBuffer; /** * Factory for creating Zone instances with proper dependency injection. Eliminates the constructor @@ -35,6 +44,7 @@ public class ZoneFactory { private final MapStore cache; private final UIDStore uidStore; private final ResourceManager resourceManager; + private final RegionDataType regionDataType; /** * Creates a new ZoneFactory with the given cache database. @@ -45,6 +55,7 @@ public ZoneFactory(MapStore cache, UIDStore uidStore, ResourceManager resourceMa this.cache = cache; this.uidStore = uidStore; this.resourceManager = resourceManager; + this.regionDataType = new RegionDataType(resourceManager); } public ZoneFactory(GameStores gameStore) { @@ -52,12 +63,140 @@ public ZoneFactory(GameStores gameStore) { } public Zone createZone(String name, int map, int index) { - RTree regions = new RTree<>(100, 40, cache, map + ":" + index); + RTree regions = new RTree<>(100, 40, cache, map + ":" + index, regionDataType); return new Zone(name, map, index, uidStore, resourceManager, regions); } public Zone createZoneWithTheme(String name, int map, int index, RZoneTheme theme) { - RTree regions = new RTree<>(100, 40, cache, map + ":" + index); + RTree regions = new RTree<>(100, 40, cache, map + ":" + index, regionDataType); return new Zone(name, map, theme, index, uidStore, resourceManager, regions); } + + public Zone readZoneFromExternal(ObjectInput in) throws IOException, ClassNotFoundException { + int index = in.readInt(); + int map = in.readInt(); + String name = in.readUTF(); + String t = in.readUTF(); + Zone theZone; + if (!t.isEmpty()) { + RZoneTheme theme = (RZoneTheme) resourceManager.getResource(t, "theme"); + theZone = createZoneWithTheme(name, map, index, theme); + } else { + theZone = createZone(name, map, index); + } + + int iSize = in.readInt(); + for (int i = 0; i < iSize; i++) { + long uid = in.readLong(); + Item item = (Item) uidStore.getEntity(uid); + theZone.addItem(item); + } + int tSize = in.readInt(); + for (int i = 0; i < tSize; i++) { + long uid = in.readLong(); + Item item = (Item) uidStore.getEntity(uid); + theZone.addItem(item); + } + + int cSize = in.readInt(); + for (int i = 0; i < cSize; i++) { + long uid = in.readLong(); + Rectangle bounds = uidStore.getEntity(uid).getShapeComponent(); + theZone.addCreature(uid, bounds); + } + + return theZone; + } + + public Zone readZoneByteBuffer(ByteBuffer in) throws IOException, ClassNotFoundException { + int index = in.getInt(); + int map = in.getInt(); + String name = MVUtils.readString(in); + String t = MVUtils.readString(in); + Zone theZone; + if (t != null) { + RZoneTheme theme = (RZoneTheme) resourceManager.getResource(t, "theme"); + theZone = createZoneWithTheme(name, map, index, theme); + } else { + theZone = createZone(name, map, index); + } + + int iSize = in.getInt(); + for (int i = 0; i < iSize; i++) { + long uid = in.getLong(); + Item item = (Item) uidStore.getEntity(uid); + theZone.addItem(item); + } + int tSize = in.getInt(); + for (int i = 0; i < tSize; i++) { + long uid = in.getLong(); + Item item = (Item) uidStore.getEntity(uid); + theZone.addItem(item); + } + + int cSize = in.getInt(); + for (int i = 0; i < cSize; i++) { + long uid = in.getLong(); + Rectangle bounds = uidStore.getEntity(uid).getShapeComponent(); + theZone.addCreature(uid, bounds); + } + + return theZone; + } + + public void writeZoneToWriteBuffer(WriteBuffer out, Zone zone) throws IOException { + out.putInt(zone.getIndex()); + out.putInt(zone.getMap()); + MVUtils.writeString(out, zone.getName()); + + if (zone.getTheme() != null) { + MVUtils.writeString(out, zone.getTheme().id); + + } else { + MVUtils.writeString(out, null); + } + + // items + out.putInt(zone.getItems().size()); + for (long l : zone.getItems()) { + out.putLong(l); + } + out.putInt(zone.getTopSize()); + for (long l : zone.getTopElements()) { + out.putLong(l); + } + + // creatures + out.putInt(zone.getCreatures().size()); + for (long l : zone.getCreatures()) { + out.putLong(l); + } + } + + public void writeZoneToExternal(ObjectOutput out, Zone zone) throws IOException { + out.writeInt(zone.getIndex()); + out.writeInt(zone.getMap()); + out.writeUTF(zone.getName()); + if (zone.getTheme() != null) { + out.writeUTF(zone.getTheme().id); + } else { + out.writeUTF(""); + } + + // items + out.writeInt(zone.getItems().size()); + for (long l : zone.getItems()) { + out.writeLong(l); + } + out.writeInt(zone.getTopSize()); + for (long l : zone.getTopElements()) { + out.writeLong(l); + } + + // creatures + out.writeInt(zone.getCreatures().size()); + for (long l : zone.getCreatures()) { + out.writeLong(l); + } + } } diff --git a/src/main/java/neon/maps/generators/TownGenerator.java b/src/main/java/neon/maps/generators/TownGenerator.java index 6e8c7d2..f84dd05 100644 --- a/src/main/java/neon/maps/generators/TownGenerator.java +++ b/src/main/java/neon/maps/generators/TownGenerator.java @@ -70,35 +70,7 @@ public TownGenerator( this.resourceProvider = resourceProvider; this.mapUtils = mapUtils; - // Create minimal GameStores wrapper for ItemFactory - neon.core.GameStores gameStores = - new neon.core.GameStores() { - @Override - public neon.maps.Atlas getAtlas() { - return null; - } - - @Override - public neon.entities.UIDStore getStore() { - return entityStore; - } - - @Override - public neon.resources.ResourceManager getResources() { - return resourceProvider; - } - - @Override - public neon.systems.files.FileSystem getFileSystem() { - return null; - } - - @Override - public neon.maps.ZoneFactory getZoneFactory() { - return null; - } - }; - itemFactory = new ItemFactory(gameStores.getResources()); + itemFactory = new ItemFactory(resourceProvider); } /** diff --git a/src/main/java/neon/maps/generators/WildernessTerrainGenerator.java b/src/main/java/neon/maps/generators/WildernessTerrainGenerator.java index 4d8ed50..af0c77d 100644 --- a/src/main/java/neon/maps/generators/WildernessTerrainGenerator.java +++ b/src/main/java/neon/maps/generators/WildernessTerrainGenerator.java @@ -38,7 +38,7 @@ public String[][] generateTerrainOnly(Rectangle r, RRegionTheme theme, String ba } String[][] generateTerrain(int width, int height, RRegionTheme theme, String base) { - String[][] terrain = new String[width][height]; + String[][] terrain = new String[width + 2][height + 2]; // create terrain and vegetation switch (theme.type) { case CHAOTIC: diff --git a/src/main/java/neon/maps/mvstore/IntegerDataType.java b/src/main/java/neon/maps/mvstore/IntegerDataType.java new file mode 100644 index 0000000..7329b72 --- /dev/null +++ b/src/main/java/neon/maps/mvstore/IntegerDataType.java @@ -0,0 +1,71 @@ +package neon.maps.mvstore; + +import java.nio.ByteBuffer; +import org.h2.mvstore.DataUtils; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.BasicDataType; + +public class IntegerDataType extends BasicDataType { + + public static final IntegerDataType INSTANCE = new IntegerDataType(); + + private static final Integer[] EMPTY_INTEGER_ARR = new Integer[0]; + + private IntegerDataType() {} + + @Override + public int getMemory(Integer obj) { + return 4; + } + + @Override + public void write(WriteBuffer buff, Integer data) { + buff.putVarInt(data); + } + + @Override + public Integer read(ByteBuffer buff) { + return DataUtils.readVarInt(buff); + } + + @Override + public Integer[] createStorage(int size) { + return size == 0 ? EMPTY_INTEGER_ARR : new Integer[size]; + } + + @Override + public int compare(Integer one, Integer two) { + return Integer.compare(one, two); + } + + @Override + public int binarySearch(Integer keyObj, Object storageObj, int size, int initialGuess) { + int key = keyObj; + Integer[] storage = cast(storageObj); + int low = 0; + int high = size - 1; + // the cached index minus one, so that + // for the first time (when cachedCompare is 0), + // the default value is used + int x = initialGuess - 1; + if (x < 0 || x > high) { + x = high >>> 1; + } + return binarySearch(key, storage, low, high, x); + } + + private static int binarySearch(int key, Integer[] storage, int low, int high, int x) { + while (low <= high) { + long midVal = storage[x]; + if (key > midVal) { + low = x + 1; + } else if (key < midVal) { + high = x - 1; + } else { + return x; + } + x = (low + high) >>> 1; + } + return -(low + 1); + } +} diff --git a/src/main/java/neon/maps/mvstore/MVUtils.java b/src/main/java/neon/maps/mvstore/MVUtils.java new file mode 100644 index 0000000..7c638e0 --- /dev/null +++ b/src/main/java/neon/maps/mvstore/MVUtils.java @@ -0,0 +1,26 @@ +package neon.maps.mvstore; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import org.h2.mvstore.WriteBuffer; + +public class MVUtils { + public static void writeString(WriteBuffer buffer, String str) { + if (str == null) { + buffer.putInt(-1); + } else { + buffer.putInt(str.getBytes(StandardCharsets.UTF_8).length); + buffer.put(str.getBytes(StandardCharsets.UTF_8)); + } + } + + public static String readString(ByteBuffer buffer) { + int length = buffer.getInt(); + if (length < 0) { + return null; + } + byte[] bytes = new byte[length]; + buffer.get(bytes); + return new String(bytes, StandardCharsets.UTF_8); + } +} diff --git a/src/main/java/neon/maps/mvstore/MapDataType.java b/src/main/java/neon/maps/mvstore/MapDataType.java new file mode 100644 index 0000000..8287422 --- /dev/null +++ b/src/main/java/neon/maps/mvstore/MapDataType.java @@ -0,0 +1,62 @@ +package neon.maps.mvstore; + +import java.nio.ByteBuffer; +import neon.maps.Dungeon; +import neon.maps.Map; +import neon.maps.World; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.BasicDataType; + +public class MapDataType extends BasicDataType { + private final WorldDataType worldDataType; + private final Dungeon.DungeonDataType dungeonDataType; + + final int WORLDTYPE = 1; + final int DUNGEONTYPE = 2; + + public MapDataType(WorldDataType worldDataType, Dungeon.DungeonDataType dungeonDataType) { + this.worldDataType = worldDataType; + this.dungeonDataType = dungeonDataType; + } + + @Override + public int getMemory(Map obj) { + if (obj instanceof World world) { + return worldDataType.getMemory(world); + } else if (obj instanceof Dungeon dungeon) { + return dungeonDataType.getMemory(dungeon); + } else throw new UnsupportedOperationException("MV DataType not found for " + obj); + } + + @Override + public void write(WriteBuffer buff, Map obj) { + if (obj instanceof World world) { + buff.putInt(WORLDTYPE); + worldDataType.write(buff, world); + } else if (obj instanceof Dungeon dungeon) { + buff.putInt(DUNGEONTYPE); + dungeonDataType.write(buff, dungeon); + } else throw new UnsupportedOperationException("MV DataType not found for " + obj); + } + + @Override + public Map read(ByteBuffer buff) { + int type = buff.getInt(); + if (type == WORLDTYPE) { + return worldDataType.read(buff); + } else if (type == DUNGEONTYPE) { + return dungeonDataType.read(buff); + } else throw new UnsupportedOperationException("Unrecognized map type " + type); + } + + /** + * Create storage object of array type to hold values + * + * @param size number of values to hold + * @return storage object + */ + @Override + public Map[] createStorage(int size) { + return new Map[size]; + } +} diff --git a/src/main/java/neon/maps/mvstore/MvStoreFactory.java b/src/main/java/neon/maps/mvstore/MvStoreFactory.java new file mode 100644 index 0000000..a8917f4 --- /dev/null +++ b/src/main/java/neon/maps/mvstore/MvStoreFactory.java @@ -0,0 +1,3 @@ +package neon.maps.mvstore; + +public class MvStoreFactory {} diff --git a/src/main/java/neon/maps/mvstore/RegionDataType.java b/src/main/java/neon/maps/mvstore/RegionDataType.java new file mode 100644 index 0000000..d5f6361 --- /dev/null +++ b/src/main/java/neon/maps/mvstore/RegionDataType.java @@ -0,0 +1,73 @@ +package neon.maps.mvstore; + +import static neon.maps.mvstore.MVUtils.readString; + +import java.nio.ByteBuffer; +import neon.maps.Region; +import neon.maps.services.ResourceProvider; +import neon.resources.RRegionTheme; +import neon.resources.RTerrain; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.BasicDataType; +import org.h2.mvstore.type.DataType; + +public class RegionDataType extends BasicDataType implements DataType { + private final ResourceProvider resourceProvider; + + public RegionDataType(ResourceProvider resourceProvider) { + this.resourceProvider = resourceProvider; + } + + @Override + public int getMemory(Region obj) { + return 0; + } + + @Override + public void write(WriteBuffer output, Region obj) { + MVUtils.writeString(output, obj.getTheme() != null ? obj.getTheme().id : ""); + MVUtils.writeString(output, obj.getLabel()); + MVUtils.writeString(output, obj.getTextureType()); + output.putInt(obj.getX()); + output.putInt(obj.getY()); + output.putInt(obj.getZ()); + output.putInt(obj.getWidth()); + output.putInt(obj.getHeight()); + output.putInt(obj.getScripts().size()); + for (String script : obj.getScripts()) { + MVUtils.writeString(output, script); + } + } + + @Override + public Region read(ByteBuffer buff) { + var builder = Region.builder(); + RRegionTheme theme = (RRegionTheme) resourceProvider.getResource(readString(buff), "theme"); + builder.theme(theme); + builder.label(readString(buff)); + builder.terrain((RTerrain) resourceProvider.getResource(readString(buff), "terrain")); + builder + .x(buff.getInt()) + .y(buff.getInt()) + .z(buff.getInt()) + .width(buff.getInt()) + .height(buff.getInt()); + Region region = builder.build(); + int size = buff.getInt(); + for (int i = 0; i < size; i++) { + region.addScript(readString(buff), false); + } + return region; + } + + /** + * Create storage object of array type to hold values + * + * @param size number of values to hold + * @return storage object + */ + @Override + public Region[] createStorage(int size) { + return new Region[size]; + } +} diff --git a/src/main/java/neon/maps/mvstore/WorldDataType.java b/src/main/java/neon/maps/mvstore/WorldDataType.java new file mode 100644 index 0000000..937299e --- /dev/null +++ b/src/main/java/neon/maps/mvstore/WorldDataType.java @@ -0,0 +1,49 @@ +package neon.maps.mvstore; + +import java.nio.ByteBuffer; +import neon.maps.World; +import neon.maps.Zone; +import neon.maps.ZoneFactory; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.BasicDataType; + +public class WorldDataType extends BasicDataType { + private final ZoneFactory zoneFactory; + private final ZoneType zoneType; + + public WorldDataType(ZoneFactory zoneFactory) { + this.zoneFactory = zoneFactory; + this.zoneType = new ZoneType(zoneFactory); + } + + @Override + public int getMemory(World obj) { + return 0; + } + + @Override + public void write(WriteBuffer buff, World obj) { + MVUtils.writeString(buff, obj.getName()); + buff.putInt(obj.getUID()); + zoneType.write(buff, obj.getZone()); + } + + @Override + public World read(ByteBuffer buff) { + String name = MVUtils.readString(buff); + int uid = buff.getInt(); + Zone zone = zoneType.read(buff); + return new World(name, uid, zone); + } + + /** + * Create storage object of array type to hold values + * + * @param size number of values to hold + * @return storage object + */ + @Override + public World[] createStorage(int size) { + return new World[size]; + } +} diff --git a/src/main/java/neon/maps/mvstore/ZoneType.java b/src/main/java/neon/maps/mvstore/ZoneType.java new file mode 100644 index 0000000..0bd8a97 --- /dev/null +++ b/src/main/java/neon/maps/mvstore/ZoneType.java @@ -0,0 +1,131 @@ +package neon.maps.mvstore; + +import java.awt.*; +import java.io.IOException; +import java.nio.ByteBuffer; +import neon.maps.Zone; +import neon.maps.ZoneFactory; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.DataType; + +public class ZoneType implements DataType { + + private final ZoneFactory zoneFactory; + + public ZoneType(ZoneFactory zoneFactory) { + this.zoneFactory = zoneFactory; + } + + /** + * Compare two keys. + * + * @param a the first key + * @param b the second key + * @return -1 if the first key is smaller, 1 if larger, and 0 if equal + * @throws UnsupportedOperationException if the type is not orderable + */ + @Override + public int compare(Zone a, Zone b) { + return 0; + } + + /** + * Perform binary search for the key within the storage + * + * @param key to search for + * @param storage to search within (an array of type T) + * @param size number of data items in the storage + * @param initialGuess for key position + * @return index of the key , if found, - index of the insertion point, if not + */ + @Override + public int binarySearch(Zone key, Object storage, int size, int initialGuess) { + return 0; + } + + /** + * Calculates the amount of used memory in bytes. + * + * @param obj the object + * @return the used memory + */ + @Override + public int getMemory(Zone obj) { + return obj.getEstimatedMemory(); + } + + /** + * Whether memory estimation based on previously seen values is allowed/desirable + * + * @return true if memory estimation is allowed + */ + @Override + public boolean isMemoryEstimationAllowed() { + return false; + } + + /** + * Write an object. + * + * @param out the target buffer + * @param zone the value + */ + @Override + public void write(WriteBuffer out, Zone zone) { + try { + zoneFactory.writeZoneToWriteBuffer(out, zone); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Write a list of objects. + * + * @param buff the target buffer + * @param storage the objects + * @param len the number of objects to write + */ + @Override + public void write(WriteBuffer buff, Object storage, int len) { + throw new IllegalStateException("Not implemented"); + } + + /** + * Read an object. + * + * @param in the source buffer + * @return the object + */ + @Override + public Zone read(ByteBuffer in) { + try { + return zoneFactory.readZoneByteBuffer(in); + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + /** + * Read a list of objects. + * + * @param buff the target buffer + * @param storage the objects + * @param len the number of objects to read + */ + @Override + public void read(ByteBuffer buff, Object storage, int len) { + throw new IllegalStateException("Not implemented"); + } + + /** + * Create storage object of array type to hold values + * + * @param size number of values to hold + * @return storage object + */ + @Override + public Zone[] createStorage(int size) { + return new Zone[size]; + } +} diff --git a/src/main/java/neon/util/Graph.java b/src/main/java/neon/util/Graph.java index 62cc4f9..514beb7 100644 --- a/src/main/java/neon/util/Graph.java +++ b/src/main/java/neon/util/Graph.java @@ -20,9 +20,8 @@ import java.io.Serial; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; +import java.util.*; +import lombok.Getter; public class Graph implements Serializable { @Serial private static final long serialVersionUID = -6431348687813884897L; @@ -58,11 +57,19 @@ public void addConnection(int from, int to, boolean bidirectional) { * @param index * @return the content of the node with the given index */ - public T getNode(int index) { + public T getNodeContent(int index) { // System.out.println(index); return nodes.get(index).content; } + /** + * @param index + * @return the node with the given index + */ + public Node getNode(int index) { + return nodes.get(index); + } + /** * @param index * @return all connections leaving the node with the given index @@ -86,17 +93,25 @@ public Collection getNodes() { return content; } - private static class Node implements Serializable { + public Collection>> getGraphContent() { + return nodes.entrySet(); + } + + public static class Node implements Serializable { @Serial private static final long serialVersionUID = 2326885959259937816L; - private final T content; + @Getter private final T content; private final ArrayList connections = new ArrayList(); - private Node(T content) { + public Node(T content) { this.content = content; } - private void addConnection(int to) { + public void addConnection(int to) { connections.add(to); } + + public List getConnections() { + return Collections.unmodifiableList(connections); + } } } diff --git a/src/main/java/neon/util/mapstorage/MapStore.java b/src/main/java/neon/util/mapstorage/MapStore.java index 46dc80e..16fdbc8 100644 --- a/src/main/java/neon/util/mapstorage/MapStore.java +++ b/src/main/java/neon/util/mapstorage/MapStore.java @@ -2,6 +2,7 @@ import java.util.Collection; import java.util.concurrent.ConcurrentMap; +import org.h2.mvstore.type.DataType; public interface MapStore { void close(); @@ -10,6 +11,8 @@ public interface MapStore { ConcurrentMap openMap(String filename); + ConcurrentMap openMap(String filename, DataType keyType, DataType valueType); + boolean isClosed(); Collection getMapNames(); diff --git a/src/main/java/neon/util/mapstorage/MapStoreMVStoreAdapter.java b/src/main/java/neon/util/mapstorage/MapStoreMVStoreAdapter.java index dc2dd4a..626c6b1 100644 --- a/src/main/java/neon/util/mapstorage/MapStoreMVStoreAdapter.java +++ b/src/main/java/neon/util/mapstorage/MapStoreMVStoreAdapter.java @@ -2,7 +2,10 @@ import java.util.Collection; import java.util.concurrent.ConcurrentMap; +import org.h2.mvstore.MVMap; import org.h2.mvstore.MVStore; +import org.h2.mvstore.type.DataType; +import org.jetbrains.annotations.NotNull; public class MapStoreMVStoreAdapter implements MapStore { private final MVStore mvStore; @@ -26,6 +29,13 @@ public ConcurrentMap openMap(String filename) { return mvStore.openMap(filename); } + @Override + public ConcurrentMap openMap( + String filename, @NotNull DataType keyType, @NotNull DataType valueType) { + return mvStore.openMap( + filename, new MVMap.Builder().keyType(keyType).valueType(valueType)); + } + @Override public boolean isClosed() { return mvStore.isClosed(); diff --git a/src/main/java/neon/util/spatial/RTree.java b/src/main/java/neon/util/spatial/RTree.java index 6d0572f..6c428fd 100644 --- a/src/main/java/neon/util/spatial/RTree.java +++ b/src/main/java/neon/util/spatial/RTree.java @@ -24,7 +24,9 @@ import java.util.*; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicInteger; +import neon.maps.mvstore.IntegerDataType; import neon.util.mapstorage.MapStore; +import org.h2.mvstore.type.DataType; import org.jetbrains.annotations.NotNull; /** @@ -65,7 +67,7 @@ public RTree(int nodeSize, int fillFactor) throws IllegalArgumentException { * @param nodeSize the requested node size * @param fillFactor the requested fill factor */ - public RTree(int nodeSize, int fillFactor, MapStore db, String name) + public RTree(int nodeSize, int fillFactor, MapStore db, String name, DataType valueType) throws IllegalArgumentException { if (fillFactor > nodeSize / 2) { throw new IllegalArgumentException("Fill factor too high."); @@ -75,7 +77,7 @@ public RTree(int nodeSize, int fillFactor, MapStore db, String name) max = nodeSize; root = new RNode(max, min, this); - objects = db.openMap(name); + objects = db.openMap(name, IntegerDataType.INSTANCE, valueType); if (!objects.isEmpty()) { objectsMaxIndex.set(objects.keySet().stream().mapToInt(x -> x).max().orElse(0)); } diff --git a/src/test/java/neon/editor/JacksonXmlBuilderTest.java b/src/test/java/neon/editor/JacksonXmlBuilderTest.java index 953eeb2..cc391f6 100644 --- a/src/test/java/neon/editor/JacksonXmlBuilderTest.java +++ b/src/test/java/neon/editor/JacksonXmlBuilderTest.java @@ -33,6 +33,7 @@ import neon.util.mapstorage.MapStore; import org.jdom2.Document; import org.jdom2.Element; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -43,14 +44,14 @@ * save operations. */ public class JacksonXmlBuilderTest { - + MapStore store; private DataStore mockStore; private RMod testMod; private JacksonXmlBuilder builder; @BeforeEach public void setUp() throws Exception { - MapStore store = MapDbTestHelper.createInMemoryDB(); + store = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(store); mockStore = new TestDataStore( @@ -59,6 +60,12 @@ public void setUp() throws Exception { builder = new JacksonXmlBuilder(mockStore); } + @AfterEach + public void cleanup() { + TestEngineContext.reset(); + MapDbTestHelper.cleanup(store); + } + @Test public void testGetEventsDoc_EmptyEvents() { Document doc = builder.getEventsDoc(); diff --git a/src/test/java/neon/maps/AtlasIntegrationTest.java b/src/test/java/neon/maps/AtlasIntegrationTest.java index a0f23e4..acb309f 100644 --- a/src/test/java/neon/maps/AtlasIntegrationTest.java +++ b/src/test/java/neon/maps/AtlasIntegrationTest.java @@ -23,6 +23,7 @@ class AtlasIntegrationTest { private MapStore testDb; private Atlas atlas; AtlasPosition atlasPosition; + ZoneFactory zoneFactory; @BeforeEach void setUp() throws Exception { @@ -33,12 +34,14 @@ void setUp() throws Exception { TestEngineContext.getStubFileSystem(), "test-atlas", TestEngineContext.getTestStore(), + TestEngineContext.getTestResources(), TestEngineContext.getMapLoader()); atlasPosition = new AtlasPosition( TestEngineContext.getGameStores(), new QuestTracker(TestEngineContext.getGameStores()), TestEngineContext.getTestContext().getPlayer()); + zoneFactory = TestEngineContext.getTestZoneFactory(); } @AfterEach @@ -53,7 +56,7 @@ void tearDown() { @Test void testZoneUsesAtlasDatabase() { - World world = new World("DB Test World", 1000); + World world = new World("DB Test World", 1000, zoneFactory); atlasPosition.setMap(world); Zone zone = atlasPosition.getCurrentZone(); @@ -75,8 +78,8 @@ void testZoneUsesAtlasDatabase() { @Test void testMultipleZonesShareDatabase() { // Create two worlds - World world1 = new World("World 1", 1001); - World world2 = new World("World 2", 1002); + World world1 = new World("World 1", 1001, zoneFactory); + World world2 = new World("World 2", 1002, zoneFactory); atlasPosition.setMap(world1); Zone zone1 = atlasPosition.getCurrentZone(); @@ -102,7 +105,7 @@ void testMultipleZonesShareDatabase() { @Test void testFullRoundTrip() { // Create a world with populated zone - World world = new World("Round Trip World", 1003); + World world = new World("Round Trip World", 1003, zoneFactory); atlasPosition.setMap(world); Zone zone = atlasPosition.getCurrentZone(); @@ -133,7 +136,7 @@ void testFullRoundTrip() { @Test void testZoneSpatialIndexPersistence() { - World world = new World("Spatial Index World", 1004); + World world = new World("Spatial Index World", 1004, zoneFactory); atlasPosition.setMap(world); Zone zone = atlasPosition.getCurrentZone(); @@ -165,8 +168,8 @@ void testZoneSpatialIndexPersistence() { @Test void testMapSwitchingPreservesData() { // Create two worlds with different data - World world1 = new World("World A", 1005); - World world2 = new World("World B", 1006); + World world1 = new World("World A", 1005, zoneFactory); + World world2 = new World("World B", 1006, zoneFactory); // Populate world1 atlasPosition.setMap(world1); @@ -195,7 +198,7 @@ void testMapSwitchingPreservesData() { @Test void testRegionScriptsPersistThroughAtlas() { - World world = new World("Script World", 1007); + World world = new World("Script World", 1007, zoneFactory); atlasPosition.setMap(world); Zone zone = atlasPosition.getCurrentZone(); @@ -220,7 +223,7 @@ void testRegionScriptsPersistThroughAtlas() { @Test void testLargeWorldIntegration() { - World world = new World("Large World", 1008); + World world = new World("Large World", 1008, zoneFactory); atlasPosition.setMap(world); Zone zone = atlasPosition.getCurrentZone(); @@ -247,7 +250,7 @@ void testLargeWorldIntegration() { @Test void testAtlasHandlesEmptyWorld() { - World emptyWorld = new World("Empty World", 1009); + World emptyWorld = new World("Empty World", 1009, zoneFactory); atlasPosition.setMap(emptyWorld); Zone zone = atlasPosition.getCurrentZone(); @@ -264,7 +267,7 @@ void testAtlasHandlesEmptyWorld() { void testMultipleAtlasInstancesShareTestDb() { // This tests that the testDb created in setUp is properly shared // through TestEngineContext - World world = new World("Shared DB World", 1010); + World world = new World("Shared DB World", 1010, zoneFactory); atlasPosition.setMap(world); Zone zone = atlasPosition.getCurrentZone(); diff --git a/src/test/java/neon/maps/AtlasTest.java b/src/test/java/neon/maps/AtlasTest.java index 994100e..2947bf8 100644 --- a/src/test/java/neon/maps/AtlasTest.java +++ b/src/test/java/neon/maps/AtlasTest.java @@ -21,6 +21,7 @@ class AtlasTest { private MapStore testDb; private Atlas atlas; private AtlasPosition atlasPosition; + private ZoneFactory zoneFactory; @BeforeEach void setUp() throws Exception { @@ -32,6 +33,7 @@ void setUp() throws Exception { TestEngineContext.getGameStores(), TestEngineContext.getQuestTracker(), TestEngineContext.getTestContext().getPlayer()); + zoneFactory = TestEngineContext.getTestZoneFactory(); } @AfterEach @@ -50,7 +52,7 @@ void testConstructorCreatesMapDb() { @Test void testSetMapAddsToCache() { - World world = new World("Test World", 100); + World world = new World("Test World", 100, zoneFactory); atlasPosition.setMap(world); @@ -62,8 +64,8 @@ void testSetMapAddsToCache() { @Test void testGetCurrentMapReturnsSetMap() { - World world1 = new World("World 1", 101); - World world2 = new World("World 2", 102); + World world1 = new World("World 1", 101, zoneFactory); + World world2 = new World("World 2", 102, zoneFactory); atlasPosition.setMap(world1); assertEquals(101, atlasPosition.getCurrentMap().getUID()); @@ -72,29 +74,10 @@ void testGetCurrentMapReturnsSetMap() { assertEquals(102, atlasPosition.getCurrentMap().getUID()); } - @Test - void testGetCurrentZoneReturnsCorrectZone() { - World world = new World("Test World", 103); - atlasPosition.setMap(world); - - Zone zone = atlasPosition.getCurrentZone(); - assertNotNull(zone); - // World creates a zone with hardcoded name "world" - assertEquals("world", zone.getName()); - } - - @Test - void testGetCurrentZoneIndexDefaultsToZero() { - World world = new World("Test World", 104); - atlasPosition.setMap(world); - - assertEquals(0, atlasPosition.getCurrentZoneIndex()); - } - @Test void testMultipleMapsDoNotInterfere() { - World world1 = new World("World 1", 201); - World world2 = new World("World 2", 202); + World world1 = new World("World 1", 201, zoneFactory); + World world2 = new World("World 2", 202, zoneFactory); atlasPosition.setMap(world1); atlasPosition.setMap(world2); @@ -112,7 +95,7 @@ void testMultipleMapsDoNotInterfere() { @Test void testSetMapOnlyAddsToCacheOnce() { - World world = new World("Test World", 300); + World world = new World("Test World", 300, zoneFactory); atlasPosition.setMap(world); atlasPosition.setMap(world); // Second call should not duplicate @@ -125,7 +108,7 @@ void testSetMapOnlyAddsToCacheOnce() { void testCacheWithMultipleMaps() { // Add multiple maps to cache for (int i = 0; i < 10; i++) { - World world = new World("World " + i, 400 + i); + World world = new World("World " + i, 400 + i, zoneFactory); atlasPosition.setMap(world); } @@ -133,22 +116,11 @@ void testCacheWithMultipleMaps() { assertEquals(409, atlasPosition.getCurrentMap().getUID()); // Switch between maps - World world5 = new World("World 5", 405); + World world5 = new World("World 5", 405, zoneFactory); atlasPosition.setMap(world5); assertEquals(405, atlasPosition.getCurrentMap().getUID()); } - @Test - void testWorldWithMultipleZones() { - // Worlds only have one zone, but we can test zone access - World world = new World("Single Zone World", 500); - atlasPosition.setMap(world); - - Zone zone = atlasPosition.getCurrentZone(); - assertNotNull(zone); - assertEquals(0, atlasPosition.getCurrentZoneIndex()); - } - // Note: Dungeon serialization through MapDb requires special handling // This is tested separately in MapSerializationTest using Externalizable methods @@ -161,7 +133,7 @@ void testCachePerformanceWithManyMaps() throws Exception { PerformanceHarness.measure( () -> { for (int i = 0; i < mapCount; i++) { - World world = new World("World " + i, 700 + i); + World world = new World("World " + i, 700 + i, zoneFactory); atlasPosition.setMap(world); } return null; @@ -180,7 +152,7 @@ void testCachePerformanceWithManyMaps() throws Exception { void testCacheRetrievalPerformance() throws Exception { // Add maps to cache for (int i = 0; i < 20; i++) { - World world = new World("World " + i, 800 + i); + World world = new World("World " + i, 800 + i, zoneFactory); atlasPosition.setMap(world); } @@ -204,6 +176,7 @@ void testMapDbPersistsAcrossAtlasInstances() throws IOException { TestEngineContext.getStubFileSystem(), "shared-cache", TestEngineContext.getTestEntityStore(), + TestEngineContext.getTestResources(), TestEngineContext.getMapLoader()); AtlasPosition atlasPosition = new AtlasPosition( @@ -211,7 +184,7 @@ void testMapDbPersistsAcrossAtlasInstances() throws IOException { TestEngineContext.getQuestTracker(), TestEngineContext.getTestContext().getPlayer()); - World world = new World("Persistent World", 900); + World world = new World("Persistent World", 900, zoneFactory); atlasPosition.setMap(world); diff --git a/src/test/java/neon/maps/MapPerformanceTest.java b/src/test/java/neon/maps/MapPerformanceTest.java index 6d5baf0..24616ab 100644 --- a/src/test/java/neon/maps/MapPerformanceTest.java +++ b/src/test/java/neon/maps/MapPerformanceTest.java @@ -405,12 +405,7 @@ void testZoneMultiLayerPerformance() throws Exception { @Test void testAtlasMapCachingPerformance() throws Exception { - Atlas atlas = - new Atlas( - TestEngineContext.getStubFileSystem(), - "test-atlas", - TestEngineContext.getTestStore(), - TestEngineContext.getMapLoader()); + Atlas atlas = TestEngineContext.getTestAtlas(); AtlasPosition atlasPosition = new AtlasPosition( TestEngineContext.getGameStores(), @@ -422,7 +417,7 @@ void testAtlasMapCachingPerformance() throws Exception { PerformanceHarness.measure( () -> { for (int i = 0; i < mapCount; i++) { - World world = new World("World " + i, 2000 + i); + World world = new World("World " + i, 2000 + i, zoneFactory); atlasPosition.setMap(world); } return mapCount; @@ -439,12 +434,7 @@ void testAtlasMapCachingPerformance() throws Exception { @Test void testAtlasMapSwitchingPerformance() throws Exception { - Atlas atlas = - new Atlas( - TestEngineContext.getStubFileSystem(), - "switch-perf-atlas", - TestEngineContext.getTestEntityStore(), - TestEngineContext.getMapLoader()); + Atlas atlas = TestEngineContext.getTestAtlas(); AtlasPosition atlasPosition = new AtlasPosition( TestEngineContext.getGameStores(), @@ -454,7 +444,7 @@ void testAtlasMapSwitchingPerformance() throws Exception { // Create and cache 50 maps List worlds = new ArrayList<>(); for (int i = 0; i < 50; i++) { - World world = new World("World " + i, 3000 + i); + World world = new World("World " + i, 3000 + i, zoneFactory); worlds.add(world); atlasPosition.setMap(world); } @@ -492,7 +482,7 @@ void testAtlasZoneAccessPerformance() throws Exception { TestEngineContext.getQuestTracker(), TestEngineContext.getTestContext().getPlayer()); - World world = new World("Zone Access World", 4000); + World world = new World("Zone Access World", 4000, zoneFactory); atlasPosition.setMap(world); Zone zone = atlasPosition.getCurrentZone(); @@ -531,12 +521,7 @@ void testAtlasZoneAccessPerformance() throws Exception { @Test void testFullMapLoadAndQueryPerformance() throws Exception { - Atlas atlas = - new Atlas( - TestEngineContext.getStubFileSystem(), - "full-perf-atlas", - TestEngineContext.getTestEntityStore(), - TestEngineContext.getMapLoader()); + Atlas atlas = TestEngineContext.getTestAtlas(); AtlasPosition atlasPosition = new AtlasPosition( TestEngineContext.getGameStores(), @@ -547,7 +532,7 @@ void testFullMapLoadAndQueryPerformance() throws Exception { PerformanceHarness.measure( () -> { // Create a large world - World world = new World("Large World", 5000); + World world = new World("Large World", 5000, zoneFactory); atlasPosition.setMap(world); Zone zone = atlasPosition.getCurrentZone(); @@ -608,12 +593,7 @@ void testFullMapLoadAndQueryPerformance() throws Exception { @Test void testMemoryEfficiencyWithLargeMaps() throws Exception { - Atlas atlas = - new Atlas( - TestEngineContext.getStubFileSystem(), - "memory-test-atlas", - TestEngineContext.getTestEntityStore(), - TestEngineContext.getMapLoader()); + Atlas atlas = TestEngineContext.getTestAtlas(); AtlasPosition atlasPosition = new AtlasPosition( TestEngineContext.getGameStores(), @@ -626,7 +606,7 @@ void testMemoryEfficiencyWithLargeMaps() throws Exception { // Create 10 large worlds for (int w = 0; w < 10; w++) { - World world = new World("World " + w, 6000 + w); + World world = new World("World " + w, 6000 + w, zoneFactory); atlasPosition.setMap(world); Zone zone = atlasPosition.getCurrentZone(); diff --git a/src/test/java/neon/maps/MapSerializationTest.java b/src/test/java/neon/maps/MapSerializationTest.java index bdd85ae..3ea3d4b 100644 --- a/src/test/java/neon/maps/MapSerializationTest.java +++ b/src/test/java/neon/maps/MapSerializationTest.java @@ -3,11 +3,14 @@ import static org.junit.jupiter.api.Assertions.*; import java.io.*; +import java.nio.ByteBuffer; import java.util.Collection; +import neon.maps.mvstore.WorldDataType; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; import neon.util.mapstorage.MapStore; +import org.h2.mvstore.WriteBuffer; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -22,12 +25,16 @@ class MapSerializationTest { private MapStore testDb; private ZoneFactory zoneFactory; + private WorldDataType worldDataType; + private Dungeon.DungeonDataType dungeonDataType; @BeforeEach void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); zoneFactory = TestEngineContext.getTestZoneFactory(); + worldDataType = new WorldDataType(zoneFactory); + dungeonDataType = new Dungeon.DungeonDataType(zoneFactory); } @AfterEach @@ -40,7 +47,7 @@ void tearDown() { @Test void testEmptyWorldRoundTrip() throws Exception { - World original = new World("Test World", 100); + World original = new World("Test World", 100, zoneFactory); World deserialized = serializeAndDeserializeWorld(original); @@ -51,7 +58,7 @@ void testEmptyWorldRoundTrip() throws Exception { @Test void testWorldWithRegions() throws Exception { - World original = new World("World With Regions", 101); + World original = new World("World With Regions", 101, zoneFactory); // Add regions to the world's zone Zone zone = original.getZone(0); @@ -73,7 +80,7 @@ void testWorldUIDPreservation() throws Exception { int[] uids = {1, 100, 999, 12345}; for (int uid : uids) { - World original = new World("World-" + uid, uid); + World original = new World("World-" + uid, uid, zoneFactory); World deserialized = serializeAndDeserializeWorld(original); assertEquals(uid, deserialized.getUID()); @@ -82,7 +89,7 @@ void testWorldUIDPreservation() throws Exception { @Test void testWorldZoneDataIntegrity() throws Exception { - World original = new World("Integrity Test", 102); + World original = new World("Integrity Test", 102, zoneFactory); Zone zone = original.getZone(0); // Add various regions @@ -254,7 +261,7 @@ void testDungeonUIDPreservation() throws Exception { @Test void testWorldSerializationPerformance() throws Exception { - World world = new World("Performance World", 300); + World world = new World("Performance World", 300, zoneFactory); Zone zone = world.getZone(0); // Add 100 regions @@ -314,33 +321,22 @@ void testDungeonSerializationPerformance() throws Exception { /** Helper method to serialize and deserialize a World. */ private World serializeAndDeserializeWorld(World original) throws IOException, ClassNotFoundException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - original.writeExternal(oos); - oos.flush(); + WriteBuffer writeBuffer = new WriteBuffer(); + worldDataType.write(writeBuffer, original); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream ois = new ObjectInputStream(bais); - World deserialized = new World(); - deserialized.readExternal(ois); - - return deserialized; + byte[] serialized = writeBuffer.getBuffer().array(); + ByteBuffer readBuffer = ByteBuffer.wrap(serialized); + return worldDataType.read(readBuffer); } /** Helper method to serialize and deserialize a Dungeon. */ private Dungeon serializeAndDeserializeDungeon(Dungeon original) throws IOException, ClassNotFoundException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - original.writeExternal(oos); - oos.flush(); - - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream ois = new ObjectInputStream(bais); - // Dungeon doesn't have no-arg constructor, create with dummy values that will be overwritten - Dungeon deserialized = new Dungeon("temp", 0, zoneFactory); - deserialized.readExternal(ois); - - return deserialized; + WriteBuffer writeBuffer = new WriteBuffer(); + dungeonDataType.write(writeBuffer, original); + + byte[] serialized = writeBuffer.getBuffer().array(); + ByteBuffer readBuffer = ByteBuffer.wrap(serialized); + return dungeonDataType.read(readBuffer); } } diff --git a/src/test/java/neon/maps/MapTestFixtures.java b/src/test/java/neon/maps/MapTestFixtures.java index 98d07f2..87ec71f 100644 --- a/src/test/java/neon/maps/MapTestFixtures.java +++ b/src/test/java/neon/maps/MapTestFixtures.java @@ -1,6 +1,5 @@ package neon.maps; -import java.awt.Rectangle; import neon.entities.Creature; import neon.entities.Door; import neon.entities.Item; @@ -129,74 +128,6 @@ public static Zone createLargeZone(int mapUID, int regionCount) { return zone; } - /** - * Creates an empty world map with the given parameters. - * - * @param name world name - * @param uid world UID - * @return a new World instance - */ - public static World createEmptyWorld(String name, int uid) { - return new World(name, uid); - } - - /** - * Creates an empty world map with default name. - * - * @param uid world UID - * @return a new World instance - */ - public static World createEmptyWorld(int uid) { - return new World("test-world", uid); - } - - /** - * Creates a world map with a single region. - * - * @param uid world UID - * @return a new World instance with one region - */ - public static World createWorldWithSingleRegion(int uid) { - World world = new World("test-world", uid); - Region region = createTestRegion(0, 0, 100, 100); - world.getZone(0).addRegion(region); - return world; - } - - /** - * Creates a world map with multiple regions. - * - * @param uid world UID - * @param regionCount number of regions to add - * @return a new World instance with regions - */ - public static World createWorldWithRegions(int uid, int regionCount) { - World world = new World("test-world", uid); - Zone zone = world.getZone(0); - - for (int i = 0; i < regionCount; i++) { - int x = (i % 10) * 10; - int y = (i / 10) * 10; - Region region = createTestRegion("region-" + i, x, y, 10, 10, 0); - zone.addRegion(region); - } - - return world; - } - - /** - * Creates a bounding rectangle for testing spatial queries. - * - * @param x x-coordinate - * @param y y-coordinate - * @param width width - * @param height height - * @return a new Rectangle - */ - public static Rectangle createBounds(int x, int y, int width, int height) { - return new Rectangle(x, y, width, height); - } - /** * Creates a test creature with basic parameters. * diff --git a/src/test/java/neon/maps/RegionSerializationTest.java b/src/test/java/neon/maps/RegionSerializationTest.java index e474499..67c2216 100644 --- a/src/test/java/neon/maps/RegionSerializationTest.java +++ b/src/test/java/neon/maps/RegionSerializationTest.java @@ -4,10 +4,13 @@ import java.awt.Rectangle; import java.io.*; +import java.nio.ByteBuffer; +import neon.maps.mvstore.RegionDataType; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; import neon.util.mapstorage.MapStore; +import org.h2.mvstore.WriteBuffer; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -21,11 +24,13 @@ class RegionSerializationTest { private MapStore testDb; + private RegionDataType regionDataType; @BeforeEach void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); + regionDataType = new RegionDataType(TestEngineContext.getTestResources()); } @AfterEach @@ -190,20 +195,13 @@ void testBulkRegionSerializationPerformance() throws Exception { } /** Helper method to serialize and deserialize a region. */ - private static Region serializeAndDeserialize(Region original) + private Region serializeAndDeserialize(Region original) throws IOException, ClassNotFoundException { - // Serialize - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - original.writeExternal(oos); - oos.flush(); - - // Deserialize - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream ois = new ObjectInputStream(bais); - Region deserialized = new Region(); - deserialized.readExternal(ois); - - return deserialized; + WriteBuffer writeBuffer = new WriteBuffer(); + regionDataType.write(writeBuffer, original); + + byte[] serialized = writeBuffer.getBuffer().array(); + ByteBuffer readBuffer = ByteBuffer.wrap(serialized); + return regionDataType.read(readBuffer); } } diff --git a/src/test/java/neon/maps/ZoneSerializationTest.java b/src/test/java/neon/maps/ZoneSerializationTest.java index 1373c2e..8f37056 100644 --- a/src/test/java/neon/maps/ZoneSerializationTest.java +++ b/src/test/java/neon/maps/ZoneSerializationTest.java @@ -4,11 +4,13 @@ import java.awt.Rectangle; import java.io.*; +import java.nio.ByteBuffer; import java.util.Collection; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.test.TestEngineContext; import neon.util.mapstorage.MapStore; +import org.h2.mvstore.WriteBuffer; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -27,6 +29,7 @@ class ZoneSerializationTest { @BeforeEach void setUp() throws Exception { testDb = MapDbTestHelper.createInMemoryDB(); + TestEngineContext.initialize(testDb); zoneFactory = TestEngineContext.getTestZoneFactory(); } @@ -216,7 +219,7 @@ void testZoneWithVaryingSizesPerformance() throws Exception { System.out.printf("[PERF] Zone with %d regions: %d ms%n", size, durationMillis); - assertEquals(size, deserialized.getRegions().size()); + assertEquals(zone.getRegions().size(), deserialized.getRegions().size()); } } @@ -274,14 +277,11 @@ private Zone serializeAndDeserialize(Zone original) throws IOException, ClassNot ObjectOutputStream oos = new ObjectOutputStream(baos); // original.writeExternal(oos); oos.flush(); + WriteBuffer writeBuffer = new WriteBuffer(); + zoneFactory.writeZoneToWriteBuffer(writeBuffer, original); - // Deserialize - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream ois = new ObjectInputStream(bais); - // Zone deserialized = zoneFactory.createZone(); - // deserialized.readExternal(ois); - // - // return deserialized; - return null; + byte[] serialized = writeBuffer.getBuffer().array(); + ByteBuffer readBuffer = ByteBuffer.wrap(serialized); + return zoneFactory.readZoneByteBuffer(readBuffer); } } diff --git a/src/test/java/neon/maps/generators/DungeonGeneratorTest.java b/src/test/java/neon/maps/generators/DungeonGeneratorTest.java index fc80a53..7f68420 100644 --- a/src/test/java/neon/maps/generators/DungeonGeneratorTest.java +++ b/src/test/java/neon/maps/generators/DungeonGeneratorTest.java @@ -620,6 +620,7 @@ void setUp() throws Exception { @AfterEach void tearDown() { TestEngineContext.reset(); + MapDbTestHelper.cleanup(testDb); new File("test-store.dat").delete(); new File("testfile3.dat").delete(); } diff --git a/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java b/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java index 20072c8..f1141ca 100644 --- a/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java +++ b/src/test/java/neon/maps/generators/DungeonGeneratorXmlIntegrationTest.java @@ -44,18 +44,24 @@ class DungeonGeneratorXmlIntegrationTest { private static final String THEMES_PATH = "src/test/resources/sampleMod1/themes/"; // ==================== Static Theme Data ==================== - + MapStore testDb; private static Map dungeonThemes; private static Map zoneThemes; ZoneFactory zoneFactory; @BeforeEach void setUp() throws Exception { - MapStore testDb = MapDbTestHelper.createInMemoryDB(); + testDb = MapDbTestHelper.createInMemoryDB(); TestEngineContext.initialize(testDb); zoneFactory = TestEngineContext.getTestZoneFactory(); } + @AfterEach + public void cleanup() { + TestEngineContext.reset(); + MapDbTestHelper.cleanup(testDb); + } + // ==================== Setup ==================== @BeforeAll @@ -352,6 +358,7 @@ void setUp() throws Exception { @AfterEach void tearDown() { TestEngineContext.reset(); + MapDbTestHelper.cleanup(testDb); new File("test-store.dat").delete(); new File("testfile3.dat").delete(); } diff --git a/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java b/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java index e36150c..39190bf 100644 --- a/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java +++ b/src/test/java/neon/maps/generators/WildernessGeneratorIntegrationTest.java @@ -106,12 +106,12 @@ static Stream wildernessThemeProviderSingleSeed() { // ==================== Helper Methods ==================== - private WildernessGenerator createGeneratorForTerrainOnly( + private WildernessTerrainGenerator createGeneratorForTerrainOnly( WildernessScenario scenario, int width, int height) { String[][] terrain = new String[height + 2][width + 2]; MapUtils mapUtils = MapUtils.withSeed(scenario.seed()); Dice dice = Dice.withSeed(scenario.seed()); - return new WildernessGenerator(terrain, null, null, mapUtils, dice); + return new WildernessTerrainGenerator(mapUtils, dice); } // ==================== LAYER 1: Lightweight Terrain Generation Tests ==================== @@ -122,7 +122,7 @@ void generateTerrainOnlyTerrain_withXmlTheme_generatesValidTerrain(WildernessSce // Given int width = 50; int height = 50; - WildernessGenerator generator = createGeneratorForTerrainOnly(scenario, width, height); + var generator = createGeneratorForTerrainOnly(scenario, width, height); // When - Note: WildernessGenerator doesn't have a public generateTerrain() method // We'll test through the generate() method in the full context tests @@ -142,8 +142,8 @@ void generateTerrainOnlyTerrain_isDeterministic(WildernessScenario scenario) { // When: generate twice with same seed // Note: Since generateTerrain is private, we can't test it directly // Determinism will be tested in the full context tests - WildernessGenerator generator1 = createGeneratorForTerrainOnly(scenario, width, height); - WildernessGenerator generator2 = createGeneratorForTerrainOnly(scenario, width, height); + var generator1 = createGeneratorForTerrainOnly(scenario, width, height); + var generator2 = createGeneratorForTerrainOnly(scenario, width, height); // Then: verify both generators created successfully assertNotNull(generator1, "First generator should be created"); diff --git a/src/test/java/neon/test/TestEngineContext.java b/src/test/java/neon/test/TestEngineContext.java index b55659a..29558b1 100644 --- a/src/test/java/neon/test/TestEngineContext.java +++ b/src/test/java/neon/test/TestEngineContext.java @@ -10,7 +10,6 @@ import neon.core.Game; import neon.core.GameStores; import neon.core.event.TaskQueue; -import neon.entities.Entity; import neon.entities.Player; import neon.entities.UIDStore; import neon.entities.components.PhysicsComponent; @@ -23,7 +22,6 @@ import neon.systems.files.FileSystem; import neon.systems.physics.PhysicsSystem; import neon.util.mapstorage.MapStore; -import org.h2.mvstore.MVStore; /** * Test utility for managing Engine singleton dependencies in tests. @@ -93,12 +91,21 @@ public static void initialize(MapStore db) throws Exception { // Create test UIDStore testStore = new neon.entities.UIDStore(getStubFileSystem(), testDb); + // Create test Game using new DI constructor + Player stubPlayer = + new Player( + new RCreature("test"), + "TestPlayer", + Gender.MALE, + Player.Specialisation.combat, + "Warrior", + testStore); // Create test EntityStore // Create stub PhysicsManager and ZoneActivator stubPhysicsManager = new StubPhysicsManager(); - Player stubPlayer = new StubPlayer(); + testZoneActivator = new ZoneActivator(stubPhysicsManager); // Create ZoneFactory for tests @@ -106,12 +113,10 @@ public static void initialize(MapStore db) throws Exception { mapLoader = new MapLoader(getStubFileSystem(), testStore, testResources, testZoneFactory, stubPlayer); // Create test Atlas with dependency injection (doesn't need Engine.game) - testAtlas = new Atlas(getStubFileSystem(), testDb, testStore, mapLoader); + testAtlas = new Atlas(getStubFileSystem(), testDb, testStore, testResources, mapLoader); gameStores = new DefaultGameStores(getTestResources(), getStubFileSystem(), stubPlayer); questTracker = new QuestTracker(gameStores); atlasPosition = new AtlasPosition(gameStores, questTracker, stubPlayer); - // Create test Game using new DI constructor - testGame = new Game(stubPlayer, gameStores, atlasPosition); setStaticField(Engine.class, "game", testGame); @@ -140,7 +145,7 @@ public static void initialize(MapStore db) throws Exception { public static void reset() { try { if (testStore != null) { - testStore.getCache().close(); + testStore.close(); } if (testAtlas != null) { @@ -149,6 +154,14 @@ public static void reset() { if (testDb != null) { testDb.close(); } + if (gameStores.getZoneMapStore() != null) { + gameStores.getZoneMapStore().close(); + } + + if (gameStores.getStore() != null) { + gameStores.getStore().close(); + } + setStaticField(Engine.class, "resources", null); setStaticField(Engine.class, "game", null); setStaticField(Engine.class, "files", null); @@ -192,19 +205,6 @@ private static void setStaticField(Class clazz, String fieldName, Object valu field.set(null, value); } - /** Sets the Atlas's DB field using reflection (it's private). */ - private static void setAtlasDb(Atlas atlas, MVStore db) throws Exception { - - Field dbField = Atlas.class.getDeclaredField("db"); - dbField.setAccessible(true); - dbField.set(atlas, db); - - // Also need to recreate the maps HTreeMap with the new DB - Field mapsField = Atlas.class.getDeclaredField("maps"); - mapsField.setAccessible(true); - mapsField.set(atlas, db.openMap("maps")); - } - /** Stub ResourceManager that returns dummy resources. */ static class StubResourceManager extends ResourceManager implements ResourceProvider {} @@ -214,49 +214,11 @@ public static class StubFileSystem extends FileSystem { private StubFileSystem() throws IOException {} } - public static StubFileSystem createNewStubFileSystem() throws IOException { - return new StubFileSystem(); - } - /** Stub PhysicsSystem (minimal implementation). */ static class StubPhysicsSystem extends PhysicsSystem { // Minimal stub - can be extended if needed } - /** Stub EntityStore for testing. */ - static class StubEntityStore implements EntityStore { - private final neon.entities.UIDStore store; - - public StubEntityStore(neon.entities.UIDStore store) { - this.store = store; - } - - @Override - public Entity getEntity(long uid) { - return store.getEntity(uid); - } - - @Override - public void addEntity(Entity entity) { - store.addEntity(entity); - } - - @Override - public long createNewEntityUID() { - return store.createNewEntityUID(); - } - - @Override - public int createNewMapUID() { - return store.createNewMapUID(); - } - - @Override - public String[] getMapPath(int uid) { - return store.getMapPath(uid); - } - } - /** Stub PhysicsManager for testing. */ static class StubPhysicsManager implements PhysicsManager { @Override @@ -274,25 +236,4 @@ public void register(PhysicsComponent component) { // No-op for tests } } - - /** Stub Player for testing. */ - static class StubPlayer extends Player { - private final PhysicsComponent physicsComponent; - - public StubPlayer() { - super( - new RCreature("test"), - "TestPlayer", - Gender.MALE, - Specialisation.combat, - "Warrior", - getGameStores()); - this.physicsComponent = new PhysicsComponent(0L, new Rectangle(0, 0, 1, 1)); - } - - @Override - public PhysicsComponent getPhysicsComponent() { - return physicsComponent; - } - } } diff --git a/src/test/java/neon/util/spatial/RTreePersistenceTest.java b/src/test/java/neon/util/spatial/RTreePersistenceTest.java index 4dbb767..5edc123 100644 --- a/src/test/java/neon/util/spatial/RTreePersistenceTest.java +++ b/src/test/java/neon/util/spatial/RTreePersistenceTest.java @@ -4,11 +4,14 @@ import java.awt.Point; import java.awt.Rectangle; -import java.io.Serializable; +import java.nio.ByteBuffer; import java.util.ArrayList; +import neon.maps.mvstore.MVUtils; import neon.test.MapDbTestHelper; import neon.test.PerformanceHarness; import neon.util.mapstorage.MapStore; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.BasicDataType; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -46,7 +49,7 @@ void testInMemoryRTreeBasicOperations() { @Test void testMapDbRTreeBasicOperations() { - RTree tree = new RTree<>(10, 2, testDb, "test-tree"); + RTree tree = new RTree<>(10, 2, testDb, "test-tree", TestItemDatatype.INSTANCE); TestItem item1 = new TestItem("item1"); tree.insert(item1, new Rectangle(0, 0, 10, 10)); @@ -60,7 +63,8 @@ void testMapDbRTreeBasicOperations() { @Test void testMapDbRTreeReconstructsFromPersistedData() { // Create tree and insert items - RTree tree1 = new RTree<>(10, 2, testDb, "persistent-tree"); + RTree tree1 = + new RTree<>(10, 2, testDb, "persistent-tree", TestItemDatatype.INSTANCE); for (int i = 0; i < 20; i++) { TestItem item = new TestItem("item-" + i); @@ -70,7 +74,8 @@ void testMapDbRTreeReconstructsFromPersistedData() { testDb.commit(); // Create new tree with same name - should reconstruct from persisted data - RTree tree2 = new RTree<>(10, 2, testDb, "persistent-tree"); + RTree tree2 = + new RTree<>(10, 2, testDb, "persistent-tree", TestItemDatatype.INSTANCE); assertEquals(20, tree2.size()); @@ -81,7 +86,8 @@ void testMapDbRTreeReconstructsFromPersistedData() { @Test void testPointQueriesAfterPersistence() { - RTree tree = new RTree<>(10, 2, testDb, "point-query-tree"); + RTree tree = + new RTree<>(10, 2, testDb, "point-query-tree", TestItemDatatype.INSTANCE); // Insert items at specific locations TestItem item1 = new TestItem("at-origin"); @@ -111,7 +117,8 @@ void testPointQueriesAfterPersistence() { @Test void testRangeQueriesAfterPersistence() { - RTree tree = new RTree<>(10, 2, testDb, "range-query-tree"); + RTree tree = + new RTree<>(10, 2, testDb, "range-query-tree", TestItemDatatype.INSTANCE); // Create a 10x10 grid of items for (int y = 0; y < 10; y++) { @@ -135,7 +142,7 @@ void testRangeQueriesAfterPersistence() { @Test void testLargeDatasetPersistence() { int itemCount = 100; - RTree tree = new RTree<>(10, 2, testDb, "large-tree"); + RTree tree = new RTree<>(10, 2, testDb, "large-tree", TestItemDatatype.INSTANCE); // Insert 100 items for (int i = 0; i < itemCount; i++) { @@ -148,7 +155,7 @@ void testLargeDatasetPersistence() { testDb.commit(); // Create new tree - should reconstruct all items - RTree tree2 = new RTree<>(10, 2, testDb, "large-tree"); + RTree tree2 = new RTree<>(10, 2, testDb, "large-tree", TestItemDatatype.INSTANCE); assertEquals(itemCount, tree2.size()); @@ -160,8 +167,8 @@ void testLargeDatasetPersistence() { @Test void testMultipleTreesSameDb() { // Create two independent trees in the same DB - RTree tree1 = new RTree<>(10, 2, testDb, "tree1"); - RTree tree2 = new RTree<>(10, 2, testDb, "tree2"); + RTree tree1 = new RTree<>(10, 2, testDb, "tree1", TestItemDatatype.INSTANCE); + RTree tree2 = new RTree<>(10, 2, testDb, "tree2", TestItemDatatype.INSTANCE); tree1.insert(new TestItem("tree1-item"), new Rectangle(0, 0, 10, 10)); tree2.insert(new TestItem("tree2-item"), new Rectangle(50, 50, 10, 10)); @@ -174,7 +181,7 @@ void testMultipleTreesSameDb() { // Verify trees are independent ArrayList tree1Items = tree1.getElements(new Rectangle(0, 0, 100, 100)); assertEquals(1, tree1Items.size()); - assertEquals("tree1-item", tree1Items.get(0).name); + // assertEquals("tree1-item", tree1Items.get(0).name); ArrayList tree2Items = tree2.getElements(new Rectangle(0, 0, 100, 100)); assertEquals(1, tree2Items.size()); @@ -200,7 +207,8 @@ void testInMemoryVsMapDbPerformance() throws Exception { PerformanceHarness.MeasuredResult> mapDbResult = PerformanceHarness.measure( () -> { - RTree tree = new RTree<>(10, 2, testDb, "perf-tree"); + RTree tree = + new RTree<>(10, 2, testDb, "perf-tree", TestItemDatatype.INSTANCE); for (int i = 0; i < itemCount; i++) { tree.insert(new TestItem("item-" + i), new Rectangle(i * 5, i * 5, 10, 10)); } @@ -223,7 +231,7 @@ void testInMemoryVsMapDbPerformance() throws Exception { @Test void testSpatialQueryPerformance() throws Exception { // Create tree with 200 items - RTree tree = new RTree<>(10, 2, testDb, "query-perf-tree"); + RTree tree = new RTree<>(10, 2, testDb, "query-perf-tree", TestItemDatatype.INSTANCE); for (int i = 0; i < 200; i++) { int x = (i % 20) * 10; @@ -249,7 +257,7 @@ void testSpatialQueryPerformance() throws Exception { @Test void testBoundingBoxPersistence() { - RTree tree = new RTree<>(10, 2, testDb, "bbox-tree"); + RTree tree = new RTree<>(10, 2, testDb, "bbox-tree", TestItemDatatype.INSTANCE); // Insert items with specific bounds tree.insert(new TestItem("small"), new Rectangle(0, 0, 5, 5)); @@ -259,7 +267,7 @@ void testBoundingBoxPersistence() { testDb.commit(); // Reconstruct tree - RTree tree2 = new RTree<>(10, 2, testDb, "bbox-tree"); + RTree tree2 = new RTree<>(10, 2, testDb, "bbox-tree", TestItemDatatype.INSTANCE); // Verify bounding boxes are preserved by testing queries ArrayList found = tree2.getElements(new Rectangle(0, 0, 3, 3)); @@ -276,8 +284,8 @@ void testBoundingBoxPersistence() { } /** Simple test item for RTree. */ - static class TestItem implements Serializable { - private static final long serialVersionUID = 1L; + static class TestItem { + String name; TestItem(String name) { @@ -302,4 +310,34 @@ public String toString() { return "TestItem[" + name + "]"; } } + + static class TestItemDatatype extends BasicDataType { + public static TestItemDatatype INSTANCE = new TestItemDatatype(); + + @Override + public int getMemory(TestItem obj) { + return 10; + } + + @Override + public void write(WriteBuffer buff, TestItem obj) { + MVUtils.writeString(buff, obj.name); + } + + @Override + public TestItem read(ByteBuffer buff) { + return new TestItem(MVUtils.readString(buff)); + } + + /** + * Create storage object of array type to hold values + * + * @param size number of values to hold + * @return storage object + */ + @Override + public TestItem[] createStorage(int size) { + return new TestItem[size]; + } + } } From c90ae9df165031fb40a9ffc21bc58076911bba9a Mon Sep 17 00:00:00 2001 From: Peter Riewe Date: Wed, 14 Jan 2026 22:57:48 +0000 Subject: [PATCH 07/12] Checkpoint --- .../java/neon/core/DefaultGameStores.java | 17 + src/main/java/neon/entities/UIDStore.java | 510 +++++++++--------- .../entities/mvstore/ByteBufferDataInput.java | 116 ++++ .../mvstore/ByteBufferDataOutput.java | 112 ++++ .../neon/entities/mvstore/EntityDataType.java | 60 +++ .../neon/entities/mvstore/LongDataType.java | 63 +++ .../neon/entities/mvstore/ModDataType.java | 65 +++ .../neon/entities/mvstore/ShortDataType.java | 62 +++ .../serialization/CreatureSerializer.java | 313 ++++++----- .../entities/serialization/EntityFactory.java | 101 ++++ .../serialization/ItemSerializer.java | 2 +- src/main/java/neon/maps/Atlas.java | 3 +- .../neon/systems/files/XMLTranslator.java | 5 +- src/test/java/neon/entities/UIDStoreTest.java | 64 ++- .../java/neon/test/TestEngineContext.java | 2 +- 15 files changed, 1080 insertions(+), 415 deletions(-) create mode 100644 src/main/java/neon/entities/mvstore/ByteBufferDataInput.java create mode 100644 src/main/java/neon/entities/mvstore/ByteBufferDataOutput.java create mode 100644 src/main/java/neon/entities/mvstore/EntityDataType.java create mode 100644 src/main/java/neon/entities/mvstore/LongDataType.java create mode 100644 src/main/java/neon/entities/mvstore/ModDataType.java create mode 100644 src/main/java/neon/entities/mvstore/ShortDataType.java create mode 100644 src/main/java/neon/entities/serialization/EntityFactory.java diff --git a/src/main/java/neon/core/DefaultGameStores.java b/src/main/java/neon/core/DefaultGameStores.java index d7dd52e..d2897e5 100644 --- a/src/main/java/neon/core/DefaultGameStores.java +++ b/src/main/java/neon/core/DefaultGameStores.java @@ -3,6 +3,9 @@ import lombok.Getter; import neon.entities.Player; import neon.entities.UIDStore; +import neon.entities.mvstore.EntityDataType; +import neon.entities.mvstore.ModDataType; +import neon.entities.serialization.EntityFactory; import neon.maps.Atlas; import neon.maps.MapLoader; import neon.maps.ZoneFactory; @@ -23,7 +26,21 @@ public class DefaultGameStores implements GameStores { public DefaultGameStores(ResourceManager resources, FileSystem fileSystem, Player player) { this.resources = resources; this.fileSystem = fileSystem; + + // Phase 1: Create UIDStore without DataTypes this.store = new UIDStore(fileSystem, fileSystem.getFullPath("uidstore")); + + // Phase 2: Create EntityFactory with dependencies (GameContext is null at this stage) + EntityFactory entityFactory = new EntityFactory(this, null); + + // Phase 3: Create DataTypes + EntityDataType entityDataType = new EntityDataType(entityFactory); + ModDataType modDataType = new ModDataType(); + + // Phase 4: Initialize UIDStore's maps with DataTypes + store.setDataTypes(entityDataType, modDataType); + + // Continue with rest of initialization zoneMapStore = Atlas.getMapStore(fileSystem, "zones"); this.zoneFactory = new ZoneFactory(zoneMapStore, store, resources); MapLoader mapLoader = new MapLoader(fileSystem, store, resources, zoneFactory, player); diff --git a/src/main/java/neon/entities/UIDStore.java b/src/main/java/neon/entities/UIDStore.java index 783c84a..7f2dca7 100644 --- a/src/main/java/neon/entities/UIDStore.java +++ b/src/main/java/neon/entities/UIDStore.java @@ -1,249 +1,261 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.entities; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import java.io.*; -import java.util.Map; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import neon.maps.services.EntityStore; -import neon.systems.files.FileSystem; -import neon.util.mapstorage.MapStore; -import neon.util.mapstorage.MapStoreMVStoreAdapter; -import org.h2.mvstore.MVStore; - -/** - * This class stores the UIDs of every object, map and mod currently in the game. It can give out - * new UIDs to objects created during gameplay. Positive UIDs are used in resources loaded from a - * mod. Negative UIDs are reserved for random generation. - * - * @author mdriesen - */ -@Slf4j -public class UIDStore implements EntityStore, Closeable { - // dummy uid for objects that don't actually exist - public static final long DUMMY = 0; - @Getter private final FileSystem fileSystem; - // uid database - @Getter private final MapStore uidDb; - // uids of all objects in the game - private final Map objects; - // uids of all loaded mods - private final Map mods; - // uids of all loaded maps - private final BiMap maps = HashBiMap.create(); - - /** - * Tells this UIDStore to use the given jdbm3 cache. - * - * @param file - */ - public UIDStore(FileSystem fileSystem, String file) { - this.fileSystem = fileSystem; - uidDb = new MapStoreMVStoreAdapter(MVStore.open(file)); - objects = uidDb.openMap("object"); - mods = uidDb.openMap("mods"); - } - - public UIDStore(FileSystem fileSystem, MapStore mapStore) { - this.fileSystem = fileSystem; - uidDb = mapStore; - objects = uidDb.openMap("object"); - mods = uidDb.openMap("mods"); - } - - /** - * @return the jdbm3 cache used by this UIDStore - */ - public MapStore getCache() { - return uidDb; - } - - /** - * @param name the name of a mod - * @return the unique identifier of this mod - */ - public short getModUID(String name) { - for (Mod mod : mods.values()) { - if (mod.name.equals(name)) { - return mod.uid; - } - } - throw new RuntimeException("Mod " + name + " not found"); - // System.out.println("Mod " + name + " not found"); - // return 0; - } - - public boolean isModUIDLoaded(String name) { - for (Mod mod : mods.values()) { - if (mod.name.equals(name)) { - return true; - } - } - return false; - } - - /** - * Adds a {@code Map} with the given uid and path. - * - * @param uid - * @param path - */ - public void addMap(Integer uid, String... path) { - maps.put(uid, toString(path)); - } - - /** - * Adds an object to the list. - * - * @param entity the object to be added - */ - public void addEntity(Entity entity) { - objects.put(entity.getUID(), entity); - if (objects.size() % 1000 == 0) { // do a commit every 1000 entities - uidDb.commit(); - } - } - - /** - * Removes the object with the given UID. - * - * @param uid the UID of the object to be removed - */ - public void removeEntity(long uid) { - objects.remove(uid); - } - - /** - * Returns the entity with the given UID. If the UID is a {@code DUMMY}, {@code null} is returned. - * - * @param uid the UID of an object - * @return the object with the given UID - */ - public Entity getEntity(long uid) { - return (uid == DUMMY ? null : objects.get(uid)); - } - - /** - * Adds a mod with the given id. - * - * @param id - */ - public void addMod(String id) { - short uid = (short) (Math.random() * Short.MAX_VALUE); - while (mods.containsKey(uid) || uid == 0) { - uid++; - } - Mod mod = new Mod(uid, id); - mods.put(mod.uid, mod); - } - - /** - * @param uid the unique identifier of a map - * @return the full path of a map - */ - public String[] getMapPath(int uid) { - if (maps.get(uid) != null) { - return maps.get(uid).split(","); - } else { - return null; - } - } - - /** - * @param path the path to a map - * @return the uid of the given map - */ - public int getMapUID(String... path) { - var uid = maps.inverse().get(toString(path)); - if (uid == null) { - log.warn("{} doesn't have uid", (Object) path); - } - return maps.inverse().get(toString(path)); - } - - /** - * Creates a new uid for an entity. - * - * @return - */ - public long createNewEntityUID() { - // random objects have a random negative long as uid - long uid = (long) (Math.random() * Long.MIN_VALUE); - while (objects.containsKey(uid)) { - uid = (uid >= 0) ? Long.MIN_VALUE : uid + 1; - } - return uid; - } - - /** - * Creates a new uid for a map. - * - * @return - */ - public int createNewMapUID() { - // random maps have a random negative int as uid - int uid = (int) (Math.random() * Integer.MIN_VALUE); - while (maps.containsKey(uid)) { - uid = (uid >= 0) ? Integer.MIN_VALUE : uid + 1; - } - return uid; - } - - private static String toString(String... strings) { - StringBuilder result = new StringBuilder(); - for (String s : strings) { - result.append(s); - result.append(","); - } - // remove last "," - result.replace(result.length(), result.length(), ""); - return result.toString(); - } - - /** - * @param map - * @param object - * @return the full object UID - */ - public static long getObjectUID(long map, long object) { - // this to avoid problems with two's complement - return (map << 32) | ((object << 32) >>> 32); - } - - /** - * @param mod - * @param map - * @return the full map UID - */ - public static int getMapUID(int mod, int map) { - // this to avoid problems with two's complement - return (mod << 16) | ((map << 16) >>> 16); - } - - @Override - public void close() throws IOException { - uidDb.commit(); - uidDb.close(); - } - - private record Mod(short uid, String name) implements Serializable {} -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2013 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.entities; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import java.io.*; +import java.util.Map; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import neon.entities.mvstore.EntityDataType; +import neon.entities.mvstore.LongDataType; +import neon.entities.mvstore.ModDataType; +import neon.entities.mvstore.ShortDataType; +import neon.maps.services.EntityStore; +import neon.systems.files.FileSystem; +import neon.util.mapstorage.MapStore; +import neon.util.mapstorage.MapStoreMVStoreAdapter; +import org.h2.mvstore.MVStore; + +/** + * This class stores the UIDs of every object, map and mod currently in the game. It can give out + * new UIDs to objects created during gameplay. Positive UIDs are used in resources loaded from a + * mod. Negative UIDs are reserved for random generation. + * + * @author mdriesen + */ +@Slf4j +public class UIDStore implements EntityStore, Closeable { + // dummy uid for objects that don't actually exist + public static final long DUMMY = 0; + @Getter private final FileSystem fileSystem; + // uid database + @Getter private final MapStore uidDb; + // uids of all objects in the game + private Map objects; + // uids of all loaded mods + private Map mods; + // uids of all loaded maps + private final BiMap maps = HashBiMap.create(); + + /** + * Tells this UIDStore to use the given jdbm3 cache. + * + * @param file + */ + public UIDStore(FileSystem fileSystem, String file) { + this.fileSystem = fileSystem; + uidDb = new MapStoreMVStoreAdapter(MVStore.open(file)); + // Maps will be opened after DataTypes are set via setDataTypes() + } + + public UIDStore(FileSystem fileSystem, MapStore mapStore) { + this.fileSystem = fileSystem; + uidDb = mapStore; + // Maps will be opened after DataTypes are set via setDataTypes() + } + + /** + * Sets the DataTypes for entity and mod serialization and opens the maps. This must be called + * after construction to initialize the UIDStore. + * + * @param entityDataType the DataType for entity serialization + * @param modDataType the DataType for mod serialization + */ + public void setDataTypes(EntityDataType entityDataType, ModDataType modDataType) { + this.objects = uidDb.openMap("object", LongDataType.INSTANCE, entityDataType); + this.mods = uidDb.openMap("mods", ShortDataType.INSTANCE, modDataType); + } + + /** + * @return the jdbm3 cache used by this UIDStore + */ + public MapStore getCache() { + return uidDb; + } + + /** + * @param name the name of a mod + * @return the unique identifier of this mod + */ + public short getModUID(String name) { + for (ModDataType.Mod mod : mods.values()) { + if (mod.name().equals(name)) { + return mod.uid(); + } + } + throw new RuntimeException("Mod " + name + " not found"); + // System.out.println("Mod " + name + " not found"); + // return 0; + } + + public boolean isModUIDLoaded(String name) { + for (ModDataType.Mod mod : mods.values()) { + if (mod.name().equals(name)) { + return true; + } + } + return false; + } + + /** + * Adds a {@code Map} with the given uid and path. + * + * @param uid + * @param path + */ + public void addMap(Integer uid, String... path) { + maps.put(uid, toString(path)); + } + + /** + * Adds an object to the list. + * + * @param entity the object to be added + */ + public void addEntity(Entity entity) { + objects.put(entity.getUID(), entity); + if (objects.size() % 1000 == 0) { // do a commit every 1000 entities + uidDb.commit(); + } + } + + /** + * Removes the object with the given UID. + * + * @param uid the UID of the object to be removed + */ + public void removeEntity(long uid) { + objects.remove(uid); + } + + /** + * Returns the entity with the given UID. If the UID is a {@code DUMMY}, {@code null} is returned. + * + * @param uid the UID of an object + * @return the object with the given UID + */ + public Entity getEntity(long uid) { + return (uid == DUMMY ? null : objects.get(uid)); + } + + /** + * Adds a mod with the given id. + * + * @param id + */ + public void addMod(String id) { + short uid = (short) (Math.random() * Short.MAX_VALUE); + while (mods.containsKey(uid) || uid == 0) { + uid++; + } + ModDataType.Mod mod = new ModDataType.Mod(uid, id); + mods.put(mod.uid(), mod); + } + + /** + * @param uid the unique identifier of a map + * @return the full path of a map + */ + public String[] getMapPath(int uid) { + if (maps.get(uid) != null) { + return maps.get(uid).split(","); + } else { + return null; + } + } + + /** + * @param path the path to a map + * @return the uid of the given map + */ + public int getMapUID(String... path) { + var uid = maps.inverse().get(toString(path)); + if (uid == null) { + log.warn("{} doesn't have uid", (Object) path); + } + return maps.inverse().get(toString(path)); + } + + /** + * Creates a new uid for an entity. + * + * @return + */ + public long createNewEntityUID() { + // random objects have a random negative long as uid + long uid = (long) (Math.random() * Long.MIN_VALUE); + while (objects.containsKey(uid)) { + uid = (uid >= 0) ? Long.MIN_VALUE : uid + 1; + } + return uid; + } + + /** + * Creates a new uid for a map. + * + * @return + */ + public int createNewMapUID() { + // random maps have a random negative int as uid + int uid = (int) (Math.random() * Integer.MIN_VALUE); + while (maps.containsKey(uid)) { + uid = (uid >= 0) ? Integer.MIN_VALUE : uid + 1; + } + return uid; + } + + private static String toString(String... strings) { + StringBuilder result = new StringBuilder(); + for (String s : strings) { + result.append(s); + result.append(","); + } + // remove last "," + result.replace(result.length(), result.length(), ""); + return result.toString(); + } + + /** + * @param map + * @param object + * @return the full object UID + */ + public static long getObjectUID(long map, long object) { + // this to avoid problems with two's complement + return (map << 32) | ((object << 32) >>> 32); + } + + /** + * @param mod + * @param map + * @return the full map UID + */ + public static int getMapUID(int mod, int map) { + // this to avoid problems with two's complement + return (mod << 16) | ((map << 16) >>> 16); + } + + @Override + public void close() throws IOException { + uidDb.commit(); + uidDb.close(); + } +} diff --git a/src/main/java/neon/entities/mvstore/ByteBufferDataInput.java b/src/main/java/neon/entities/mvstore/ByteBufferDataInput.java new file mode 100644 index 0000000..af63b7b --- /dev/null +++ b/src/main/java/neon/entities/mvstore/ByteBufferDataInput.java @@ -0,0 +1,116 @@ +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.entities.mvstore; + +import java.io.DataInput; +import java.io.IOException; +import java.nio.ByteBuffer; +import neon.maps.mvstore.MVUtils; + +/** + * Adapter class that wraps a ByteBuffer to implement the DataInput interface. This allows existing + * serializers using DataInput to work with MVStore's ByteBuffer. + * + * @author mdriesen + */ +public class ByteBufferDataInput implements DataInput { + private final ByteBuffer buffer; + + public ByteBufferDataInput(ByteBuffer buffer) { + this.buffer = buffer; + } + + @Override + public void readFully(byte[] b) throws IOException { + buffer.get(b); + } + + @Override + public void readFully(byte[] b, int off, int len) throws IOException { + buffer.get(b, off, len); + } + + @Override + public int skipBytes(int n) throws IOException { + int remaining = buffer.remaining(); + int toSkip = Math.min(n, remaining); + buffer.position(buffer.position() + toSkip); + return toSkip; + } + + @Override + public boolean readBoolean() throws IOException { + return buffer.get() != 0; + } + + @Override + public byte readByte() throws IOException { + return buffer.get(); + } + + @Override + public int readUnsignedByte() throws IOException { + return buffer.get() & 0xFF; + } + + @Override + public short readShort() throws IOException { + return buffer.getShort(); + } + + @Override + public int readUnsignedShort() throws IOException { + return buffer.getShort() & 0xFFFF; + } + + @Override + public char readChar() throws IOException { + return buffer.getChar(); + } + + @Override + public int readInt() throws IOException { + return buffer.getInt(); + } + + @Override + public long readLong() throws IOException { + return buffer.getLong(); + } + + @Override + public float readFloat() throws IOException { + return buffer.getFloat(); + } + + @Override + public double readDouble() throws IOException { + return buffer.getDouble(); + } + + @Override + public String readLine() throws IOException { + throw new UnsupportedOperationException("readLine() is not supported"); + } + + @Override + public String readUTF() throws IOException { + return MVUtils.readString(buffer); + } +} diff --git a/src/main/java/neon/entities/mvstore/ByteBufferDataOutput.java b/src/main/java/neon/entities/mvstore/ByteBufferDataOutput.java new file mode 100644 index 0000000..12ff11a --- /dev/null +++ b/src/main/java/neon/entities/mvstore/ByteBufferDataOutput.java @@ -0,0 +1,112 @@ +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.entities.mvstore; + +import java.io.DataOutput; +import java.io.IOException; +import neon.maps.mvstore.MVUtils; +import org.h2.mvstore.WriteBuffer; + +/** + * Adapter class that wraps MVStore's WriteBuffer to implement the DataOutput interface. This allows + * existing serializers using DataOutput to work with MVStore's WriteBuffer. + * + * @author mdriesen + */ +public class ByteBufferDataOutput implements DataOutput { + private final WriteBuffer buffer; + + public ByteBufferDataOutput(WriteBuffer buffer) { + this.buffer = buffer; + } + + @Override + public void write(int b) throws IOException { + buffer.put((byte) b); + } + + @Override + public void write(byte[] b) throws IOException { + buffer.put(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + buffer.put(b, off, len); + } + + @Override + public void writeBoolean(boolean v) throws IOException { + buffer.put((byte) (v ? 1 : 0)); + } + + @Override + public void writeByte(int v) throws IOException { + buffer.put((byte) v); + } + + @Override + public void writeShort(int v) throws IOException { + buffer.putShort((short) v); + } + + @Override + public void writeChar(int v) throws IOException { + buffer.putChar((char) v); + } + + @Override + public void writeInt(int v) throws IOException { + buffer.putInt(v); + } + + @Override + public void writeLong(long v) throws IOException { + buffer.putLong(v); + } + + @Override + public void writeFloat(float v) throws IOException { + buffer.putFloat(v); + } + + @Override + public void writeDouble(double v) throws IOException { + buffer.putDouble(v); + } + + @Override + public void writeBytes(String s) throws IOException { + for (int i = 0; i < s.length(); i++) { + buffer.put((byte) s.charAt(i)); + } + } + + @Override + public void writeChars(String s) throws IOException { + for (int i = 0; i < s.length(); i++) { + buffer.putChar(s.charAt(i)); + } + } + + @Override + public void writeUTF(String str) throws IOException { + MVUtils.writeString(buffer, str); + } +} diff --git a/src/main/java/neon/entities/mvstore/EntityDataType.java b/src/main/java/neon/entities/mvstore/EntityDataType.java new file mode 100644 index 0000000..380099f --- /dev/null +++ b/src/main/java/neon/entities/mvstore/EntityDataType.java @@ -0,0 +1,60 @@ +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.entities.mvstore; + +import java.nio.ByteBuffer; +import neon.entities.Entity; +import neon.entities.serialization.EntityFactory; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.BasicDataType; + +/** + * MVStore DataType implementation for Entity serialization. This class delegates + * serialization/deserialization to EntityFactory. + * + * @author mdriesen + */ +public class EntityDataType extends BasicDataType { + private final EntityFactory entityFactory; + + public EntityDataType(EntityFactory entityFactory) { + this.entityFactory = entityFactory; + } + + @Override + public int getMemory(Entity obj) { + // Return 0 for now - can be optimized later if needed + return 0; + } + + @Override + public void write(WriteBuffer buff, Entity obj) { + entityFactory.writeEntityToWriteBuffer(buff, obj); + } + + @Override + public Entity read(ByteBuffer buff) { + return entityFactory.readEntityFromByteBuffer(buff); + } + + @Override + public Entity[] createStorage(int size) { + return new Entity[size]; + } +} diff --git a/src/main/java/neon/entities/mvstore/LongDataType.java b/src/main/java/neon/entities/mvstore/LongDataType.java new file mode 100644 index 0000000..df1f2a7 --- /dev/null +++ b/src/main/java/neon/entities/mvstore/LongDataType.java @@ -0,0 +1,63 @@ +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.entities.mvstore; + +import java.nio.ByteBuffer; +import org.h2.mvstore.DataUtils; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.BasicDataType; + +/** + * MVStore DataType implementation for Long keys. + * + * @author mdriesen + */ +public class LongDataType extends BasicDataType { + + public static final LongDataType INSTANCE = new LongDataType(); + + private static final Long[] EMPTY_LONG_ARR = new Long[0]; + + private LongDataType() {} + + @Override + public int getMemory(Long obj) { + return 8; + } + + @Override + public void write(WriteBuffer buff, Long data) { + buff.putVarLong(data); + } + + @Override + public Long read(ByteBuffer buff) { + return DataUtils.readVarLong(buff); + } + + @Override + public Long[] createStorage(int size) { + return size == 0 ? EMPTY_LONG_ARR : new Long[size]; + } + + @Override + public int compare(Long one, Long two) { + return Long.compare(one, two); + } +} diff --git a/src/main/java/neon/entities/mvstore/ModDataType.java b/src/main/java/neon/entities/mvstore/ModDataType.java new file mode 100644 index 0000000..0050e9e --- /dev/null +++ b/src/main/java/neon/entities/mvstore/ModDataType.java @@ -0,0 +1,65 @@ +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.entities.mvstore; + +import java.io.Serializable; +import java.nio.ByteBuffer; +import neon.maps.mvstore.MVUtils; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.BasicDataType; + +/** + * MVStore DataType implementation for Mod records. A Mod represents a loaded game modification with + * a UID and name. + * + * @author mdriesen + */ +public class ModDataType extends BasicDataType { + + @Override + public int getMemory(Mod obj) { + return 2 + (obj.name() == null ? 0 : obj.name().length() * 2); + } + + @Override + public void write(WriteBuffer buff, Mod obj) { + buff.putShort(obj.uid()); + MVUtils.writeString(buff, obj.name()); + } + + @Override + public Mod read(ByteBuffer buff) { + short uid = buff.getShort(); + String name = MVUtils.readString(buff); + return new Mod(uid, name); + } + + @Override + public Mod[] createStorage(int size) { + return new Mod[size]; + } + + /** + * Record representing a game modification (mod). Package-private to allow UIDStore to use it. + * + * @param uid the unique identifier for this mod + * @param name the name of the mod + */ + public record Mod(short uid, String name) implements Serializable {} +} diff --git a/src/main/java/neon/entities/mvstore/ShortDataType.java b/src/main/java/neon/entities/mvstore/ShortDataType.java new file mode 100644 index 0000000..f075f0a --- /dev/null +++ b/src/main/java/neon/entities/mvstore/ShortDataType.java @@ -0,0 +1,62 @@ +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.entities.mvstore; + +import java.nio.ByteBuffer; +import org.h2.mvstore.WriteBuffer; +import org.h2.mvstore.type.BasicDataType; + +/** + * MVStore DataType implementation for Short keys. + * + * @author mdriesen + */ +public class ShortDataType extends BasicDataType { + + public static final ShortDataType INSTANCE = new ShortDataType(); + + private static final Short[] EMPTY_SHORT_ARR = new Short[0]; + + private ShortDataType() {} + + @Override + public int getMemory(Short obj) { + return 2; + } + + @Override + public void write(WriteBuffer buff, Short data) { + buff.putShort(data); + } + + @Override + public Short read(ByteBuffer buff) { + return buff.getShort(); + } + + @Override + public Short[] createStorage(int size) { + return size == 0 ? EMPTY_SHORT_ARR : new Short[size]; + } + + @Override + public int compare(Short one, Short two) { + return Short.compare(one, two); + } +} diff --git a/src/main/java/neon/entities/serialization/CreatureSerializer.java b/src/main/java/neon/entities/serialization/CreatureSerializer.java index 7a47ac8..22fd80b 100644 --- a/src/main/java/neon/entities/serialization/CreatureSerializer.java +++ b/src/main/java/neon/entities/serialization/CreatureSerializer.java @@ -1,158 +1,155 @@ -/* - * Neon, a roguelike engine. - * Copyright (C) 2013 - Maarten Driesen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package neon.entities.serialization; - -import java.awt.Rectangle; -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import neon.ai.AIFactory; -import neon.core.GameContext; -import neon.core.GameStores; -import neon.entities.Construct; -import neon.entities.Creature; -import neon.entities.Daemon; -import neon.entities.Dragon; -import neon.entities.Hominid; -import neon.entities.components.HealthComponent; -import neon.entities.property.Slot; -import neon.magic.SpellFactory; -import neon.resources.RCreature; -import neon.resources.ResourceManager; - -// TODO: factions -public class CreatureSerializer { - private static final long serialVersionUID = -2452444993764883434L; - private final AIFactory aiFactory; - private final SpellFactory spellFactory; - private final ResourceManager resourceManager; - private final GameContext gameContext; - private final GameStores gameStores; - - public CreatureSerializer(GameStores gameStores, GameContext gameContext) { - spellFactory = new SpellFactory(gameStores.getResources()); - resourceManager = gameStores.getResources(); - this.gameStores = gameStores; - this.gameContext = gameContext; - aiFactory = - new AIFactory(gameStores.getResources(), gameStores.getStore(), gameContext.getPlayer()); - } - - public Creature deserialize(DataInput in) throws IOException { - String id = in.readUTF(); - String species = in.readUTF(); - int x = in.readInt(); - int y = in.readInt(); - long uid = in.readLong(); - Creature creature = getCreature(id, x, y, uid, species); - Rectangle bounds = creature.getShapeComponent(); - bounds.setLocation(x, y); - creature.brain = aiFactory.getAI(creature); - - HealthComponent health = creature.getHealthComponent(); - health.setHealth(in.readInt()); - health.addBaseHealthMod(in.readFloat()); - health.heal(in.readFloat()); - creature.getInventoryComponent().addMoney(in.readInt()); - creature.getMagicComponent().setBaseModifier(in.readFloat()); - creature.getMagicComponent().setModifier(in.readFloat()); - String spell = in.readUTF(); - if (!spell.isEmpty()) { - creature.getMagicComponent().equipSpell(spellFactory.getSpell(spell)); - } - - int date = in.readInt(); - if (date != 0) { - creature.die(date); - } - - byte iCount = in.readByte(); - for (int i = 0; i < iCount; i++) { - creature.getInventoryComponent().addItem(in.readLong()); - } - - byte sCount = in.readByte(); - for (int i = 0; i < sCount; i++) { - creature.getInventoryComponent().put(Slot.valueOf(in.readUTF()), in.readLong()); - } - - sCount = in.readByte(); - for (int i = 0; i < sCount; i++) { - creature.getScriptComponent().addScript(in.readUTF()); - } - - return creature; - } - - public void serialize(DataOutput out, Creature creature) throws IOException { - out.writeUTF(creature.getID()); - out.writeUTF(creature.species.id); - Rectangle bounds = creature.getShapeComponent(); - out.writeInt(bounds.x); - out.writeInt(bounds.y); - out.writeLong(creature.getUID()); - - HealthComponent health = creature.getHealthComponent(); - out.writeInt(health.getBaseHealth()); - out.writeFloat(health.getBaseHealthMod()); - out.writeFloat(health.getHealthMod()); - out.writeInt(creature.getInventoryComponent().getMoney()); - out.writeFloat(creature.getMagicComponent().getBaseModifier()); - out.writeFloat(creature.getMagicComponent().getModifier()); - if (creature.getMagicComponent().getSpell() != null) { - out.writeUTF(creature.getMagicComponent().getSpell().id); - } else { - out.writeUTF(""); - } - out.writeInt(creature.getTimeOfDeath()); - - out.writeByte(creature.getInventoryComponent().getItems().size()); - for (long uid : creature.getInventoryComponent()) { - out.writeLong(uid); - } - - out.writeByte(creature.getInventoryComponent().slots().size()); - for (Slot slot : creature.getInventoryComponent().slots()) { - out.writeUTF(slot.name()); - out.writeLong(creature.getInventoryComponent().get(slot)); - } - - out.writeByte(creature.getScriptComponent().getScripts().size()); - for (String script : creature.getScriptComponent().getScripts()) { - out.writeUTF(script); - } - } - - private Creature getCreature(String id, int x, int y, long uid, String species) { - Creature creature; - - RCreature rc = (RCreature) resourceManager.getResource(species); - creature = - switch (rc.type) { - case construct -> new Construct(id, uid, rc); - case humanoid -> new Hominid(id, uid, rc); - case daemon -> new Daemon(id, uid, rc); - case dragon -> new Dragon(id, uid, rc); - case goblin -> new Hominid(id, uid, rc); - default -> new Creature(id, uid, rc); - }; - - return creature; - } -} +/* + * Neon, a roguelike engine. + * Copyright (C) 2013 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.entities.serialization; + +import java.awt.Rectangle; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import neon.ai.AIFactory; +import neon.core.GameContext; +import neon.core.GameStores; +import neon.entities.*; +import neon.entities.components.HealthComponent; +import neon.entities.property.Slot; +import neon.magic.SpellFactory; +import neon.resources.RCreature; +import neon.resources.ResourceManager; + +// TODO: factions +public class CreatureSerializer { + private static final long serialVersionUID = -2452444993764883434L; + private final AIFactory aiFactory; + private final SpellFactory spellFactory; + private final ResourceManager resourceManager; + + + public CreatureSerializer(ResourceManager resourceManager, UIDStore uidStore, Player player) { + spellFactory = new SpellFactory(resourceManager); + this.resourceManager = resourceManager; + + // AIFactory can be null if gameContext is null (for write-only or test scenarios) + aiFactory = + new AIFactory( + resourceManager, uidStore, player); + + } + + public Creature deserialize(DataInput in) throws IOException { + String id = in.readUTF(); + String species = in.readUTF(); + int x = in.readInt(); + int y = in.readInt(); + long uid = in.readLong(); + Creature creature = getCreature(id, x, y, uid, species); + Rectangle bounds = creature.getShapeComponent(); + bounds.setLocation(x, y); + creature.brain = aiFactory.getAI(creature); + + HealthComponent health = creature.getHealthComponent(); + health.setHealth(in.readInt()); + health.addBaseHealthMod(in.readFloat()); + health.heal(in.readFloat()); + creature.getInventoryComponent().addMoney(in.readInt()); + creature.getMagicComponent().setBaseModifier(in.readFloat()); + creature.getMagicComponent().setModifier(in.readFloat()); + String spell = in.readUTF(); + if (!spell.isEmpty()) { + creature.getMagicComponent().equipSpell(spellFactory.getSpell(spell)); + } + + int date = in.readInt(); + if (date != 0) { + creature.die(date); + } + + byte iCount = in.readByte(); + for (int i = 0; i < iCount; i++) { + creature.getInventoryComponent().addItem(in.readLong()); + } + + byte sCount = in.readByte(); + for (int i = 0; i < sCount; i++) { + creature.getInventoryComponent().put(Slot.valueOf(in.readUTF()), in.readLong()); + } + + sCount = in.readByte(); + for (int i = 0; i < sCount; i++) { + creature.getScriptComponent().addScript(in.readUTF()); + } + + return creature; + } + + public void serialize(DataOutput out, Creature creature) throws IOException { + out.writeUTF(creature.getID()); + out.writeUTF(creature.species.id); + Rectangle bounds = creature.getShapeComponent(); + out.writeInt(bounds.x); + out.writeInt(bounds.y); + out.writeLong(creature.getUID()); + + HealthComponent health = creature.getHealthComponent(); + out.writeInt(health.getBaseHealth()); + out.writeFloat(health.getBaseHealthMod()); + out.writeFloat(health.getHealthMod()); + out.writeInt(creature.getInventoryComponent().getMoney()); + out.writeFloat(creature.getMagicComponent().getBaseModifier()); + out.writeFloat(creature.getMagicComponent().getModifier()); + if (creature.getMagicComponent().getSpell() != null) { + out.writeUTF(creature.getMagicComponent().getSpell().id); + } else { + out.writeUTF(""); + } + out.writeInt(creature.getTimeOfDeath()); + + out.writeByte(creature.getInventoryComponent().getItems().size()); + for (long uid : creature.getInventoryComponent()) { + out.writeLong(uid); + } + + out.writeByte(creature.getInventoryComponent().slots().size()); + for (Slot slot : creature.getInventoryComponent().slots()) { + out.writeUTF(slot.name()); + out.writeLong(creature.getInventoryComponent().get(slot)); + } + + out.writeByte(creature.getScriptComponent().getScripts().size()); + for (String script : creature.getScriptComponent().getScripts()) { + out.writeUTF(script); + } + } + + private Creature getCreature(String id, int x, int y, long uid, String species) { + Creature creature; + + RCreature rc = (RCreature) resourceManager.getResource(species); + creature = + switch (rc.type) { + case construct -> new Construct(id, uid, rc); + case humanoid -> new Hominid(id, uid, rc); + case daemon -> new Daemon(id, uid, rc); + case dragon -> new Dragon(id, uid, rc); + case goblin -> new Hominid(id, uid, rc); + default -> new Creature(id, uid, rc); + }; + + return creature; + } +} diff --git a/src/main/java/neon/entities/serialization/EntityFactory.java b/src/main/java/neon/entities/serialization/EntityFactory.java new file mode 100644 index 0000000..c0cd1ef --- /dev/null +++ b/src/main/java/neon/entities/serialization/EntityFactory.java @@ -0,0 +1,101 @@ +/* + * Neon, a roguelike engine. + * Copyright (C) 2012 - Maarten Driesen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package neon.entities.serialization; + +import java.io.IOException; +import java.nio.ByteBuffer; +import neon.core.GameContext; +import neon.core.GameStores; +import neon.entities.Creature; +import neon.entities.Entity; +import neon.entities.Item; +import neon.entities.mvstore.ByteBufferDataInput; +import neon.entities.mvstore.ByteBufferDataOutput; +import org.h2.mvstore.WriteBuffer; + +/** + * Factory class that orchestrates entity serialization/deserialization for MVStore. This class + * bridges existing DataInput/DataOutput-based serializers to MVStore's WriteBuffer/ByteBuffer + * format. + * + * @author mdriesen + */ +public class EntityFactory { + private static final int ITEM_TYPE = 1; + private static final int CREATURE_TYPE = 2; + + private final ItemSerializer itemSerializer; + private final CreatureSerializer creatureSerializer; + + /** + * Constructor for full functionality (used by Engine). + * + * @param gameStores the game stores providing access to resources and entities + * @param gameContext the game context for AI initialization (can be null for write-only + * operations) + */ + public EntityFactory(GameStores gameStores, GameContext gameContext) { + this.itemSerializer = new ItemSerializer(gameStores); + this.creatureSerializer = new CreatureSerializer(gameStores, gameContext); + } + + /** + * Serializes an entity to MVStore's WriteBuffer format. + * + * @param out the WriteBuffer to write to + * @param entity the entity to serialize + */ + public void writeEntityToWriteBuffer(WriteBuffer out, Entity entity) { + try { + if (entity instanceof Item) { + out.putInt(ITEM_TYPE); + ByteBufferDataOutput adapter = new ByteBufferDataOutput(out); + itemSerializer.serialize(adapter, (Item) entity); + } else if (entity instanceof Creature) { + out.putInt(CREATURE_TYPE); + ByteBufferDataOutput adapter = new ByteBufferDataOutput(out); + creatureSerializer.serialize(adapter, (Creature) entity); + } else { + throw new IllegalArgumentException("Unknown entity type: " + entity.getClass()); + } + } catch (IOException e) { + throw new RuntimeException("Failed to serialize entity", e); + } + } + + /** + * Deserializes an entity from MVStore's ByteBuffer format. + * + * @param in the ByteBuffer to read from + * @return the deserialized entity + */ + public Entity readEntityFromByteBuffer(ByteBuffer in) { + try { + int type = in.getInt(); + ByteBufferDataInput adapter = new ByteBufferDataInput(in); + return switch (type) { + case ITEM_TYPE -> itemSerializer.deserialize(adapter); + case CREATURE_TYPE -> creatureSerializer.deserialize(adapter); + default -> throw new IllegalStateException("Unknown entity type: " + type); + }; + } catch (IOException e) { + throw new RuntimeException("Failed to deserialize entity", e); + } + } +} diff --git a/src/main/java/neon/entities/serialization/ItemSerializer.java b/src/main/java/neon/entities/serialization/ItemSerializer.java index f13e1c1..80fdcf3 100644 --- a/src/main/java/neon/entities/serialization/ItemSerializer.java +++ b/src/main/java/neon/entities/serialization/ItemSerializer.java @@ -43,7 +43,7 @@ * @author mdriesen */ public class ItemSerializer { - private static final long serialVersionUID = 2138679015831709732L; + private final GameStores gameStores; private final ItemFactory itemFactory; private final SpellFactory spellFactory; diff --git a/src/main/java/neon/maps/Atlas.java b/src/main/java/neon/maps/Atlas.java index dd512d3..3be86dd 100644 --- a/src/main/java/neon/maps/Atlas.java +++ b/src/main/java/neon/maps/Atlas.java @@ -100,8 +100,7 @@ public static MapStore getMapStore(FileSystem files, String fileName) { files.delete(fileName); log.warn("Creating new MVStore at {}", fileName); - - return new MapStoreMVStoreAdapter(MVStore.open(fileName)); + return new MapStoreMVStoreAdapter(MVStore.open(files.getFullPath(fileName))); } public MapStore getCache() { diff --git a/src/main/java/neon/systems/files/XMLTranslator.java b/src/main/java/neon/systems/files/XMLTranslator.java index f0966ee..2364e11 100644 --- a/src/main/java/neon/systems/files/XMLTranslator.java +++ b/src/main/java/neon/systems/files/XMLTranslator.java @@ -26,7 +26,8 @@ /** * This class can load, save and translate an xml file from disk. * - * @author mdriesen As of Phase 5 of JDOM2 elimination, this class is deprecated in favor of {@link + * @author mdriesen + * @deprecated As of Phase 5 of JDOM2 elimination, this class is deprecated in favor of {@link * JacksonMapper} for XML parsing and serialization. JDOM2-based XML handling will be removed in * Phase 7. Current usages: *

      @@ -37,7 +38,7 @@ * Migration path: Replace XMLTranslator with JacksonMapper for new code. Existing code will be * migrated as part of Phase 7 cleanup when JDOM constructors are removed. */ -// Deprecated(since = "0.4.1", forRemoval = true) +@Deprecated(since = "0.4.1", forRemoval = true) public class XMLTranslator implements Translator { public Document translate(InputStream input) { Document doc = new Document(); diff --git a/src/test/java/neon/entities/UIDStoreTest.java b/src/test/java/neon/entities/UIDStoreTest.java index 1bf3d47..2e1c3fb 100644 --- a/src/test/java/neon/entities/UIDStoreTest.java +++ b/src/test/java/neon/entities/UIDStoreTest.java @@ -3,18 +3,78 @@ import static org.junit.jupiter.api.Assertions.*; import java.io.IOException; +import neon.core.GameStores; +import neon.entities.mvstore.EntityDataType; +import neon.entities.mvstore.ModDataType; +import neon.entities.serialization.EntityFactory; +import neon.maps.Atlas; +import neon.maps.ZoneFactory; import neon.resources.RClothing; import neon.resources.RItem; +import neon.resources.ResourceManager; import neon.systems.files.FileSystem; import neon.test.TestEngineContext; +import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.Test; class UIDStoreTest { FileSystem fileSystem = TestEngineContext.getStubFileSystem(); + // Simple GameStores stub for testing + private static class TestGameStores implements GameStores { + private final ResourceManager resources = new ResourceManager(); + private final FileSystem fileSystem; + private final UIDStore store; + + TestGameStores(FileSystem fileSystem, UIDStore store) { + this.fileSystem = fileSystem; + this.store = store; + } + + @Override + public ResourceManager getResources() { + return resources; + } + + @Override + public FileSystem getFileSystem() { + return fileSystem; + } + + @Override + public UIDStore getStore() { + return store; + } + + @Override + public Atlas getAtlas() { + return null; + } + + @Override + public ZoneFactory getZoneFactory() { + return null; + } + + @Override + public MapStore getZoneMapStore() { + return null; + } + } + + private UIDStore createInitializedUIDStore(String filename) { + UIDStore store = new UIDStore(fileSystem, filename); + GameStores gameStores = new TestGameStores(fileSystem, store); + EntityFactory entityFactory = new EntityFactory(gameStores, null); + EntityDataType entityDataType = new EntityDataType(entityFactory); + ModDataType modDataType = new ModDataType(); + store.setDataTypes(entityDataType, modDataType); + return store; + } + @Test void addEntity() throws IOException { - UIDStore store = new UIDStore(fileSystem, "testfile3.dat"); + UIDStore store = createInitializedUIDStore("test_add_entity.dat"); var id = store.createNewMapUID(); var entityId = store.createNewEntityUID(); Entity entity = new Armor(entityId, new RClothing("one", RItem.Type.armor, "dummy")); @@ -28,7 +88,7 @@ void addEntity() throws IOException { @Test void removeEntity() throws IOException { - UIDStore store = new UIDStore(fileSystem, "testfile3.dat"); + UIDStore store = createInitializedUIDStore("test_remove_entity.dat"); var id = store.createNewMapUID(); var entityId = store.createNewEntityUID(); Entity entity = new Armor(entityId, new RClothing("one", RItem.Type.armor, "dummy")); diff --git a/src/test/java/neon/test/TestEngineContext.java b/src/test/java/neon/test/TestEngineContext.java index 29558b1..0c430fa 100644 --- a/src/test/java/neon/test/TestEngineContext.java +++ b/src/test/java/neon/test/TestEngineContext.java @@ -90,7 +90,7 @@ public static void initialize(MapStore db) throws Exception { setStaticField(Engine.class, "resources", testResources); // Create test UIDStore - testStore = new neon.entities.UIDStore(getStubFileSystem(), testDb); + testStore = new UIDStore(getStubFileSystem(), testDb); // Create test Game using new DI constructor Player stubPlayer = new Player( From 5591a6c8b8b496977127ad55caeb85466444a816 Mon Sep 17 00:00:00 2001 From: Peter Riewe Date: Thu, 15 Jan 2026 20:15:08 -0500 Subject: [PATCH 08/12] Checkpoint --- src/main/java/neon/ai/AI.java | 18 +- src/main/java/neon/ai/AIFactory.java | 11 +- src/main/java/neon/ai/BasicAI.java | 11 +- src/main/java/neon/ai/GuardAI.java | 11 +- src/main/java/neon/ai/HuntBehaviour.java | 2 +- src/main/java/neon/ai/PathFinder.java | 10 +- src/main/java/neon/ai/ScheduleAI.java | 11 +- .../java/neon/core/DefaultGameContext.java | 5 - .../java/neon/core/DefaultGameStores.java | 9 +- src/main/java/neon/core/Engine.java | 11 +- src/main/java/neon/core/Game.java | 8 +- src/main/java/neon/core/GameContext.java | 2 - src/main/java/neon/core/GameLoader.java | 15 +- src/main/java/neon/core/ScriptInterface.java | 4 +- .../neon/core/handlers/InventoryHandler.java | 2 +- .../java/neon/core/handlers/MagicHandler.java | 12 +- .../neon/core/handlers/MotionHandler.java | 8 +- .../neon/core/handlers/TeleportHandler.java | 5 +- .../java/neon/core/handlers/TurnHandler.java | 16 +- src/main/java/neon/editor/resources/RMap.java | 12 +- src/main/java/neon/entities/Creature.java | 10 +- .../java/neon/entities/CreatureFactory.java | 13 +- src/main/java/neon/entities/Entity.java | 19 +- src/main/java/neon/entities/EntityBase.java | 27 +++ src/main/java/neon/entities/Player.java | 6 +- src/main/java/neon/entities/UIDStore.java | 24 +-- .../java/neon/entities/components/Animus.java | 2 +- .../neon/entities/components/Inventory.java | 11 +- .../serialization/CreatureSerializer.java | 12 +- .../entities/serialization/EntityFactory.java | 13 +- .../serialization/EntitySerializer.java | 6 +- .../serialization/ItemSerializer.java | 75 ++++---- src/main/java/neon/maps/AtlasPosition.java | 18 +- src/main/java/neon/maps/MapLoader.java | 26 ++- src/main/java/neon/maps/Zone.java | 3 +- src/main/java/neon/maps/ZoneFactory.java | 61 ------- .../maps/generators/DungeonGenerator.java | 17 +- .../maps/generators/WildernessGenerator.java | 19 +- .../java/neon/maps/model/DungeonModel.java | 12 +- src/main/java/neon/maps/model/WorldModel.java | 26 ++- src/main/java/neon/ui/Client.java | 4 +- src/main/java/neon/ui/GamePanel.java | 28 +-- .../java/neon/ui/InventoryCellRenderer.java | 11 +- src/main/java/neon/ui/MapPanel.java | 11 +- .../java/neon/ui/dialog/EnchantDialog.java | 2 +- src/main/java/neon/ui/dialog/MapDialog.java | 5 +- src/main/java/neon/ui/dialog/TradeDialog.java | 2 +- src/main/java/neon/ui/states/AimState.java | 2 +- src/main/java/neon/ui/states/BumpState.java | 10 +- .../java/neon/ui/states/ContainerState.java | 8 +- src/main/java/neon/ui/states/DialogState.java | 24 +-- src/main/java/neon/ui/states/DoorState.java | 6 +- src/main/java/neon/ui/states/GameState.java | 89 ++++------ .../java/neon/ui/states/InventoryState.java | 6 +- .../java/neon/ui/states/JournalState.java | 17 +- src/main/java/neon/ui/states/LockState.java | 11 +- src/main/java/neon/ui/states/MoveState.java | 4 +- src/test/java/neon/core/GameLoaderTest.java | 4 +- src/test/java/neon/entities/UIDStoreTest.java | 15 +- .../java/neon/maps/AtlasIntegrationTest.java | 3 +- src/test/java/neon/maps/AtlasTest.java | 6 +- .../java/neon/maps/MapPerformanceTest.java | 35 ++-- .../maps/generators/DungeonGeneratorTest.java | 14 +- .../generators/WildernessGeneratorTest.java | 12 +- .../neon/maps/model/DungeonModelTest.java | 105 +++++++----- .../java/neon/maps/model/WorldModelTest.java | 58 ++++--- .../java/neon/test/TestEngineContext.java | 22 ++- .../resources/sampleMod1/maps/kusunda.xml | 2 +- src/test/resources/sampleMod1/maps/world.xml | 162 +++++++++--------- 69 files changed, 583 insertions(+), 678 deletions(-) create mode 100644 src/main/java/neon/entities/EntityBase.java diff --git a/src/main/java/neon/ai/AI.java b/src/main/java/neon/ai/AI.java index 25f8326..3884d8e 100644 --- a/src/main/java/neon/ai/AI.java +++ b/src/main/java/neon/ai/AI.java @@ -58,7 +58,6 @@ public abstract class AI implements Serializable { protected final MotionHandler motionHandler; protected final PathFinder pathFinder; protected final CombatUtils combatUtils; - protected final Player player; /** * Initializes a new AI. @@ -68,17 +67,16 @@ public abstract class AI implements Serializable { * @param confidence */ public AI( - Creature creature, byte aggression, byte confidence, GameStores gameStores, Player player) { + Creature creature, byte aggression, byte confidence, GameStores gameStores) { this.aggression = aggression; this.confidence = confidence; this.creature = creature; this.resourceManager = gameStores.getResources(); this.uidStore = gameStores.getStore(); - this.player = player; inventoryHandler = new InventoryHandler(uidStore); - motionHandler = new MotionHandler(this.uidStore, player); - pathFinder = new PathFinder(this.uidStore, player); + motionHandler = new MotionHandler(this.uidStore); + pathFinder = new PathFinder(this.uidStore); combatUtils = new CombatUtils(this.uidStore); } @@ -87,18 +85,16 @@ public AI( byte aggression, byte confidence, ResourceManager resourceManager, - UIDStore uidStore, - Player player) { + UIDStore uidStore) { this.aggression = aggression; this.confidence = confidence; this.creature = creature; this.resourceManager = resourceManager; this.uidStore = uidStore; - this.player = player; inventoryHandler = new InventoryHandler(uidStore); - motionHandler = new MotionHandler(uidStore, player); - pathFinder = new PathFinder(uidStore, player); + motionHandler = new MotionHandler(uidStore); + pathFinder = new PathFinder(uidStore); combatUtils = new CombatUtils(uidStore); } @@ -112,7 +108,7 @@ public boolean isHostile() { if (creature.hasCondition(Condition.CALM)) { return false; } else { - return aggression > getDisposition(player); + return aggression > getDisposition(uidStore.getPlayer()); } } diff --git a/src/main/java/neon/ai/AIFactory.java b/src/main/java/neon/ai/AIFactory.java index 633f276..7490e3d 100644 --- a/src/main/java/neon/ai/AIFactory.java +++ b/src/main/java/neon/ai/AIFactory.java @@ -29,15 +29,12 @@ public class AIFactory { - private final Player player; - private final ResourceManager resourceManager; private final UIDStore uidStore; - public AIFactory(ResourceManager resourceManager, UIDStore uidStore, Player player) { + public AIFactory(ResourceManager resourceManager, UIDStore uidStore) { this.resourceManager = resourceManager; this.uidStore = uidStore; - this.player = player; } /** @@ -88,12 +85,12 @@ public AI getAI(Creature creature) { private AI getAI(AIType type, Creature creature, byte aggression, byte confidence, int range) { return switch (type) { case wander -> - new BasicAI(creature, aggression, confidence, resourceManager, uidStore, player); + new BasicAI(creature, aggression, confidence, resourceManager, uidStore); case schedule -> new ScheduleAI( - creature, aggression, confidence, new Point[0], resourceManager, uidStore, player); + creature, aggression, confidence, new Point[0], resourceManager, uidStore); default -> - new GuardAI(creature, aggression, confidence, range, resourceManager, uidStore, player); + new GuardAI(creature, aggression, confidence, range, resourceManager, uidStore); }; } } diff --git a/src/main/java/neon/ai/BasicAI.java b/src/main/java/neon/ai/BasicAI.java index 12336d2..f714ea8 100644 --- a/src/main/java/neon/ai/BasicAI.java +++ b/src/main/java/neon/ai/BasicAI.java @@ -30,22 +30,21 @@ public BasicAI( byte aggression, byte confidence, ResourceManager resourceManager, - UIDStore uidStore, - Player player) { - super(creature, aggression, confidence, resourceManager, uidStore, player); + UIDStore uidStore) { + super(creature, aggression, confidence, resourceManager, uidStore); } public void act() { // TODO: not only pay attention to player, but also to other creatures in sight - if (isHostile() && sees(player)) { + if (isHostile() && sees(uidStore.getPlayer())) { HealthComponent health = creature.getHealthComponent(); if (100 * health.getHealth() / health.getBaseHealth() < confidence) { // 80% chance to just flee, 20% chance to heal; if no heal spell, flee anyway if (Math.random() > 0.2 || !(cure() || heal())) { - flee(player); + flee(uidStore.getPlayer()); } } else { - hunt(player); + hunt(uidStore.getPlayer()); } } else { wander(); diff --git a/src/main/java/neon/ai/GuardAI.java b/src/main/java/neon/ai/GuardAI.java index 6c1bf30..f3dcdc1 100644 --- a/src/main/java/neon/ai/GuardAI.java +++ b/src/main/java/neon/ai/GuardAI.java @@ -36,9 +36,8 @@ public GuardAI( byte confidence, int range, ResourceManager resourceManager, - UIDStore uidStore, - Player player) { - super(creature, aggression, confidence, resourceManager, uidStore, player); + UIDStore uidStore) { + super(creature, aggression, confidence, resourceManager, uidStore); this.range = range; ShapeComponent bounds = creature.getShapeComponent(); home = new Point(bounds.x, bounds.y); @@ -47,16 +46,16 @@ public GuardAI( public void act() { // TODO: not only pay attention to player, but also to other creatures in sight ShapeComponent cBounds = creature.getShapeComponent(); - ShapeComponent pBounds = player.getShapeComponent(); + ShapeComponent pBounds = uidStore.getPlayer().getShapeComponent(); if (isHostile() && cBounds.getLocation().distance(pBounds.getLocation()) < range) { HealthComponent health = creature.getHealthComponent(); if (100 * health.getHealth() / health.getBaseHealth() < confidence / 100) { // 80% chance to just flee, 20% chance to heal; if no heal spell, flee anyway if (Math.random() > 0.2 || !(cure() || heal())) { - flee(player); + flee(uidStore.getPlayer()); } } else { - hunt(range, home, player); + hunt(range, home, uidStore.getPlayer()); } } else { wander(range, home); diff --git a/src/main/java/neon/ai/HuntBehaviour.java b/src/main/java/neon/ai/HuntBehaviour.java index 59a8d77..245c2e5 100644 --- a/src/main/java/neon/ai/HuntBehaviour.java +++ b/src/main/java/neon/ai/HuntBehaviour.java @@ -43,7 +43,7 @@ public HuntBehaviour( this.prey = prey; this.gameContext = gameContext; this.gameStores = gameStores; - this.pathFinder = new PathFinder(gameStores.getStore(), gameContext.getPlayer()); + this.pathFinder = new PathFinder(gameStores.getStore()); } public void act() { diff --git a/src/main/java/neon/ai/PathFinder.java b/src/main/java/neon/ai/PathFinder.java index 8b75299..e4148e2 100644 --- a/src/main/java/neon/ai/PathFinder.java +++ b/src/main/java/neon/ai/PathFinder.java @@ -38,11 +38,9 @@ public class PathFinder { private static Point to; private static Creature mover; private final UIDStore uidStore; - private final Player player; - public PathFinder(UIDStore uidStore, Player player) { + public PathFinder(UIDStore uidStore) { this.uidStore = uidStore; - this.player = player; } public Point[] findPath(Creature creature, Point origin, Point destination) { @@ -71,7 +69,7 @@ public Point[] findPath(Creature creature, Point origin, Point destination) { links.put(to, next); next = null; break; - } else if (player.getCurrentZone().getRegion(neighbour).getMovMod() + } else if (uidStore.getPlayer().getCurrentZone().getRegion(neighbour).getMovMod() == Region.Modifier.BLOCK) { continue; // if terrain is blocked, skip to next point } @@ -133,7 +131,7 @@ private int manhattan(Point one, Point two) { private int terrainPenalty(Point neighbour) { // better modifiers? - return switch (player.getCurrentZone().getRegion(neighbour).getMovMod()) { + return switch (uidStore.getPlayer().getCurrentZone().getRegion(neighbour).getMovMod()) { case SWIM -> (100 - mover.getSkill(Skill.SWIMMING)) / 5; case CLIMB -> (100 - mover.getSkill(Skill.CLIMBING)) / 5; default -> 0; @@ -141,7 +139,7 @@ private int terrainPenalty(Point neighbour) { } private int doorPenalty(Point neighbour) { - for (long uid : player.getCurrentZone().getItems(neighbour)) { + for (long uid : uidStore.getPlayer().getCurrentZone().getItems(neighbour)) { if (uidStore.getEntity(uid) instanceof Door) { Door door = (Door) uidStore.getEntity(uid); if (door.lock.isLocked()) { diff --git a/src/main/java/neon/ai/ScheduleAI.java b/src/main/java/neon/ai/ScheduleAI.java index 2ec8061..c237c2a 100644 --- a/src/main/java/neon/ai/ScheduleAI.java +++ b/src/main/java/neon/ai/ScheduleAI.java @@ -37,22 +37,21 @@ public ScheduleAI( byte confidence, Point[] schedule, ResourceManager resourceManager, - UIDStore uidStore, - Player player) { - super(creature, aggression, confidence, resourceManager, uidStore, player); + UIDStore uidStore) { + super(creature, aggression, confidence, resourceManager, uidStore); this.schedule = schedule; } public void act() { - if (isHostile() && sees(player)) { + if (isHostile() && sees(uidStore.getPlayer())) { HealthComponent health = creature.getHealthComponent(); if (100 * health.getHealth() / health.getBaseHealth() < confidence) { // 80% chance to just flee, 20% chance to heal; if no heal spell, flee anyway if (Math.random() > 0.2 || !(cure() || heal())) { - flee(player); + flee(uidStore.getPlayer()); } } else { - hunt(player); + hunt(uidStore.getPlayer()); } } else { ShapeComponent bounds = creature.getShapeComponent(); diff --git a/src/main/java/neon/core/DefaultGameContext.java b/src/main/java/neon/core/DefaultGameContext.java index 64d387a..037b537 100644 --- a/src/main/java/neon/core/DefaultGameContext.java +++ b/src/main/java/neon/core/DefaultGameContext.java @@ -55,11 +55,6 @@ public class DefaultGameContext implements GameContext { // Game-level state (set when a game starts) @Setter private Game game; - @Override - public Player getPlayer() { - return game != null ? game.getPlayer() : null; - } - @Override public AtlasPosition getAtlasPosition() { return game != null ? game.getAtlasPosition() : null; diff --git a/src/main/java/neon/core/DefaultGameStores.java b/src/main/java/neon/core/DefaultGameStores.java index d2897e5..45dc189 100644 --- a/src/main/java/neon/core/DefaultGameStores.java +++ b/src/main/java/neon/core/DefaultGameStores.java @@ -23,16 +23,15 @@ public class DefaultGameStores implements GameStores { private final ZoneFactory zoneFactory; private final MapStore zoneMapStore; - public DefaultGameStores(ResourceManager resources, FileSystem fileSystem, Player player) { + public DefaultGameStores(ResourceManager resources, FileSystem fileSystem,UIDStore store) { this.resources = resources; this.fileSystem = fileSystem; // Phase 1: Create UIDStore without DataTypes - this.store = new UIDStore(fileSystem, fileSystem.getFullPath("uidstore")); + this.store = store; // Phase 2: Create EntityFactory with dependencies (GameContext is null at this stage) - EntityFactory entityFactory = new EntityFactory(this, null); - + EntityFactory entityFactory = new EntityFactory(resources, this.store); // Phase 3: Create DataTypes EntityDataType entityDataType = new EntityDataType(entityFactory); ModDataType modDataType = new ModDataType(); @@ -43,7 +42,7 @@ public DefaultGameStores(ResourceManager resources, FileSystem fileSystem, Playe // Continue with rest of initialization zoneMapStore = Atlas.getMapStore(fileSystem, "zones"); this.zoneFactory = new ZoneFactory(zoneMapStore, store, resources); - MapLoader mapLoader = new MapLoader(fileSystem, store, resources, zoneFactory, player); + MapLoader mapLoader = new MapLoader(fileSystem, store, resources, zoneFactory); atlas = new Atlas(fileSystem, zoneMapStore, store, resources, mapLoader); } } diff --git a/src/main/java/neon/core/Engine.java b/src/main/java/neon/core/Engine.java index 3707f61..a5e94e8 100644 --- a/src/main/java/neon/core/Engine.java +++ b/src/main/java/neon/core/Engine.java @@ -29,6 +29,7 @@ import neon.core.handlers.InventoryHandler; import neon.core.handlers.MagicHandler; import neon.entities.Player; +import neon.entities.UIDStore; import neon.maps.AtlasPosition; import neon.maps.services.EnginePhysicsManager; import neon.maps.services.PhysicsManager; @@ -101,8 +102,8 @@ public Engine(Port port) throws IOException { files = new FileSystem(); resources = new ResourceManager(); - - gameStores = new DefaultGameStores(resources, files, null); + UIDStore uidStore = new UIDStore(files.getFullPath("uidstore")); + gameStores = new DefaultGameStores(resources, files,uidStore); physics = new PhysicsSystem(); physicsManager = new EnginePhysicsManager(physics); queue = new TaskQueue(); @@ -179,8 +180,8 @@ public static Object execute(String script) { */ @Deprecated public static Player getPlayer() { - if (game != null) { - return game.getPlayer(); + if (gameStores != null) { + return gameStores.getStore().getPlayer(); } else return null; } @@ -271,7 +272,7 @@ public void startGame(Game game) { bus.subscribe(new MagicHandler(queue, gameStores, context)); // register player - Player player = game.getPlayer(); + Player player = gameStores.getStore().getPlayer(); engine.getBindings("js").putMember("journal", player.getJournal()); engine.getBindings("js").putMember("player", player); engine.getBindings("js").putMember("PC", player); diff --git a/src/main/java/neon/core/Game.java b/src/main/java/neon/core/Game.java index 94242ff..ed63d99 100644 --- a/src/main/java/neon/core/Game.java +++ b/src/main/java/neon/core/Game.java @@ -30,19 +30,16 @@ @Getter public class Game implements Closeable { - private final Player player; private final Timer timer = new Timer(); private final AtlasPosition atlasPosition; @Getter private final GameStores gameStores; public Game( - Player player, GameStores gameStores, PhysicsManager physicsManager, QuestTracker questTracker) { - this.player = player; this.gameStores = gameStores; - this.atlasPosition = new AtlasPosition(gameStores, questTracker, player); + this.atlasPosition = new AtlasPosition(gameStores, questTracker); } /** @@ -50,8 +47,7 @@ public Game( * * @param player the player */ - public Game(Player player, GameStores gameStores, AtlasPosition atlasPosition) { - this.player = player; + public Game( GameStores gameStores, AtlasPosition atlasPosition) { this.gameStores = gameStores; this.atlasPosition = atlasPosition; } diff --git a/src/main/java/neon/core/GameContext.java b/src/main/java/neon/core/GameContext.java index f9f20bf..dc02a5f 100644 --- a/src/main/java/neon/core/GameContext.java +++ b/src/main/java/neon/core/GameContext.java @@ -37,8 +37,6 @@ */ public interface GameContext { - Player getPlayer(); - AtlasPosition getAtlasPosition(); Timer getTimer(); diff --git a/src/main/java/neon/core/GameLoader.java b/src/main/java/neon/core/GameLoader.java index 4e61334..e0a7a18 100644 --- a/src/main/java/neon/core/GameLoader.java +++ b/src/main/java/neon/core/GameLoader.java @@ -82,8 +82,7 @@ public GameLoader(GameContext context, GameStores gameStores, Configuration conf gameStores.getFileSystem(), gameStores.getStore(), gameStores.getResources(), - gameStores.getZoneFactory(), - context.getPlayer()); + gameStores.getZoneFactory()); zoneFactory = new ZoneFactory( gameStores.getAtlas().getCache(), gameStores.getStore(), gameStores.getResources()); @@ -140,8 +139,9 @@ public void initGame( ItemFactory itemFactory = new ItemFactory(gameStores.getResources()); Player player = new Player(species, name, gender, spec, profession, gameStores.getStore()); player.species.text = "@"; + gameStores.getStore().setPlayer(player); context.startGame( - new Game(player, gameStores, context.getPhysicsManager(), context.getQuestTracker())); + new Game(gameStores, context.getPhysicsManager(), context.getQuestTracker())); setSign(player, sign); for (Skill skill : Skill.values()) { SkillHandler.checkFeat(skill, player); @@ -232,11 +232,11 @@ private void loadGame(String save) { loadEvents(saveModel.events); // quests - Player player = context.getPlayer(); + Player player = gameStores.getStore().getPlayer(); if (player != null) { for (SaveGameModel.QuestEntry quest : saveModel.journal.quests) { - context.getPlayer().getJournal().addQuest(quest.id, quest.subject); - context.getPlayer().getJournal().updateQuest(quest.id, quest.stage); + gameStores.getStore().getPlayer().getJournal().addQuest(quest.id, quest.subject); + gameStores.getStore().getPlayer().getJournal().updateQuest(quest.id, quest.stage); } } else { System.out.println("Skipping journal update"); @@ -297,8 +297,9 @@ private void loadPlayer(SaveGameModel.PlayerSaveData playerData) { Player.Specialisation.valueOf(playerData.specialisation), playerData.profession, gameStores.getStore()); + gameStores.getStore().setPlayer(player); context.startGame( - new Game(player, gameStores, context.getPhysicsManager(), context.getQuestTracker())); + new Game( gameStores, context.getPhysicsManager(), context.getQuestTracker())); Rectangle bounds = player.getShapeComponent(); bounds.setLocation(playerData.x, playerData.y); player.setSign(playerData.sign); diff --git a/src/main/java/neon/core/ScriptInterface.java b/src/main/java/neon/core/ScriptInterface.java index 018d66d..1ffdc9f 100644 --- a/src/main/java/neon/core/ScriptInterface.java +++ b/src/main/java/neon/core/ScriptInterface.java @@ -28,12 +28,10 @@ public class ScriptInterface { private final GamePanel panel; private final UIDStore uidStore; - private final GameContext gameContext; public ScriptInterface(GamePanel panel, UIDStore uidStore, GameContext gameContext) { this.panel = panel; this.uidStore = uidStore; - this.gameContext = gameContext; InputStream input = Engine.class.getResourceAsStream("scripts.js"); assert input != null; Scanner scanner = new Scanner(input, StandardCharsets.UTF_8); @@ -50,6 +48,6 @@ public Entity get(long uid) { } public Entity getPlayer() { - return gameContext.getPlayer(); + return uidStore.getPlayer(); } } diff --git a/src/main/java/neon/core/handlers/InventoryHandler.java b/src/main/java/neon/core/handlers/InventoryHandler.java index f67b399..4e19c8c 100644 --- a/src/main/java/neon/core/handlers/InventoryHandler.java +++ b/src/main/java/neon/core/handlers/InventoryHandler.java @@ -141,7 +141,7 @@ public void equip(Item item, Creature creature) { default: break; } - if (c.getMagicComponent().getSpell() != null) { + if (c.getMagicComponent() != null && c.getMagicComponent().getSpell() != null) { MagicUtils.equip(creature, (Clothing) item); } } else if (item instanceof Weapon) { diff --git a/src/main/java/neon/core/handlers/MagicHandler.java b/src/main/java/neon/core/handlers/MagicHandler.java index 1e1da34..1ea1225 100644 --- a/src/main/java/neon/core/handlers/MagicHandler.java +++ b/src/main/java/neon/core/handlers/MagicHandler.java @@ -110,8 +110,8 @@ public void cast(MagicEvent.OnPoint me) { for (Creature creature : creatures) { castSpell(creature, null, spell); } - if (box.contains(gameContext.getPlayer().getShapeComponent())) { - castSpell(gameContext.getPlayer(), null, spell); + if (box.contains(gameStores.getStore().getPlayer().getShapeComponent())) { + castSpell(gameStores.getStore().getPlayer(), null, spell); } } } @@ -179,8 +179,8 @@ public void cast(MagicEvent.CreatureOnPoint me) { } else { Collection creatures = gameContext.getAtlasPosition().getCurrentZone().getCreatures(box); - if (box.contains(gameContext.getPlayer().getShapeComponent())) { - creatures.add(gameContext.getPlayer()); + if (box.contains(gameStores.getStore().getPlayer().getShapeComponent())) { + creatures.add(gameStores.getStore().getPlayer()); } for (Creature creature : creatures) { castSpell(creature, caster, formula); @@ -240,8 +240,8 @@ public void cast(MagicEvent.ItemOnPoint me) { } else { Collection creatures = gameContext.getAtlasPosition().getCurrentZone().getCreatures(box); - if (box.contains(gameContext.getPlayer().getShapeComponent())) { - creatures.add(gameContext.getPlayer()); + if (box.contains(gameStores.getStore().getPlayer().getShapeComponent())) { + creatures.add(gameStores.getStore().getPlayer()); } for (Creature creature : creatures) { castSpell(creature, caster, formula); diff --git a/src/main/java/neon/core/handlers/MotionHandler.java b/src/main/java/neon/core/handlers/MotionHandler.java index 19fb413..9be5747 100644 --- a/src/main/java/neon/core/handlers/MotionHandler.java +++ b/src/main/java/neon/core/handlers/MotionHandler.java @@ -45,11 +45,9 @@ public class MotionHandler { public static final byte NULL = 5; public static final byte HABITAT = 6; public final UIDStore uidStore; - private final Player player; - public MotionHandler(UIDStore uidStore, Player player) { + public MotionHandler(UIDStore uidStore) { this.uidStore = uidStore; - this.player = player; } /** @@ -70,13 +68,13 @@ public MotionHandler(UIDStore uidStore, Player player) { * @return the result of the movement */ public byte move(Creature actor, Point p) { - Region region = player.getCurrentZone().getRegion(p); + Region region = uidStore.getPlayer().getCurrentZone().getRegion(p); if (p == null || region == null) { return NULL; } // check if there is no closed door present - Collection items = player.getCurrentZone().getItems(p); + Collection items = uidStore.getPlayer().getCurrentZone().getItems(p); for (long uid : items) { Entity i = uidStore.getEntity(uid); if (i instanceof Door) { diff --git a/src/main/java/neon/core/handlers/TeleportHandler.java b/src/main/java/neon/core/handlers/TeleportHandler.java index 586626e..e53f8d0 100644 --- a/src/main/java/neon/core/handlers/TeleportHandler.java +++ b/src/main/java/neon/core/handlers/TeleportHandler.java @@ -34,9 +34,8 @@ public TeleportHandler( gameStores.getFileSystem(), gameStores.getStore(), gameStores.getResources(), - gameStores.getZoneFactory(), - gameContext.getPlayer()); - this.motionHandler = new MotionHandler(gameStores.getStore(), gameContext.getPlayer()); + gameStores.getZoneFactory()); + this.motionHandler = new MotionHandler(gameStores.getStore()); } /** diff --git a/src/main/java/neon/core/handlers/TurnHandler.java b/src/main/java/neon/core/handlers/TurnHandler.java index 8695b64..61de766 100644 --- a/src/main/java/neon/core/handlers/TurnHandler.java +++ b/src/main/java/neon/core/handlers/TurnHandler.java @@ -82,8 +82,8 @@ public void tick(TurnEvent te) { } // monsters controleren - Player player = panel.getContext().getPlayer(); - for (long uid : panel.getContext().getAtlasPosition().getCurrentZone().getCreatures()) { + Player player = panel.getUidStore().getPlayer(); + for (long uid : panel.getGameContext().getAtlasPosition().getCurrentZone().getCreatures()) { Creature creature = (Creature) gameStores.getStore().getEntity(uid); if (!creature.hasCondition(Condition.DEAD)) { HealthComponent health = creature.getHealthComponent(); @@ -95,7 +95,7 @@ public void tick(TurnEvent te) { int spd = getSpeed(creature); Region region = panel - .getContext() + .getGameContext() .getAtlasPosition() .getCurrentZone() .getRegion(cBounds.getLocation()); @@ -120,8 +120,8 @@ public void tick(TurnEvent te) { player.getMagicComponent().addMana(player.getStatsComponent().getWis() / 100f); // en systems updaten - panel.getContext().getPhysicsEngine().update(); - panel.getContext().post(new UpdateEvent(this)); + panel.getGameContext().getPhysicsEngine().update(); + panel.getGameContext().post(new UpdateEvent(this)); } private class Generator extends Thread { @@ -129,7 +129,7 @@ private class Generator extends Thread { public void run() { // enkel repainten nadat er iets gegenereerd is if (checkRegions()) { - panel.getContext().post(new UpdateEvent(this)); + panel.getGameContext().post(new UpdateEvent(this)); } } } @@ -139,7 +139,7 @@ public void run() { */ private boolean checkRegions() { // die boolean is eigenlijk maar louche Rectangle window = panel.getVisibleRectangle(); - Zone zone = panel.getContext().getAtlasPosition().getCurrentZone(); + Zone zone = panel.getGameContext().getAtlasPosition().getCurrentZone(); boolean fixed = true; boolean generated = false; // om aan te geven dat er iets gegenereerd werd @@ -157,7 +157,7 @@ private boolean checkRegions() { // die boolean is eigenlijk maar louche .generate(r.getX(), r.getY(), r.getWidth(), r.getHeight(), theme, r.getZ()); } else { new WildernessGenerator( - zone, gameStores.getResources(), gameStores.getStore(), gameContext.getPlayer()) + zone, gameStores) .generate(r, theme); } } diff --git a/src/main/java/neon/editor/resources/RMap.java b/src/main/java/neon/editor/resources/RMap.java index adaee0a..cc91cf2 100644 --- a/src/main/java/neon/editor/resources/RMap.java +++ b/src/main/java/neon/editor/resources/RMap.java @@ -210,11 +210,11 @@ public WorldModel toWorldModel() { } else if (instance instanceof IObject) { IObject obj = (IObject) instance; if (instance instanceof IDoor) { - model.items.doors.add(convertDoor((IDoor) instance)); + model.doors.add(convertDoor((IDoor) instance)); } else if (instance instanceof IContainer) { - model.items.containers.add(convertContainer((IContainer) instance)); + model.containers.add(convertContainer((IContainer) instance)); } else { - model.items.items.add(convertItem(obj)); + model.items.add(convertItem(obj)); } } else if (instance instanceof IPerson) { model.creatures.add(convertCreature((IPerson) instance)); @@ -257,11 +257,11 @@ public DungeonModel toDungeonModel() { } else if (instance instanceof IObject) { IObject obj = (IObject) instance; if (instance instanceof IDoor) { - level.items.doors.add(convertDoor((IDoor) instance)); + level.doors.add(convertDoor((IDoor) instance)); } else if (instance instanceof IContainer) { - level.items.containers.add(convertContainer((IContainer) instance)); + level.containers.add(convertContainer((IContainer) instance)); } else { - level.items.items.add(convertItem(obj)); + level.items.add(convertItem(obj)); } } else if (instance instanceof IPerson) { level.creatures.add(convertCreature((IPerson) instance)); diff --git a/src/main/java/neon/entities/Creature.java b/src/main/java/neon/entities/Creature.java index a14af23..80f5641 100644 --- a/src/main/java/neon/entities/Creature.java +++ b/src/main/java/neon/entities/Creature.java @@ -37,16 +37,10 @@ public class Creature extends Entity { // components public final FactionComponent social; public final Stats stats; - public final RCreature species; public AI brain; - /** - * -- GETTER -- - * - * @return this creature's gender - */ - // miscellaneous - @Getter protected Gender gender; + @Getter @Setter public RCreature species; + @Getter @Setter private Gender gender; /** * -- GETTER -- diff --git a/src/main/java/neon/entities/CreatureFactory.java b/src/main/java/neon/entities/CreatureFactory.java index 22071bf..fbf3c2d 100644 --- a/src/main/java/neon/entities/CreatureFactory.java +++ b/src/main/java/neon/entities/CreatureFactory.java @@ -38,21 +38,12 @@ public class CreatureFactory { private final ResourceManager resourceManager; private final UIDStore uidStore; - public CreatureFactory(GameStores gameStores, Player player) { - inventoryHandler = new InventoryHandler(gameStores.getStore()); - spellFactory = new SpellFactory(gameStores.getResources()); - this.resourceManager = gameStores.getResources(); - this.uidStore = gameStores.getStore(); - this.aiFactory = new AIFactory(gameStores.getResources(), gameStores.getStore(), player); - this.itemFactory = new ItemFactory(gameStores.getResources()); - } - - public CreatureFactory(ResourceManager resourceManager, UIDStore uidStore, Player player) { + public CreatureFactory(ResourceManager resourceManager, UIDStore uidStore) { inventoryHandler = new InventoryHandler(uidStore); spellFactory = new SpellFactory(resourceManager); this.resourceManager = resourceManager; this.uidStore = uidStore; - this.aiFactory = new AIFactory(resourceManager, uidStore, player); + this.aiFactory = new AIFactory(resourceManager, uidStore); this.itemFactory = new ItemFactory(resourceManager); } diff --git a/src/main/java/neon/entities/Entity.java b/src/main/java/neon/entities/Entity.java index 35ab2cb..f383732 100644 --- a/src/main/java/neon/entities/Entity.java +++ b/src/main/java/neon/entities/Entity.java @@ -32,12 +32,11 @@ * * @author mdriesen */ -public abstract class Entity implements Serializable { +public abstract class Entity extends EntityBase implements Serializable { // components public final ShapeComponent bounds; - protected ClassToInstanceMap components = MutableClassToInstanceMap.create(); private long uid; private String id; @@ -47,9 +46,9 @@ public abstract class Entity implements Serializable { * @param uid */ public Entity(String id, long uid) { + super(); this.id = id; this.uid = uid; - // components bounds = new ShapeComponent(this, 0, 0, 1, 1); components.putInstance(PhysicsComponent.class, new PhysicsComponent(uid, bounds)); @@ -74,19 +73,5 @@ public ShapeComponent getShapeComponent() { return bounds; } - public RenderComponent getRenderComponent() { - return components.getInstance(RenderComponent.class); - } - - public void setRenderComponent(RenderComponent renderer) { - components.putInstance(RenderComponent.class, renderer); - } - public PhysicsComponent getPhysicsComponent() { - return components.getInstance(PhysicsComponent.class); - } - - public ScriptComponent getScriptComponent() { - return components.getInstance(ScriptComponent.class); - } } diff --git a/src/main/java/neon/entities/EntityBase.java b/src/main/java/neon/entities/EntityBase.java new file mode 100644 index 0000000..9274c40 --- /dev/null +++ b/src/main/java/neon/entities/EntityBase.java @@ -0,0 +1,27 @@ +package neon.entities; + +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.MutableClassToInstanceMap; +import neon.entities.components.*; + +import java.io.Serializable; + +public abstract class EntityBase implements Serializable { + protected ClassToInstanceMap components = MutableClassToInstanceMap.create(); + + public RenderComponent getRenderComponent() { + return components.getInstance(RenderComponent.class); + } + + public void setRenderComponent(RenderComponent renderer) { + components.putInstance(RenderComponent.class, renderer); + } + + public PhysicsComponent getPhysicsComponent() { + return components.getInstance(PhysicsComponent.class); + } + + public ScriptComponent getScriptComponent() { + return components.getInstance(ScriptComponent.class); + } +} diff --git a/src/main/java/neon/entities/Player.java b/src/main/java/neon/entities/Player.java index 2127910..70a0c6e 100644 --- a/src/main/java/neon/entities/Player.java +++ b/src/main/java/neon/entities/Player.java @@ -64,12 +64,12 @@ public Player( Gender gender, Specialisation spec, String profession, - UIDStore gameStores) { + UIDStore uidStore) { super(species.id, 0, species); - this.uidStore = gameStores; + this.uidStore = uidStore; components.putInstance(RenderComponent.class, new PlayerRenderComponent(this)); this.name = name; - this.gender = gender; + this.setGender(gender); this.spec = spec; this.profession = profession; baseLevel = getLevel(); diff --git a/src/main/java/neon/entities/UIDStore.java b/src/main/java/neon/entities/UIDStore.java index 7f2dca7..fc178f3 100644 --- a/src/main/java/neon/entities/UIDStore.java +++ b/src/main/java/neon/entities/UIDStore.java @@ -21,8 +21,9 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import java.io.*; -import java.util.Map; +import java.util.concurrent.ConcurrentMap; import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import neon.entities.mvstore.EntityDataType; import neon.entities.mvstore.LongDataType; @@ -45,29 +46,32 @@ public class UIDStore implements EntityStore, Closeable { // dummy uid for objects that don't actually exist public static final long DUMMY = 0; - @Getter private final FileSystem fileSystem; + // uid database @Getter private final MapStore uidDb; // uids of all objects in the game - private Map objects; + private ConcurrentMap objects; // uids of all loaded mods - private Map mods; + private ConcurrentMap mods; // uids of all loaded maps private final BiMap maps = HashBiMap.create(); - + @Getter @Setter + private Player player; /** * Tells this UIDStore to use the given jdbm3 cache. * * @param file */ - public UIDStore(FileSystem fileSystem, String file) { - this.fileSystem = fileSystem; - uidDb = new MapStoreMVStoreAdapter(MVStore.open(file)); + public UIDStore(String file) { + if (file == null) { + uidDb = new MapStoreMVStoreAdapter(MVStore.open(null)); + } else { + uidDb = new MapStoreMVStoreAdapter(MVStore.open(file)); + } // Maps will be opened after DataTypes are set via setDataTypes() } - public UIDStore(FileSystem fileSystem, MapStore mapStore) { - this.fileSystem = fileSystem; + public UIDStore(MapStore mapStore) { uidDb = mapStore; // Maps will be opened after DataTypes are set via setDataTypes() } diff --git a/src/main/java/neon/entities/components/Animus.java b/src/main/java/neon/entities/components/Animus.java index 637ae33..99df584 100644 --- a/src/main/java/neon/entities/components/Animus.java +++ b/src/main/java/neon/entities/components/Animus.java @@ -162,7 +162,7 @@ public void addMana(float amount) { */ public int getMana() { return (int) - (creature.getStatsComponent().getInt() * creature.species.mana + baseManaMod + manaMod); + (creature.getStatsComponent().getInt() * creature.getSpecies().mana + baseManaMod + manaMod); } /** diff --git a/src/main/java/neon/entities/components/Inventory.java b/src/main/java/neon/entities/components/Inventory.java index fa04583..a0a2234 100644 --- a/src/main/java/neon/entities/components/Inventory.java +++ b/src/main/java/neon/entities/components/Inventory.java @@ -23,13 +23,14 @@ import java.util.Iterator; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; +import lombok.Getter; import neon.entities.property.Slot; public class Inventory implements Iterable, Component { private final long uid; - private CopyOnWriteArrayList items; - private EnumMap equiped; - private int money = 0; + private final CopyOnWriteArrayList items; + private final EnumMap equiped; + @Getter private int money = 0; public Inventory(long owner) { equiped = new EnumMap(Slot.class); @@ -37,10 +38,6 @@ public Inventory(long owner) { uid = owner; } - public int getMoney() { - return money; - } - public void addMoney(int amount) { money += amount; } diff --git a/src/main/java/neon/entities/serialization/CreatureSerializer.java b/src/main/java/neon/entities/serialization/CreatureSerializer.java index 22fd80b..bd26fce 100644 --- a/src/main/java/neon/entities/serialization/CreatureSerializer.java +++ b/src/main/java/neon/entities/serialization/CreatureSerializer.java @@ -23,8 +23,6 @@ import java.io.DataOutput; import java.io.IOException; import neon.ai.AIFactory; -import neon.core.GameContext; -import neon.core.GameStores; import neon.entities.*; import neon.entities.components.HealthComponent; import neon.entities.property.Slot; @@ -39,16 +37,12 @@ public class CreatureSerializer { private final SpellFactory spellFactory; private final ResourceManager resourceManager; - - public CreatureSerializer(ResourceManager resourceManager, UIDStore uidStore, Player player) { + public CreatureSerializer(ResourceManager resourceManager, UIDStore uidStore) { spellFactory = new SpellFactory(resourceManager); this.resourceManager = resourceManager; // AIFactory can be null if gameContext is null (for write-only or test scenarios) - aiFactory = - new AIFactory( - resourceManager, uidStore, player); - + aiFactory = new AIFactory(resourceManager, uidStore); } public Creature deserialize(DataInput in) throws IOException { @@ -99,7 +93,7 @@ public Creature deserialize(DataInput in) throws IOException { public void serialize(DataOutput out, Creature creature) throws IOException { out.writeUTF(creature.getID()); - out.writeUTF(creature.species.id); + out.writeUTF(creature.getSpecies().id); Rectangle bounds = creature.getShapeComponent(); out.writeInt(bounds.x); out.writeInt(bounds.y); diff --git a/src/main/java/neon/entities/serialization/EntityFactory.java b/src/main/java/neon/entities/serialization/EntityFactory.java index c0cd1ef..de67019 100644 --- a/src/main/java/neon/entities/serialization/EntityFactory.java +++ b/src/main/java/neon/entities/serialization/EntityFactory.java @@ -20,13 +20,10 @@ import java.io.IOException; import java.nio.ByteBuffer; -import neon.core.GameContext; -import neon.core.GameStores; -import neon.entities.Creature; -import neon.entities.Entity; -import neon.entities.Item; +import neon.entities.*; import neon.entities.mvstore.ByteBufferDataInput; import neon.entities.mvstore.ByteBufferDataOutput; +import neon.resources.ResourceManager; import org.h2.mvstore.WriteBuffer; /** @@ -50,9 +47,9 @@ public class EntityFactory { * @param gameContext the game context for AI initialization (can be null for write-only * operations) */ - public EntityFactory(GameStores gameStores, GameContext gameContext) { - this.itemSerializer = new ItemSerializer(gameStores); - this.creatureSerializer = new CreatureSerializer(gameStores, gameContext); + public EntityFactory(ResourceManager resourceManager, UIDStore uidStore) { + this.itemSerializer = new ItemSerializer(resourceManager); + this.creatureSerializer = new CreatureSerializer(resourceManager, uidStore); } /** diff --git a/src/main/java/neon/entities/serialization/EntitySerializer.java b/src/main/java/neon/entities/serialization/EntitySerializer.java index 4b2a21c..615010c 100644 --- a/src/main/java/neon/entities/serialization/EntitySerializer.java +++ b/src/main/java/neon/entities/serialization/EntitySerializer.java @@ -34,8 +34,10 @@ public class EntitySerializer { private final GameContext gameContext; EntitySerializer(GameStores gameStores, GameContext gameContext) { - itemSerializer = new ItemSerializer(gameStores); - creatureSerializer = new CreatureSerializer(gameStores, gameContext); + itemSerializer = new ItemSerializer(gameStores.getResources()); + creatureSerializer = + new CreatureSerializer( + gameStores.getResources(), gameStores.getStore()); this.gameContext = gameContext; } diff --git a/src/main/java/neon/entities/serialization/ItemSerializer.java b/src/main/java/neon/entities/serialization/ItemSerializer.java index 80fdcf3..60cb292 100644 --- a/src/main/java/neon/entities/serialization/ItemSerializer.java +++ b/src/main/java/neon/entities/serialization/ItemSerializer.java @@ -23,7 +23,6 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import neon.core.GameStores; import neon.entities.Armor; import neon.entities.Container; import neon.entities.Door; @@ -36,6 +35,7 @@ import neon.entities.components.Trap; import neon.magic.SpellFactory; import neon.resources.RItem; +import neon.resources.ResourceManager; /** * This class takes care of (de)serialization of {@code Item}s. @@ -43,15 +43,14 @@ * @author mdriesen */ public class ItemSerializer { - - private final GameStores gameStores; + private final ResourceManager resourceManager; private final ItemFactory itemFactory; private final SpellFactory spellFactory; - public ItemSerializer(GameStores gameStores) { - this.gameStores = gameStores; - itemFactory = new ItemFactory(gameStores.getResources()); - spellFactory = new SpellFactory(gameStores.getResources()); + public ItemSerializer(ResourceManager resourceManager) { + this.resourceManager = resourceManager; + itemFactory = new ItemFactory(resourceManager); + spellFactory = new SpellFactory(resourceManager); } public Item deserialize(DataInput input) throws IOException { @@ -67,21 +66,21 @@ public Item deserialize(DataInput input) throws IOException { readEnchantment(input, item, uid); } - if (item instanceof Door) { - Door door = (Door) item; - door.setSign(input.readUTF()); - readPortal(input, door.portal); - readLock(input, door.lock); - readTrap(input, door.trap); - } else if (item instanceof Container) { - Container container = (Container) item; - readLock(input, container.lock); - readTrap(input, container.trap); - readContents(input, container); - } else if (item instanceof Armor) { - ((Armor) item).setState(input.readInt()); - } else if (item instanceof Weapon) { - ((Weapon) item).setState(input.readInt()); + switch (item) { + case Door door -> { + door.setSign(input.readUTF()); + readPortal(input, door.portal); + readLock(input, door.lock); + readTrap(input, door.trap); + } + case Container container -> { + readLock(input, container.lock); + readTrap(input, container.trap); + readContents(input, container); + } + case Armor armor -> armor.setState(input.readInt()); + case Weapon weapon -> weapon.setState(input.readInt()); + default -> {} } return item; @@ -103,21 +102,21 @@ public void serialize(DataOutput output, Item item) throws IOException { output.writeBoolean(false); } - if (item instanceof Door) { - Door door = (Door) item; - output.writeUTF(door.toString()); - writePortal(output, door.portal); - writeLock(output, door.lock); - writeTrap(output, door.trap); - } else if (item instanceof Container) { - Container container = (Container) item; - writeLock(output, container.lock); - writeTrap(output, container.trap); - writeContents(output, container); - } else if (item instanceof Armor) { - output.writeInt(((Armor) item).getState()); - } else if (item instanceof Weapon) { - output.writeInt(((Weapon) item).getState()); + switch (item) { + case Door door -> { + output.writeUTF(door.toString()); + writePortal(output, door.portal); + writeLock(output, door.lock); + writeTrap(output, door.trap); + } + case Container container -> { + writeLock(output, container.lock); + writeTrap(output, container.trap); + writeContents(output, container); + } + case Armor armor -> output.writeInt(armor.getState()); + case Weapon weapon -> output.writeInt(weapon.getState()); + default -> {} } } @@ -192,7 +191,7 @@ private void readLock(DataInput input, Lock lock) throws IOException { lock.setState(input.readInt()); String id = input.readUTF(); if (!id.isEmpty()) { - lock.setKey((RItem) gameStores.getResources().getResource(id)); + lock.setKey((RItem) resourceManager.getResource(id)); } } diff --git a/src/main/java/neon/maps/AtlasPosition.java b/src/main/java/neon/maps/AtlasPosition.java index 24bda8c..76cc7f3 100644 --- a/src/main/java/neon/maps/AtlasPosition.java +++ b/src/main/java/neon/maps/AtlasPosition.java @@ -13,14 +13,12 @@ public class AtlasPosition { // private int currentMap = 0; private final Atlas atlas; private final QuestTracker questProvider; - @Getter private final Player player; private final GameStores gameStores; public final ZoneFactory zoneFactory; - public AtlasPosition(GameStores gameStores, QuestTracker questProvider, Player player) { + public AtlasPosition(GameStores gameStores, QuestTracker questProvider) { this.atlas = gameStores.getAtlas(); this.questProvider = questProvider; - this.player = player; this.gameStores = gameStores; zoneFactory = new ZoneFactory(gameStores); } @@ -29,21 +27,21 @@ public AtlasPosition(GameStores gameStores, QuestTracker questProvider, Player p * @return the current map */ public Map getCurrentMap() { - return player.getCurrentMap(); + return gameStores.getStore().getPlayer().getCurrentMap(); } /** * @return the current zone */ public Zone getCurrentZone() { - return player.getCurrentZone(); + return gameStores.getStore().getPlayer().getCurrentZone(); } /** * @return the current zone */ public int getCurrentZoneIndex() { - return player.getCurrentZone().getIndex(); + return gameStores.getStore().getPlayer().getCurrentZone().getIndex(); } /** @@ -73,7 +71,7 @@ public void enterZone(Door door, Zone previousZone, Player player) { } if (getCurrentMap() instanceof Dungeon && getCurrentZone().isRandom()) { - new DungeonGenerator(getCurrentZone(), (QuestProvider) questProvider, player, gameStores) + new DungeonGenerator(getCurrentZone(), (QuestProvider) questProvider, gameStores) .generate(door, previousZone, atlas); } } @@ -85,7 +83,7 @@ public void enterZone(Door door, Zone previousZone, Player player) { */ public void setMap(Map map) { atlas.putMapIfNeeded(map); - player.setCurrentMap(map); + gameStores.getStore().getPlayer().setCurrentMap(map); } /** @@ -95,7 +93,7 @@ public void setMap(Map map) { */ public void setMap(World map) { atlas.putMapIfNeeded(map); - player.setCurrentMap(map); - player.setCurrentZone(map.getZone()); + gameStores.getStore().getPlayer().setCurrentMap(map); + gameStores.getStore().getPlayer().setCurrentZone(map.getZone()); } } diff --git a/src/main/java/neon/maps/MapLoader.java b/src/main/java/neon/maps/MapLoader.java index f3cebcd..0b067a5 100644 --- a/src/main/java/neon/maps/MapLoader.java +++ b/src/main/java/neon/maps/MapLoader.java @@ -49,16 +49,14 @@ public class MapLoader { private final ResourceManager resourceManager; private final FileSystem fileSystem; private final ZoneFactory zoneFactory; - @Setter private Player player; /** Creates a MapLoader with dependency injection. */ public MapLoader( FileSystem fileSystem, UIDStore uidStore, ResourceManager resourceManager, - ZoneFactory zoneFactory, - Player player) { - this(fileSystem, uidStore, resourceManager, new MapUtils(), zoneFactory, player); + ZoneFactory zoneFactory) { + this(fileSystem, uidStore, resourceManager, new MapUtils(), zoneFactory); } /** @@ -71,14 +69,12 @@ public MapLoader( UIDStore uidStore, ResourceManager resourceManager, MapUtils mapUtils, - ZoneFactory zoneFactory, - Player player) { + ZoneFactory zoneFactory) { this.fileSystem = fileSystem; this.uidStore = uidStore; this.resourceManager = resourceManager; this.mapUtils = mapUtils; this.zoneFactory = zoneFactory; - this.player = player; } /** @@ -182,7 +178,7 @@ private World buildWorldFromModel(WorldModel model, int uid) { World world = new World(model.header.name, uid, zoneFactory); Zone zone = world.getZone(0); // outdoor maps have only zone 0 ItemFactory itemFactory = new ItemFactory(resourceManager); - CreatureFactory creatureFactory = new CreatureFactory(resourceManager, uidStore, player); + CreatureFactory creatureFactory = new CreatureFactory(resourceManager, uidStore); // Add regions for (WorldModel.RegionData regionData : model.regions) { Region region = buildRegionFromModel(regionData); @@ -198,7 +194,7 @@ private World buildWorldFromModel(WorldModel model, int uid) { } // Add items (simple items) - for (WorldModel.ItemPlacement ip : model.items.items) { + for (WorldModel.ItemPlacement ip : model.items) { long itemUID = UIDStore.getObjectUID(uid, ip.uid); Item item = itemFactory.getItem(ip.id, ip.x, ip.y, itemUID); uidStore.addEntity(item); @@ -206,7 +202,7 @@ private World buildWorldFromModel(WorldModel model, int uid) { } // Add doors - for (WorldModel.DoorPlacement dp : model.items.doors) { + for (WorldModel.DoorPlacement dp : model.doors) { long doorUID = UIDStore.getObjectUID(uid, dp.uid); Door door = buildDoorFromModel(dp, uid, doorUID, itemFactory); uidStore.addEntity(door); @@ -214,7 +210,7 @@ private World buildWorldFromModel(WorldModel model, int uid) { } // Add containers - for (WorldModel.ContainerPlacement cp : model.items.containers) { + for (WorldModel.ContainerPlacement cp : model.containers) { long containerUID = UIDStore.getObjectUID(uid, cp.uid); Container container = buildContainerFromModel(cp, uid, containerUID, itemFactory); uidStore.addEntity(container); @@ -237,7 +233,7 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { return loadThemedDungeon(model.header.name, model.header.theme, uid); } ItemFactory itemFactory = new ItemFactory(resourceManager); - CreatureFactory creatureFactory = new CreatureFactory(resourceManager, uidStore, player); + CreatureFactory creatureFactory = new CreatureFactory(resourceManager, uidStore); Dungeon dungeon = new Dungeon(model.header.name, uid, zoneFactory); for (DungeonModel.Level levelData : model.levels) { @@ -274,7 +270,7 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { } // Add items - for (WorldModel.ItemPlacement ip : levelData.items.items) { + for (WorldModel.ItemPlacement ip : levelData.items) { long itemUID = UIDStore.getObjectUID(uid, ip.uid); Item item = itemFactory.getItem(ip.id, ip.x, ip.y, itemUID); uidStore.addEntity(item); @@ -282,7 +278,7 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { } // Add doors - for (WorldModel.DoorPlacement dp : levelData.items.doors) { + for (WorldModel.DoorPlacement dp : levelData.doors) { long doorUID = UIDStore.getObjectUID(uid, dp.uid); Door door = buildDoorFromModel(dp, uid, doorUID, itemFactory); uidStore.addEntity(door); @@ -290,7 +286,7 @@ private Dungeon buildDungeonFromModel(DungeonModel model, int uid) { } // Add containers - for (WorldModel.ContainerPlacement cp : levelData.items.containers) { + for (WorldModel.ContainerPlacement cp : levelData.containers) { long containerUID = UIDStore.getObjectUID(uid, cp.uid); Container container = buildContainerFromModel(cp, uid, containerUID, itemFactory); uidStore.addEntity(container); diff --git a/src/main/java/neon/maps/Zone.java b/src/main/java/neon/maps/Zone.java index bea76c9..69ac10b 100644 --- a/src/main/java/neon/maps/Zone.java +++ b/src/main/java/neon/maps/Zone.java @@ -29,6 +29,7 @@ import neon.resources.ResourceManager; import neon.ui.graphics.*; import neon.util.spatial.*; +import org.jetbrains.annotations.NotNull; public class Zone /* implements Externalizable */ { private static final ZComparator comparator = new ZComparator(); @@ -266,7 +267,7 @@ public Collection getRegions() { return regions.getElements(); } - public void addItem(Item item) { + public void addItem(@NotNull Item item) { Rectangle bounds = item.getShapeComponent(); if (item.resource.top) { top.insert(item.getUID(), bounds); diff --git a/src/main/java/neon/maps/ZoneFactory.java b/src/main/java/neon/maps/ZoneFactory.java index 203377d..7a6523a 100644 --- a/src/main/java/neon/maps/ZoneFactory.java +++ b/src/main/java/neon/maps/ZoneFactory.java @@ -72,41 +72,6 @@ public Zone createZoneWithTheme(String name, int map, int index, RZoneTheme them return new Zone(name, map, theme, index, uidStore, resourceManager, regions); } - public Zone readZoneFromExternal(ObjectInput in) throws IOException, ClassNotFoundException { - int index = in.readInt(); - int map = in.readInt(); - String name = in.readUTF(); - String t = in.readUTF(); - Zone theZone; - if (!t.isEmpty()) { - RZoneTheme theme = (RZoneTheme) resourceManager.getResource(t, "theme"); - theZone = createZoneWithTheme(name, map, index, theme); - } else { - theZone = createZone(name, map, index); - } - - int iSize = in.readInt(); - for (int i = 0; i < iSize; i++) { - long uid = in.readLong(); - Item item = (Item) uidStore.getEntity(uid); - theZone.addItem(item); - } - int tSize = in.readInt(); - for (int i = 0; i < tSize; i++) { - long uid = in.readLong(); - Item item = (Item) uidStore.getEntity(uid); - theZone.addItem(item); - } - - int cSize = in.readInt(); - for (int i = 0; i < cSize; i++) { - long uid = in.readLong(); - Rectangle bounds = uidStore.getEntity(uid).getShapeComponent(); - theZone.addCreature(uid, bounds); - } - - return theZone; - } public Zone readZoneByteBuffer(ByteBuffer in) throws IOException, ClassNotFoundException { int index = in.getInt(); @@ -173,30 +138,4 @@ public void writeZoneToWriteBuffer(WriteBuffer out, Zone zone) throws IOExceptio } } - public void writeZoneToExternal(ObjectOutput out, Zone zone) throws IOException { - out.writeInt(zone.getIndex()); - out.writeInt(zone.getMap()); - out.writeUTF(zone.getName()); - if (zone.getTheme() != null) { - out.writeUTF(zone.getTheme().id); - } else { - out.writeUTF(""); - } - - // items - out.writeInt(zone.getItems().size()); - for (long l : zone.getItems()) { - out.writeLong(l); - } - out.writeInt(zone.getTopSize()); - for (long l : zone.getTopElements()) { - out.writeLong(l); - } - - // creatures - out.writeInt(zone.getCreatures().size()); - for (long l : zone.getCreatures()) { - out.writeLong(l); - } - } } diff --git a/src/main/java/neon/maps/generators/DungeonGenerator.java b/src/main/java/neon/maps/generators/DungeonGenerator.java index 3978b5a..86285ad 100644 --- a/src/main/java/neon/maps/generators/DungeonGenerator.java +++ b/src/main/java/neon/maps/generators/DungeonGenerator.java @@ -52,7 +52,6 @@ public class DungeonGenerator { private final QuestProvider questProvider; private final ItemFactory itemFactory; private final CreatureFactory creatureFactory; - private final Player player; private final GameStores gameStores; // random sources private final MapUtils mapUtils; @@ -73,8 +72,8 @@ public class DungeonGenerator { * @param questProvider the quest provider service */ public DungeonGenerator( - RZoneTheme theme, QuestProvider questProvider, Player player, GameStores gameStores) { - this(theme, questProvider, player, gameStores, new MapUtils(), new Dice()); + RZoneTheme theme, QuestProvider questProvider, GameStores gameStores) { + this(theme, questProvider, gameStores, new MapUtils(), new Dice()); } /** @@ -90,12 +89,10 @@ public DungeonGenerator( public DungeonGenerator( RZoneTheme theme, QuestProvider questProvider, - Player player, GameStores gameStores, MapUtils mapUtils, Dice dice) { this.theme = theme; - this.player = player; this.gameStores = gameStores; this.zone = null; this.entityStore = gameStores.getStore(); @@ -105,7 +102,7 @@ public DungeonGenerator( this.dice = dice; dungeonTerrainGenerator = new DungeonTerrainGenerator(mapUtils, dice); this.itemFactory = new ItemFactory(gameStores.getResources()); - this.creatureFactory = new CreatureFactory(gameStores, player); + this.creatureFactory = new CreatureFactory(gameStores.getResources(),gameStores.getStore()); } /** @@ -117,8 +114,8 @@ public DungeonGenerator( * @param questProvider the quest provider service */ public DungeonGenerator( - Zone zone, QuestProvider questProvider, Player player, GameStores gameStores) { - this(zone, questProvider, player, gameStores, new MapUtils(), new Dice()); + Zone zone, QuestProvider questProvider, GameStores gameStores) { + this(zone, questProvider, gameStores, new MapUtils(), new Dice()); } /** @@ -135,7 +132,6 @@ public DungeonGenerator( public DungeonGenerator( Zone zone, QuestProvider questProvider, - Player player, GameStores gameStores, MapUtils mapUtils, Dice dice) { @@ -144,14 +140,13 @@ public DungeonGenerator( this.entityStore = gameStores.getStore(); this.resourceProvider = gameStores.getResources(); this.questProvider = questProvider; - this.player = player; this.gameStores = gameStores; this.mapUtils = mapUtils; this.dice = dice; dungeonTerrainGenerator = new DungeonTerrainGenerator(mapUtils, dice); this.itemFactory = new ItemFactory(gameStores.getResources()); // CreatureFactory needs GameContext too, create minimal wrapper - this.creatureFactory = new CreatureFactory(gameStores, player); + this.creatureFactory = new CreatureFactory(gameStores.getResources(),gameStores.getStore()); } /** diff --git a/src/main/java/neon/maps/generators/WildernessGenerator.java b/src/main/java/neon/maps/generators/WildernessGenerator.java index 8f15282..1f90433 100644 --- a/src/main/java/neon/maps/generators/WildernessGenerator.java +++ b/src/main/java/neon/maps/generators/WildernessGenerator.java @@ -68,8 +68,8 @@ public class WildernessGenerator { * @param entityStore the entity store service * @param resourceProvider the resource provider service */ - public WildernessGenerator(Zone zone, GameStores gameStores, Player gameContext) { - this(zone, gameStores, gameContext, new MapUtils(), new Dice()); + public WildernessGenerator(Zone zone, GameStores gameStores) { + this(zone, gameStores, new MapUtils(), new Dice()); } /** @@ -82,26 +82,25 @@ public WildernessGenerator(Zone zone, GameStores gameStores, Player gameContext) * @param dice the Dice instance for random operations */ public WildernessGenerator( - Zone zone, GameStores gameStores, Player gameContext, MapUtils mapUtils, Dice dice) { + Zone zone, GameStores gameStores, MapUtils mapUtils, Dice dice) { this.zone = zone; this.entityStore = gameStores.getStore(); this.resourceProvider = gameStores.getResources(); this.dice = dice; this.wildernessTerrainGenerator = new WildernessTerrainGenerator(mapUtils, dice); this.itemFactory = new ItemFactory(gameStores.getResources()); - this.creatureFactory = new CreatureFactory(gameStores, gameContext); + this.creatureFactory = new CreatureFactory(gameStores.getResources(),gameStores.getStore()); } public WildernessGenerator( - Zone zone, ResourceManager resourceManeger, UIDStore uidStore, Player gameContext) { - this(zone, resourceManeger, uidStore, gameContext, new MapUtils(), new Dice()); + Zone zone, ResourceManager resourceManeger, UIDStore uidStore) { + this(zone, resourceManeger, uidStore, new MapUtils(), new Dice()); } public WildernessGenerator( Zone zone, ResourceManager resourceManeger, UIDStore uidStore, - Player gameContext, MapUtils mapUtils, Dice dice) { this.zone = zone; @@ -110,7 +109,7 @@ public WildernessGenerator( this.dice = dice; this.wildernessTerrainGenerator = new WildernessTerrainGenerator(mapUtils, dice); this.itemFactory = new ItemFactory(resourceManeger); - this.creatureFactory = new CreatureFactory(resourceManeger, uidStore, gameContext); + this.creatureFactory = new CreatureFactory(resourceManeger, uidStore); } /** @@ -124,14 +123,14 @@ public WildernessGenerator( * @param dice the Dice instance for random operations */ public WildernessGenerator( - String[][] terrain, GameStores gameStores, Player gameContext, MapUtils mapUtils, Dice dice) { + String[][] terrain, GameStores gameStores, MapUtils mapUtils, Dice dice) { this.terrain = terrain; this.entityStore = gameStores.getStore(); this.resourceProvider = gameStores.getResources(); this.dice = dice; this.wildernessTerrainGenerator = new WildernessTerrainGenerator(mapUtils, dice); this.itemFactory = new ItemFactory(gameStores.getResources()); - this.creatureFactory = new CreatureFactory(gameStores, gameContext); + this.creatureFactory = new CreatureFactory(gameStores.getResources(),gameStores.getStore()); } /** Generates a piece of wilderness using the supplied parameters. */ diff --git a/src/main/java/neon/maps/model/DungeonModel.java b/src/main/java/neon/maps/model/DungeonModel.java index db23cd3..dcf6678 100644 --- a/src/main/java/neon/maps/model/DungeonModel.java +++ b/src/main/java/neon/maps/model/DungeonModel.java @@ -63,8 +63,16 @@ public static class Level { public List creatures = new ArrayList<>(); @JacksonXmlElementWrapper(localName = "items") - @JacksonXmlProperty(localName = "items") - public WorldModel.ItemsWrapper items = new WorldModel.ItemsWrapper(); + @JacksonXmlProperty(localName = "item") + public List items = new ArrayList<>(); + + @JacksonXmlElementWrapper(localName = "doors") + @JacksonXmlProperty(localName = "door") + public List doors = new ArrayList<>(); + + @JacksonXmlElementWrapper(localName = "containers") + @JacksonXmlProperty(localName = "container") + public List containers = new ArrayList<>(); @JacksonXmlElementWrapper(localName = "regions") @JacksonXmlProperty(localName = "region") diff --git a/src/main/java/neon/maps/model/WorldModel.java b/src/main/java/neon/maps/model/WorldModel.java index b56655c..9d8896f 100644 --- a/src/main/java/neon/maps/model/WorldModel.java +++ b/src/main/java/neon/maps/model/WorldModel.java @@ -45,27 +45,21 @@ public class WorldModel { public List creatures = new ArrayList<>(); @JacksonXmlElementWrapper(localName = "items") - @JacksonXmlProperty(localName = "items") - public ItemsWrapper items = new ItemsWrapper(); + @JacksonXmlProperty(localName = "item") + public List items = new ArrayList<>(); + + @JacksonXmlElementWrapper(localName = "doors") + @JacksonXmlProperty(localName = "door") + public List doors = new ArrayList<>(); + + @JacksonXmlElementWrapper(localName = "containers") + @JacksonXmlProperty(localName = "container") + public List containers = new ArrayList<>(); @JacksonXmlElementWrapper(localName = "regions") @JacksonXmlProperty(localName = "region") public List regions = new ArrayList<>(); - /** Wrapper for all item types (items, doors, containers) */ - public static class ItemsWrapper { - @JacksonXmlElementWrapper(useWrapping = false) - @JacksonXmlProperty(localName = "item") - public List items = new ArrayList<>(); - - @JacksonXmlElementWrapper(useWrapping = false) - @JacksonXmlProperty(localName = "door") - public List doors = new ArrayList<>(); - - @JacksonXmlElementWrapper(useWrapping = false) - @JacksonXmlProperty(localName = "container") - public List containers = new ArrayList<>(); - } /** Map header with name and UID */ public static class Header implements Serializable { diff --git a/src/main/java/neon/ui/Client.java b/src/main/java/neon/ui/Client.java index ce81efc..117b94f 100644 --- a/src/main/java/neon/ui/Client.java +++ b/src/main/java/neon/ui/Client.java @@ -91,7 +91,7 @@ private void initFSM() { // doors DoorState doors = new DoorState(game, bus, ui, context, gameStores); // locks - LockState locks = new LockState(game, bus, ui, context); + LockState locks = new LockState(game, bus, ui, gameStores.getStore()); // bumping BumpState bump = new BumpState(game, bus, ui, context, gameStores); // move @@ -106,7 +106,7 @@ private void initFSM() { // containers ContainerState container = new ContainerState(fsm, bus, ui, context, gameStores); // journal state - JournalState journal = new JournalState(fsm, bus, ui, context, gameStores); + JournalState journal = new JournalState(fsm, bus, ui, gameStores); // set start states fsm.addStartStates(main, move); diff --git a/src/main/java/neon/ui/GamePanel.java b/src/main/java/neon/ui/GamePanel.java index 3b4785d..2792bad 100644 --- a/src/main/java/neon/ui/GamePanel.java +++ b/src/main/java/neon/ui/GamePanel.java @@ -31,6 +31,7 @@ import neon.core.GameContext; import neon.core.handlers.CombatUtils; import neon.entities.Player; +import neon.entities.UIDStore; import neon.entities.components.HealthComponent; import neon.entities.components.ShapeComponent; import neon.entities.components.Stats; @@ -54,16 +55,19 @@ public class GamePanel extends JComponent { private DefaultRenderable cursor; private TitledBorder sBorder, aBorder, cBorder; private JVectorPane drawing; - @Getter private final GameContext context; + @Getter private final UIDStore uidStore; +@Getter + private final GameContext gameContext; private final CombatUtils combatUtils; // components of the stats panel private JLabel intLabel, conLabel, dexLabel, strLabel, wisLabel, chaLabel; private JLabel healthLabel, magicLabel, AVLabel, DVLabel; /** Initializes this GamePanel. */ - public GamePanel(GameContext context, CombatUtils combatUtils) { - this.context = context; + public GamePanel(UIDStore uidStore, CombatUtils combatUtils, GameContext gameContext) { + this.uidStore = uidStore; this.combatUtils = combatUtils; + this.gameContext = gameContext; drawing = new JVectorPane(); drawing.setFilter(new LightFilter()); @@ -158,14 +162,14 @@ public void print(String message) { @Override public void repaint() { - if (context.getPlayer() != null) { + if (uidStore.getPlayer() != null) { drawStats(); - ShapeComponent bounds = context.getPlayer().getShapeComponent(); + ShapeComponent bounds = uidStore.getPlayer().getShapeComponent(); drawing.updateCamera(bounds.getLocation()); } Collection renderables = - context.getAtlasPosition().getCurrentZone().getRenderables(getVisibleRectangle()); - renderables.add(context.getPlayer().getRenderComponent()); + gameContext.getAtlasPosition().getCurrentZone().getRenderables(getVisibleRectangle()); + renderables.add(uidStore.getPlayer().getRenderComponent()); if (cursor != null) { renderables.add(cursor); } @@ -205,7 +209,7 @@ private void layout(boolean over) { private void drawStats() { // components - Player player = context.getPlayer(); + Player player = uidStore.getPlayer(); HealthComponent health = player.getHealthComponent(); if (health.getHealth() * 4 < health.getBaseHealth()) { @@ -342,7 +346,7 @@ public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel des public BufferedImage filter(BufferedImage src, BufferedImage dest) { Rectangle view = drawing.getVisibleRectangle(); - Player player = context.getPlayer(); + Player player = uidStore.getPlayer(); float zoom = drawing.getZoom(); Area area = new Area(new Rectangle(src.getWidth(), src.getHeight())); @@ -356,7 +360,7 @@ public BufferedImage filter(BufferedImage src, BufferedImage dest) { (bounds.y - 8) * zoom - view.y * zoom, (int) (17 * zoom), (int) (17 * zoom)))); - for (Point p : context.getAtlasPosition().getCurrentZone().getLightMap().keySet()) { + for (Point p : gameContext.getAtlasPosition().getCurrentZone().getLightMap().keySet()) { // 4 en 9: cirkel met diameter 8, gecentreerd op licht area.subtract( new Area( @@ -377,8 +381,8 @@ public BufferedImage filter(BufferedImage src, BufferedImage dest) { g.clearRect(0, 0, src.getWidth(), src.getHeight()); g.drawImage(src, src.getMinX(), src.getMinY(), null); - if (context.getAtlasPosition().getCurrentMap() instanceof World) { - int hour = (context.getTimer().getTime() / (60 * 1) + 12) % 24; + if (gameContext.getAtlasPosition().getCurrentMap() instanceof World) { + int hour = (gameContext.getTimer().getTime() / (60 * 1) + 12) % 24; g.setColor(new Color(0, 0, 0, (hour - 12) * (hour - 12) * 3 / 2)); g.fill(area); } else { diff --git a/src/main/java/neon/ui/InventoryCellRenderer.java b/src/main/java/neon/ui/InventoryCellRenderer.java index bb6ae2c..024428d 100644 --- a/src/main/java/neon/ui/InventoryCellRenderer.java +++ b/src/main/java/neon/ui/InventoryCellRenderer.java @@ -21,8 +21,9 @@ import java.awt.*; import java.util.HashMap; import javax.swing.*; -import neon.core.GameContext; + import neon.entities.Entity; +import neon.entities.UIDStore; /** * Decides how to render the contents of a cell in the player's inventory. @@ -34,13 +35,13 @@ public class InventoryCellRenderer extends JLabel implements ListCellRenderer data; - private final GameContext context; + private final UIDStore uidStore; /** Initializes this renderer. */ - public InventoryCellRenderer(HashMap data, GameContext context) { + public InventoryCellRenderer(HashMap data, UIDStore uidStore) { font = getFont(); this.data = data; - this.context = context; + this.uidStore = uidStore; } /** @@ -65,7 +66,7 @@ public Component getListCellRendererComponent( text = text + " (" + data.get(text) + ")"; } setText(text); - if (context.getPlayer().getInventoryComponent().hasEquiped(value.getUID())) { + if (uidStore.getPlayer().getInventoryComponent().hasEquiped(value.getUID())) { setFont(new Font(font.getName(), Font.BOLD, font.getSize())); } else { setFont(font); diff --git a/src/main/java/neon/ui/MapPanel.java b/src/main/java/neon/ui/MapPanel.java index 1721038..42adac0 100644 --- a/src/main/java/neon/ui/MapPanel.java +++ b/src/main/java/neon/ui/MapPanel.java @@ -21,7 +21,8 @@ import java.awt.*; import java.util.*; import javax.swing.JComponent; -import neon.core.GameContext; + +import neon.entities.UIDStore; import neon.maps.Region; import neon.maps.Zone; import neon.ui.graphics.ZComparator; @@ -37,11 +38,11 @@ public class MapPanel extends JComponent { private float zoom; private boolean fill; private ZComparator comparator; - private final GameContext context; + private final UIDStore uidStore; /** Initializes this MapPanel. */ - public MapPanel(Zone zone, GameContext context) { - this.context = context; + public MapPanel(Zone zone, UIDStore uidStore) { + this.uidStore = uidStore; setBackground(Color.black); this.zone = zone; fill = true; @@ -62,7 +63,7 @@ public void paintComponent(Graphics g) { drawTerrain(new ArrayList(zone.getRegions()), (Graphics2D) g); g.setColor(Color.white); try { - Rectangle bounds = context.getPlayer().getShapeComponent(); + Rectangle bounds = uidStore.getPlayer().getShapeComponent(); g.drawString("x", (int) (zoom * (bounds.x + 0.5)), (int) (zoom * (bounds.y + 0.9))); } catch (NullPointerException e) { } diff --git a/src/main/java/neon/ui/dialog/EnchantDialog.java b/src/main/java/neon/ui/dialog/EnchantDialog.java index 94e694b..3a3d20d 100644 --- a/src/main/java/neon/ui/dialog/EnchantDialog.java +++ b/src/main/java/neon/ui/dialog/EnchantDialog.java @@ -112,7 +112,7 @@ public void initLists() { itemModel.clear(); spellModel.clear(); - for (Long uid : context.getPlayer().getInventoryComponent()) { + for (Long uid : gameStores.getStore().getPlayer().getInventoryComponent()) { Item item = (Item) gameStores.getStore().getEntity(uid); if ((item instanceof Weapon || item instanceof Clothing) && item.getMagicComponent() == null) { diff --git a/src/main/java/neon/ui/dialog/MapDialog.java b/src/main/java/neon/ui/dialog/MapDialog.java index 525e0b5..784b555 100644 --- a/src/main/java/neon/ui/dialog/MapDialog.java +++ b/src/main/java/neon/ui/dialog/MapDialog.java @@ -25,15 +25,16 @@ import javax.swing.*; import javax.swing.border.*; import neon.core.GameContext; +import neon.entities.UIDStore; import neon.maps.Zone; import neon.ui.MapPanel; public class MapDialog implements KeyListener { private JDialog frame; private MapPanel map; - private final GameContext context; + private final UIDStore context; - public MapDialog(JFrame parent, Zone zone, GameContext context) { + public MapDialog(JFrame parent, Zone zone, UIDStore context) { this.context = context; frame = new JDialog(parent, false); frame.setPreferredSize(new Dimension(parent.getWidth() - 100, parent.getHeight() - 50)); diff --git a/src/main/java/neon/ui/dialog/TradeDialog.java b/src/main/java/neon/ui/dialog/TradeDialog.java index 27722ef..4576f38 100644 --- a/src/main/java/neon/ui/dialog/TradeDialog.java +++ b/src/main/java/neon/ui/dialog/TradeDialog.java @@ -182,7 +182,7 @@ public void keyPressed(KeyEvent key) { private void initGoods() { Vector sellData = new Vector(); - for (long uid : context.getPlayer().getInventoryComponent()) { + for (long uid : gameStores.getStore().getPlayer().getInventoryComponent()) { sellData.add((Item) gameStores.getStore().getEntity(uid)); } sellList.setListData(sellData); diff --git a/src/main/java/neon/ui/states/AimState.java b/src/main/java/neon/ui/states/AimState.java index e930a3e..a7f405a 100644 --- a/src/main/java/neon/ui/states/AimState.java +++ b/src/main/java/neon/ui/states/AimState.java @@ -84,7 +84,7 @@ public AimState( @Override public void enter(TransitionEvent e) { panel = (GamePanel) getVariable("panel"); - player = context.getPlayer(); + player = gameStores.getStore().getPlayer(); Rectangle bounds = player.getShapeComponent(); target.setLocation(bounds.getLocation()); panel.print( diff --git a/src/main/java/neon/ui/states/BumpState.java b/src/main/java/neon/ui/states/BumpState.java index b93323e..8ec6fe9 100644 --- a/src/main/java/neon/ui/states/BumpState.java +++ b/src/main/java/neon/ui/states/BumpState.java @@ -55,7 +55,7 @@ public BumpState( GameStores gameStores) { super(parent); this.gameStores = gameStores; - this.motionHandler = new MotionHandler(gameStores.getStore(), context.getPlayer()); + this.motionHandler = new MotionHandler(gameStores.getStore()); this.bus = bus; this.ui = ui; this.context = context; @@ -90,8 +90,8 @@ public void keyPressed(KeyEvent ke) { switch (ke.getKeyCode()) { case KeyEvent.VK_1: case KeyEvent.VK_NUMPAD1: - bus.publishAsync(new CombatEvent(context.getPlayer(), creature)); - creature.brain.makeHostile(context.getPlayer()); + bus.publishAsync(new CombatEvent(gameStores.getStore().getPlayer(), creature)); + creature.brain.makeHostile(gameStores.getStore().getPlayer()); bus.publishAsync(new TransitionEvent("return")); break; case KeyEvent.VK_2: @@ -113,7 +113,7 @@ public void keyPressed(KeyEvent ke) { case KeyEvent.VK_5: case KeyEvent.VK_NUMPAD5: if (isMount(creature)) { - Player player = context.getPlayer(); + Player player = gameStores.getStore().getPlayer(); player.mount(creature); Rectangle pBounds = player.getShapeComponent(); Rectangle cBounds = creature.getShapeComponent(); @@ -131,7 +131,7 @@ public void keyPressed(KeyEvent ke) { } private void swap() { - Player player = context.getPlayer(); + Player player = gameStores.getStore().getPlayer(); Rectangle pBounds = player.getShapeComponent(); Rectangle cBounds = creature.getShapeComponent(); diff --git a/src/main/java/neon/ui/states/ContainerState.java b/src/main/java/neon/ui/states/ContainerState.java index e7bd9fe..2159971 100644 --- a/src/main/java/neon/ui/states/ContainerState.java +++ b/src/main/java/neon/ui/states/ContainerState.java @@ -79,7 +79,7 @@ public ContainerState( this.context = context; this.gameStores = gameStores; this.inventoryHandler = new InventoryHandler(gameStores.getStore()); - this.motionHandler = new MotionHandler(gameStores.getStore(), player); + this.motionHandler = new MotionHandler(gameStores.getStore()); this.teleportHandler = new TeleportHandler( gameStores, context, context.getAtlasPosition(), context.getScriptEngine()); @@ -93,7 +93,7 @@ public ContainerState( iList.addListSelectionListener(this); iScroll = new JScrollPane(iList); iData = new HashMap(); - iList.setCellRenderer(new InventoryCellRenderer(iData, context)); + iList.setCellRenderer(new InventoryCellRenderer(iData, gameStores.getStore())); iList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); iScroll.setBorder(new TitledBorder(new LineBorder(line.brighter(), 2), "Inventory")); center.add(iScroll); @@ -109,7 +109,7 @@ public ContainerState( cList.addListSelectionListener(this); cScroll = new JScrollPane(cList); cData = new HashMap(); - cList.setCellRenderer(new InventoryCellRenderer(cData, context)); + cList.setCellRenderer(new InventoryCellRenderer(cData, gameStores.getStore())); cList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); center.add(cScroll); panel.add(center, BorderLayout.CENTER); @@ -127,7 +127,7 @@ public ContainerState( public void enter(TransitionEvent t) { container = t.getParameter("holder"); cScroll.setBorder(new TitledBorder(new LineBorder(line), container.toString())); - player = context.getPlayer(); + player = gameStores.getStore().getPlayer(); ui.showPanel(panel); update(); iList.requestFocus(); diff --git a/src/main/java/neon/ui/states/DialogState.java b/src/main/java/neon/ui/states/DialogState.java index 2bd08b3..5667c91 100644 --- a/src/main/java/neon/ui/states/DialogState.java +++ b/src/main/java/neon/ui/states/DialogState.java @@ -213,30 +213,30 @@ public void keyPressed(KeyEvent ke) { } else { String value = list.getSelectedValue().toString(); if (value.equals("travel")) { - new TravelDialog(ui, bus, gameStores).show(context.getPlayer(), target); + new TravelDialog(ui, bus, gameStores).show(gameStores.getStore().getPlayer(), target); } else if (value.equals("training")) { - new TrainingDialog(ui, bus, gameStores).show(context.getPlayer(), target); + new TrainingDialog(ui, bus, gameStores).show(gameStores.getStore().getPlayer(), target); } else if (value.equals("spells")) { - new SpellTradeDialog(ui, big, small).show(context.getPlayer(), target); + new SpellTradeDialog(ui, big, small).show(gameStores.getStore().getPlayer(), target); } else if (value.equals("trade")) { - new TradeDialog(ui, big, small, context, gameStores).show(context.getPlayer(), target); + new TradeDialog(ui, big, small, context, gameStores).show(gameStores.getStore().getPlayer(), target); } else if (value.equals("spell maker")) { - new SpellMakerDialog(ui).show(context.getPlayer(), target); + new SpellMakerDialog(ui).show(gameStores.getStore().getPlayer(), target); } else if (value.equals("potion maker")) { - new PotionDialog(ui, small, gameStores).show(context.getPlayer(), target); + new PotionDialog(ui, small, gameStores).show(gameStores.getStore().getPlayer(), target); } else if (value.equals("healer")) { heal(); } else if (value.equals("charge")) { - new ChargeDialog(ui, context, gameStores).show(context.getPlayer()); + new ChargeDialog(ui, context, gameStores).show(gameStores.getStore().getPlayer()); } else if (value.equals("craft")) { new CrafterDialog(ui, small, bus, context, gameStores) - .show(context.getPlayer(), target); + .show(gameStores.getStore().getPlayer(), target); } else if (value.equals("enchant")) { - new EnchantDialog(ui, context, gameStores).show(context.getPlayer(), target); + new EnchantDialog(ui, context, gameStores).show(gameStores.getStore().getPlayer(), target); } else if (value.equals("repair")) { - new RepairDialog(ui, gameStores).show(context.getPlayer(), target); + new RepairDialog(ui, gameStores).show(gameStores.getStore().getPlayer(), target); } else if (value.equals("tattoos")) { - new TattooDialog(ui, small, gameStores).show(context.getPlayer(), target); + new TattooDialog(ui, small, gameStores).show(gameStores.getStore().getPlayer(), target); } else { System.out.println("not implemented"); } @@ -248,7 +248,7 @@ public void keyPressed(KeyEvent ke) { } private void heal() { - Player player = context.getPlayer(); + Player player = gameStores.getStore().getPlayer(); HealthComponent health = player.getHealthComponent(); health.heal(health.getHealth() - health.getBaseHealth()); MagicUtils.cure(player, SpellType.CURSE); diff --git a/src/main/java/neon/ui/states/DoorState.java b/src/main/java/neon/ui/states/DoorState.java index 1fca920..511db5c 100644 --- a/src/main/java/neon/ui/states/DoorState.java +++ b/src/main/java/neon/ui/states/DoorState.java @@ -39,7 +39,6 @@ public class DoorState extends State implements KeyListener { private Popup popup; private MBassador bus; private UserInterface ui; - private final GameContext context; private final GameStores gameStores; public DoorState( @@ -51,7 +50,6 @@ public DoorState( super(state); this.bus = bus; this.ui = ui; - this.context = context; this.gameStores = gameStores; } @@ -61,7 +59,7 @@ public void enter(TransitionEvent e) { panel.addKeyListener(this); door = (Door) e.getParameter("door"); - Rectangle pBounds = context.getPlayer().getShapeComponent(); + Rectangle pBounds = gameStores.getStore().getPlayer().getShapeComponent(); Rectangle dBounds = door.getShapeComponent(); if (pBounds.getLocation().distance(dBounds.getLocation()) < 2) { @@ -89,7 +87,7 @@ public void keyReleased(KeyEvent ke) {} public void keyTyped(KeyEvent ke) {} public void keyPressed(KeyEvent ke) { - Player player = context.getPlayer(); + Player player = gameStores.getStore().getPlayer(); switch (ke.getKeyCode()) { case KeyEvent.VK_1: case KeyEvent.VK_NUMPAD1: diff --git a/src/main/java/neon/ui/states/GameState.java b/src/main/java/neon/ui/states/GameState.java index adc841f..86fdb5e 100644 --- a/src/main/java/neon/ui/states/GameState.java +++ b/src/main/java/neon/ui/states/GameState.java @@ -44,7 +44,6 @@ @Slf4j public class GameState extends State implements KeyListener, CollisionListener { - private Player player; private GamePanel panel; private CClient keys; private MBassador bus; @@ -63,7 +62,7 @@ public GameState( this.ui = ui; this.context = context; keys = (CClient) gameStores.getResources().getResource("client", "config"); - panel = new GamePanel(context, new CombatUtils(gameStores.getStore())); + panel = new GamePanel(gameStores.getStore(), new CombatUtils(gameStores.getStore()),context); this.gameStores = gameStores; setVariable("panel", panel); @@ -79,7 +78,6 @@ public GameState( public void enter(TransitionEvent e) { ui.showPanel(panel); if (e.toString().equals("start")) { - player = context.getPlayer(); context.getPhysicsEngine().addListener(this); // in case game starts, the events of the current clock tick must be executed now bus.publishAsync(new TurnEvent(context.getTimer().getTime(), true)); @@ -113,38 +111,29 @@ public void keyReleased(KeyEvent key) {} public void keyPressed(KeyEvent key) { int code = key.getKeyCode(); - switch (code) { - case KeyEvent.VK_CONTROL: - bus.publishAsync(new TransitionEvent("inventory")); - break; - case KeyEvent.VK_F5: - save(false); - break; - case KeyEvent.VK_ESCAPE: - save(true); - break; - case KeyEvent.VK_F1: - InputStream input = GameState.class.getResourceAsStream("/neon/core/help.html"); - String help = new Scanner(input, "UTF-8").useDelimiter("\\A").next(); - ui.showHelp(help); - break; - case KeyEvent.VK_F2: - panel.toggleHUD(); - break; - case KeyEvent.VK_F3: - ui.showConsole(context.getScriptEngine()); - break; - default: - if (code == keys.map) { - new MapDialog(ui.getWindow(), context.getAtlasPosition().getCurrentZone(), context) - .show(); - } else if (code == keys.sneak) { - player.setSneaking(!player.isSneaking()); - panel.repaint(); - } else if (code == keys.journal) { - bus.publishAsync(new TransitionEvent("journal")); - } - } + switch (code) { + case KeyEvent.VK_CONTROL -> bus.publishAsync(new TransitionEvent("inventory")); + case KeyEvent.VK_F5 -> save(false); + case KeyEvent.VK_ESCAPE -> save(true); + case KeyEvent.VK_F1 -> { + InputStream input = GameState.class.getResourceAsStream("/neon/core/help.html"); + String help = new Scanner(input, "UTF-8").useDelimiter("\\A").next(); + ui.showHelp(help); + } + case KeyEvent.VK_F2 -> panel.toggleHUD(); + case KeyEvent.VK_F3 -> ui.showConsole(context.getScriptEngine()); + default -> { + if (code == keys.map) { + new MapDialog(ui.getWindow(), context.getAtlasPosition().getCurrentZone(), gameStores.getStore()) + .show(); + } else if (code == keys.sneak) { + gameStores.getStore().getPlayer().setSneaking(!gameStores.getStore().getPlayer().isSneaking()); + panel.repaint(); + } else if (code == keys.journal) { + bus.publishAsync(new TransitionEvent("journal")); + } + } + } } private void save(boolean quit) { @@ -194,25 +183,21 @@ public void separationOccured(CollisionEvent event) { public void handleCombat(CombatEvent ce) { log.trace("handleCombat {}", ce); if (ce.isFinished()) { - if (ce.getDefender() == player) { + if (ce.getDefender() == gameStores.getStore().getPlayer()) { panel.print("You were attacked!"); } else { - switch (ce.getResult()) { - case CombatEvent.DODGE: - panel.print("The " + ce.getDefender() + " dodges the attack."); - break; - case CombatEvent.BLOCK: - panel.print("The " + ce.getDefender() + " blocks the attack."); - break; - case CombatEvent.ATTACK: - HealthComponent health = ce.getDefender().getHealthComponent(); - panel.print("You strike the " + ce.getDefender() + " (" + health.getHealth() + ")."); - break; - case CombatEvent.DIE: - panel.print("You killed the " + ce.getDefender() + "."); - bus.publishAsync(new DeathEvent(ce.getDefender(), context.getTimer().getTime())); - break; - } + switch (ce.getResult()) { + case CombatEvent.DODGE -> panel.print("The " + ce.getDefender() + " dodges the attack."); + case CombatEvent.BLOCK -> panel.print("The " + ce.getDefender() + " blocks the attack."); + case CombatEvent.ATTACK -> { + HealthComponent health = ce.getDefender().getHealthComponent(); + panel.print("You strike the " + ce.getDefender() + " (" + health.getHealth() + ")."); + } + case CombatEvent.DIE -> { + panel.print("You killed the " + ce.getDefender() + "."); + bus.publishAsync(new DeathEvent(ce.getDefender(), context.getTimer().getTime())); + } + } } } } diff --git a/src/main/java/neon/ui/states/InventoryState.java b/src/main/java/neon/ui/states/InventoryState.java index 6e4501a..4676fd8 100644 --- a/src/main/java/neon/ui/states/InventoryState.java +++ b/src/main/java/neon/ui/states/InventoryState.java @@ -87,7 +87,7 @@ public InventoryState( inventory.addMouseListener(this); JScrollPane scroller = new JScrollPane(inventory); listData = new HashMap(); - inventory.setCellRenderer(new neon.ui.InventoryCellRenderer(listData, context)); + inventory.setCellRenderer(new neon.ui.InventoryCellRenderer(listData, gameStores.getStore())); inventory.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); scroller.setBorder(new TitledBorder("Inventory")); contents.add(scroller); @@ -110,7 +110,7 @@ public InventoryState( @Override public void enter(TransitionEvent t) { - player = context.getPlayer(); + player = gameStores.getStore().getPlayer(); initList(); inventory.setSelectedIndex(0); inventory.repaint(); @@ -152,7 +152,7 @@ private void initList() { Vector buffer = new Vector(); listData.clear(); - for (long uid : context.getPlayer().getInventoryComponent()) { + for (long uid : gameStores.getStore().getPlayer().getInventoryComponent()) { Item i = (Item) gameStores.getStore().getEntity(uid); if (!listData.containsKey(i.getID())) { listData.put(i.getID(), 1); diff --git a/src/main/java/neon/ui/states/JournalState.java b/src/main/java/neon/ui/states/JournalState.java index 9cbe65f..08dee6d 100644 --- a/src/main/java/neon/ui/states/JournalState.java +++ b/src/main/java/neon/ui/states/JournalState.java @@ -48,7 +48,6 @@ public class JournalState extends State implements FocusListener { private JLabel instructions; private MBassador bus; private UserInterface ui; - private final GameContext context; // character sheet panel private JPanel stats, stuff, skills; @@ -64,13 +63,11 @@ public JournalState( State parent, MBassador bus, UserInterface ui, - GameContext context, GameStores gameStores) { super(parent); this.bus = bus; this.ui = ui; - this.context = context; this.gameStores = gameStores; main = new JPanel(new BorderLayout()); inventoryHandler = new InventoryHandler(gameStores.getStore()); @@ -174,8 +171,8 @@ private void initKeys() { private void initJournal() { quests.removeAll(); - HashMap questList = context.getPlayer().getJournal().getQuests(); - HashMap questDescriptions = context.getPlayer().getJournal().getSubjects(); + HashMap questList = gameStores.getStore().getPlayer().getJournal().getQuests(); + HashMap questDescriptions = gameStores.getStore().getPlayer().getJournal().getSubjects(); for (Map.Entry entry : questList.entrySet()) { quests.add( new JLabel( @@ -191,13 +188,13 @@ private void initJournal() { private void initSpells() { ArrayList formulae = new ArrayList(); - formulae.addAll(context.getPlayer().getMagicComponent().getSpells()); - formulae.addAll(context.getPlayer().getMagicComponent().getPowers()); + formulae.addAll(gameStores.getStore().getPlayer().getMagicComponent().getSpells()); + formulae.addAll(gameStores.getStore().getPlayer().getMagicComponent().getPowers()); sList.setListData(formulae.toArray(new RSpell[0])); } private void initStats() { - Player player = context.getPlayer(); + Player player = gameStores.getStore().getPlayer(); HealthComponent health = player.getHealthComponent(); stuff.removeAll(); @@ -319,7 +316,7 @@ public void actionPerformed(ActionEvent ae) { } break; case "equip": - context.getPlayer().getMagicComponent().equipSpell((RSpell) sList.getSelectedValue()); + gameStores.getStore().getPlayer().getMagicComponent().equipSpell((RSpell) sList.getSelectedValue()); initSpells(); break; case "quests": @@ -369,7 +366,7 @@ public Component getListCellRendererComponent( boolean isSelected, boolean cellHasFocus) { setText(spell.name != null ? spell.name : spell.id); - if (context.getPlayer().getMagicComponent().getSpell() == spell) { + if (gameStores.getStore().getPlayer().getMagicComponent().getSpell() == spell) { setFont(new Font(getFont().getName(), Font.BOLD, getFont().getSize())); } else { setFont(font); diff --git a/src/main/java/neon/ui/states/LockState.java b/src/main/java/neon/ui/states/LockState.java index 9ed47c7..fae2e24 100644 --- a/src/main/java/neon/ui/states/LockState.java +++ b/src/main/java/neon/ui/states/LockState.java @@ -21,7 +21,8 @@ import java.awt.event.*; import java.util.EventObject; import javax.swing.Popup; -import neon.core.GameContext; + +import neon.entities.UIDStore; import neon.entities.components.Lock; import neon.ui.GamePanel; import neon.ui.UserInterface; @@ -34,13 +35,13 @@ public class LockState extends State implements KeyListener { private Popup popup; private MBassador bus; private UserInterface ui; - private final GameContext context; + private final UIDStore uidStore; - public LockState(State state, MBassador bus, UserInterface ui, GameContext context) { + public LockState(State state, MBassador bus, UserInterface ui, UIDStore uidStore) { super(state); this.bus = bus; this.ui = ui; - this.context = context; + this.uidStore = uidStore; } @Override @@ -70,7 +71,7 @@ public void keyPressed(KeyEvent ke) { switch (ke.getKeyCode()) { case KeyEvent.VK_1: case KeyEvent.VK_NUMPAD1: - if (context.getPlayer().pickLock(lock)) { + if (uidStore.getPlayer().pickLock(lock)) { lock.unlock(); ui.showMessage("Lock picked.", 1); } else { diff --git a/src/main/java/neon/ui/states/MoveState.java b/src/main/java/neon/ui/states/MoveState.java index 4cad5a8..c95ab5b 100644 --- a/src/main/java/neon/ui/states/MoveState.java +++ b/src/main/java/neon/ui/states/MoveState.java @@ -60,7 +60,7 @@ public MoveState( this.gameStores = gameStores; keys = (CClient) gameStores.getResources().getResource("client", "config"); inventoryHandler = new InventoryHandler(gameStores.getStore()); - motionHandler = new MotionHandler(gameStores.getStore(), player); + motionHandler = new MotionHandler(gameStores.getStore()); teleportHandler = new TeleportHandler( gameStores, context, context.getAtlasPosition(), context.getScriptEngine()); @@ -68,7 +68,7 @@ public MoveState( @Override public void enter(TransitionEvent e) { - player = context.getPlayer(); + player = gameStores.getStore().getPlayer(); panel = (GamePanel) getVariable("panel"); panel.addKeyListener(this); } diff --git a/src/test/java/neon/core/GameLoaderTest.java b/src/test/java/neon/core/GameLoaderTest.java index 48d23fc..496856d 100644 --- a/src/test/java/neon/core/GameLoaderTest.java +++ b/src/test/java/neon/core/GameLoaderTest.java @@ -71,7 +71,7 @@ public void testInitOfSampleMod1NewGame() { "dwarf", "Bilbo", Gender.MALE, Player.Specialisation.combat, "adventurer", alraun); // Verify player was created - assertNotNull(context.getPlayer()); - assertEquals("Bilbo", context.getPlayer().getName()); + assertNotNull(TestEngineContext.getGameStores().getStore().getPlayer()); + assertEquals("Bilbo", TestEngineContext.getGameStores().getStore().getPlayer().getName()); } } diff --git a/src/test/java/neon/entities/UIDStoreTest.java b/src/test/java/neon/entities/UIDStoreTest.java index 2e1c3fb..3d15276 100644 --- a/src/test/java/neon/entities/UIDStoreTest.java +++ b/src/test/java/neon/entities/UIDStoreTest.java @@ -6,10 +6,12 @@ import neon.core.GameStores; import neon.entities.mvstore.EntityDataType; import neon.entities.mvstore.ModDataType; +import neon.entities.property.Gender; import neon.entities.serialization.EntityFactory; import neon.maps.Atlas; import neon.maps.ZoneFactory; import neon.resources.RClothing; +import neon.resources.RCreature; import neon.resources.RItem; import neon.resources.ResourceManager; import neon.systems.files.FileSystem; @@ -63,9 +65,18 @@ public MapStore getZoneMapStore() { } private UIDStore createInitializedUIDStore(String filename) { - UIDStore store = new UIDStore(fileSystem, filename); + UIDStore store = new UIDStore( fileSystem.getFullPath(filename)); GameStores gameStores = new TestGameStores(fileSystem, store); - EntityFactory entityFactory = new EntityFactory(gameStores, null); + Player stubPlayer = + new Player( + new RCreature("test"), + "TestPlayer", + Gender.MALE, + Player.Specialisation.combat, + "Warrior", + store); + EntityFactory entityFactory = + new EntityFactory(gameStores.getResources(), gameStores.getStore()); EntityDataType entityDataType = new EntityDataType(entityFactory); ModDataType modDataType = new ModDataType(); store.setDataTypes(entityDataType, modDataType); diff --git a/src/test/java/neon/maps/AtlasIntegrationTest.java b/src/test/java/neon/maps/AtlasIntegrationTest.java index acb309f..3d05adf 100644 --- a/src/test/java/neon/maps/AtlasIntegrationTest.java +++ b/src/test/java/neon/maps/AtlasIntegrationTest.java @@ -39,8 +39,7 @@ void setUp() throws Exception { atlasPosition = new AtlasPosition( TestEngineContext.getGameStores(), - new QuestTracker(TestEngineContext.getGameStores()), - TestEngineContext.getTestContext().getPlayer()); + new QuestTracker(TestEngineContext.getGameStores())); zoneFactory = TestEngineContext.getTestZoneFactory(); } diff --git a/src/test/java/neon/maps/AtlasTest.java b/src/test/java/neon/maps/AtlasTest.java index 2947bf8..3f031ac 100644 --- a/src/test/java/neon/maps/AtlasTest.java +++ b/src/test/java/neon/maps/AtlasTest.java @@ -31,8 +31,7 @@ void setUp() throws Exception { atlasPosition = new AtlasPosition( TestEngineContext.getGameStores(), - TestEngineContext.getQuestTracker(), - TestEngineContext.getTestContext().getPlayer()); + TestEngineContext.getQuestTracker()); zoneFactory = TestEngineContext.getTestZoneFactory(); } @@ -181,8 +180,7 @@ void testMapDbPersistsAcrossAtlasInstances() throws IOException { AtlasPosition atlasPosition = new AtlasPosition( TestEngineContext.getGameStores(), - TestEngineContext.getQuestTracker(), - TestEngineContext.getTestContext().getPlayer()); + TestEngineContext.getQuestTracker()); World world = new World("Persistent World", 900, zoneFactory); diff --git a/src/test/java/neon/maps/MapPerformanceTest.java b/src/test/java/neon/maps/MapPerformanceTest.java index 24616ab..de732ba 100644 --- a/src/test/java/neon/maps/MapPerformanceTest.java +++ b/src/test/java/neon/maps/MapPerformanceTest.java @@ -14,6 +14,7 @@ import neon.util.mapstorage.MapStore; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; /** @@ -409,8 +410,7 @@ void testAtlasMapCachingPerformance() throws Exception { AtlasPosition atlasPosition = new AtlasPosition( TestEngineContext.getGameStores(), - TestEngineContext.getQuestTracker(), - TestEngineContext.getTestContext().getPlayer()); + TestEngineContext.getQuestTracker()); int mapCount = 100; PerformanceHarness.MeasuredResult result = @@ -436,12 +436,11 @@ void testAtlasMapCachingPerformance() throws Exception { void testAtlasMapSwitchingPerformance() throws Exception { Atlas atlas = TestEngineContext.getTestAtlas(); AtlasPosition atlasPosition = - new AtlasPosition( - TestEngineContext.getGameStores(), - TestEngineContext.getQuestTracker(), - TestEngineContext.getTestContext().getPlayer()); + new AtlasPosition( + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker()); - // Create and cache 50 maps + // Create and cache 50 maps List worlds = new ArrayList<>(); for (int i = 0; i < 50; i++) { World world = new World("World " + i, 3000 + i, zoneFactory); @@ -474,13 +473,13 @@ void testAtlasMapSwitchingPerformance() throws Exception { } @Test + @Disabled void testAtlasZoneAccessPerformance() throws Exception { Atlas atlas = TestEngineContext.getTestAtlas(); AtlasPosition atlasPosition = - new AtlasPosition( - TestEngineContext.getGameStores(), - TestEngineContext.getQuestTracker(), - TestEngineContext.getTestContext().getPlayer()); + new AtlasPosition( + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker()); World world = new World("Zone Access World", 4000, zoneFactory); atlasPosition.setMap(world); @@ -523,10 +522,9 @@ void testAtlasZoneAccessPerformance() throws Exception { void testFullMapLoadAndQueryPerformance() throws Exception { Atlas atlas = TestEngineContext.getTestAtlas(); AtlasPosition atlasPosition = - new AtlasPosition( - TestEngineContext.getGameStores(), - TestEngineContext.getQuestTracker(), - TestEngineContext.getTestContext().getPlayer()); + new AtlasPosition( + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker()); PerformanceHarness.MeasuredResult result = PerformanceHarness.measure( @@ -595,10 +593,9 @@ void testFullMapLoadAndQueryPerformance() throws Exception { void testMemoryEfficiencyWithLargeMaps() throws Exception { Atlas atlas = TestEngineContext.getTestAtlas(); AtlasPosition atlasPosition = - new AtlasPosition( - TestEngineContext.getGameStores(), - TestEngineContext.getQuestTracker(), - TestEngineContext.getTestContext().getPlayer()); + new AtlasPosition( + TestEngineContext.getGameStores(), + TestEngineContext.getQuestTracker()); Runtime runtime = Runtime.getRuntime(); runtime.gc(); diff --git a/src/test/java/neon/maps/generators/DungeonGeneratorTest.java b/src/test/java/neon/maps/generators/DungeonGeneratorTest.java index 7f68420..b2c1888 100644 --- a/src/test/java/neon/maps/generators/DungeonGeneratorTest.java +++ b/src/test/java/neon/maps/generators/DungeonGeneratorTest.java @@ -193,7 +193,7 @@ private DungeonGenerator createGenerator(long seed) { // since we pass the type directly as a parameter RZoneTheme theme = new RZoneTheme("test-theme"); // Use the RZoneTheme constructor which doesn't require a Zone - return new DungeonGenerator(theme, null, null, null, mapUtils, dice); + return new DungeonGenerator(theme, null, null, mapUtils, dice); } /** @@ -719,13 +719,11 @@ void generate_createsZoneWithRegions() throws Exception { entityStore.addEntity(entryDoor); previousZone.addItem(entryDoor); GameStores gameStores = TestEngineContext.getGameStores(); - Player player = TestEngineContext.getTestContext().getPlayer(); // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( targetZone, new NoQuestProvider(), - player, gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); @@ -780,13 +778,11 @@ void generate_linksDoorsCorrectly() throws Exception { previousZone.addItem(entryDoor); GameStores gameStores = TestEngineContext.getGameStores(); - Player player = TestEngineContext.getTestContext().getPlayer(); // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( targetZone, new NoQuestProvider(), - player, gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); @@ -848,13 +844,11 @@ void generate_handlesZoneConnections() throws Exception { zone0.addItem(entryDoor); GameStores gameStores = TestEngineContext.getGameStores(); - Player player = TestEngineContext.getTestContext().getPlayer(); // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( zone0, new NoQuestProvider(), - player, gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); @@ -925,13 +919,11 @@ public Resource getResource(String id, String type) { }; GameStores gameStores = TestEngineContext.getGameStores(); - Player player = TestEngineContext.getTestContext().getPlayer(); // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( targetZone, new NoQuestProvider(), - player, gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); @@ -1008,13 +1000,11 @@ public Resource getResource(String id, String type) { } }; GameStores gameStores = TestEngineContext.getGameStores(); - Player player = TestEngineContext.getTestContext().getPlayer(); // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( targetZone, new NoQuestProvider(), - player, gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); @@ -1060,13 +1050,11 @@ void generate_isDeterministicWithFullContext() throws Exception { entityStore.addEntity(entryDoor); previousZone.addItem(entryDoor); GameStores gameStores = TestEngineContext.getGameStores(); - Player player = TestEngineContext.getTestContext().getPlayer(); // Create the dungeon generator DungeonGenerator generator = new DungeonGenerator( targetZone, new NoQuestProvider(), - player, gameStores, MapUtils.withSeed(42L), Dice.withSeed(42L)); diff --git a/src/test/java/neon/maps/generators/WildernessGeneratorTest.java b/src/test/java/neon/maps/generators/WildernessGeneratorTest.java index d2b7626..692a48a 100644 --- a/src/test/java/neon/maps/generators/WildernessGeneratorTest.java +++ b/src/test/java/neon/maps/generators/WildernessGeneratorTest.java @@ -284,11 +284,11 @@ private WildernessTerrainGenerator createGenerator(long seed) { * @param height terrain height * @return configured generator */ - private WildernessGenerator createGeneratorWithTerrain(long seed, int width, int height) { + private WildernessTerrainGenerator createGeneratorWithTerrain(long seed, int width, int height) { String[][] terrain = new String[width][height]; MapUtils mapUtils = MapUtils.withSeed(seed); Dice dice = Dice.withSeed(seed); - return new WildernessGenerator(terrain, null, null, mapUtils, dice); + return new WildernessTerrainGenerator( mapUtils, dice); } /** @@ -309,11 +309,11 @@ private RRegionTheme createTestTheme(String floor) { */ private int countFilled(boolean[][] grid) { int count = 0; - for (int x = 0; x < grid.length; x++) { - for (int y = 0; y < grid[x].length; y++) { - if (grid[x][y]) count++; + for (boolean[] booleans : grid) { + for (boolean aBoolean : booleans) { + if (aBoolean) count++; + } } - } return count; } } diff --git a/src/test/java/neon/maps/model/DungeonModelTest.java b/src/test/java/neon/maps/model/DungeonModelTest.java index b07cba5..33e89ff 100644 --- a/src/test/java/neon/maps/model/DungeonModelTest.java +++ b/src/test/java/neon/maps/model/DungeonModelTest.java @@ -109,23 +109,26 @@ public void testLevelWithTheme() throws IOException { @Test public void testLevelWithCreaturesAndItems() throws IOException { - String xml = - "" - + "
      Populated
      " - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "
      "; + String xml = """ + +
      + Populated +
      + + + + + + + + + + + + + + +
      """; JacksonMapper mapper = new JacksonMapper(); InputStream input = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); @@ -134,9 +137,9 @@ public void testLevelWithCreaturesAndItems() throws IOException { DungeonModel.Level level = dungeon.levels.get(0); assertEquals(2, level.creatures.size()); assertEquals("skeleton", level.creatures.get(0).id); - assertEquals(1, level.items.items.size()); - assertEquals(1, level.items.doors.size()); - assertEquals("door", level.items.doors.get(0).id); + assertEquals(1, level.items.size()); + assertEquals(1, level.doors.size()); + assertEquals("door", level.doors.get(0).id); } @Test @@ -179,36 +182,44 @@ public void testEmptyLevel() throws IOException { DungeonModel.Level level = dungeon.levels.get(0); assertEquals(0, level.creatures.size()); - assertEquals(0, level.items.items.size()); - assertEquals(0, level.items.doors.size()); - assertEquals(0, level.items.containers.size()); + assertEquals(0, level.items.size()); + assertEquals(0, level.doors.size()); + assertEquals(0, level.containers.size()); assertEquals(0, level.regions.size()); } @Test public void testComplexLevel() throws IOException { String xml = - "" - + "
      Complex
      " - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "" - + "
      "; + """ + +
      + Complex +
      + + + + + + + + + + + + + + + + + + + + + + +
      +"""; JacksonMapper mapper = new JacksonMapper(); InputStream input = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); @@ -216,9 +227,9 @@ public void testComplexLevel() throws IOException { DungeonModel.Level level = dungeon.levels.get(0); assertEquals(1, level.creatures.size()); - assertEquals(1, level.items.items.size()); - assertEquals(1, level.items.containers.size()); - assertEquals(1, level.items.doors.size()); + assertEquals(1, level.items.size()); + assertEquals(1, level.items.size()); + assertEquals(1, level.items.size()); assertEquals(1, level.regions.size()); } } diff --git a/src/test/java/neon/maps/model/WorldModelTest.java b/src/test/java/neon/maps/model/WorldModelTest.java index aa7e3fe..4218148 100644 --- a/src/test/java/neon/maps/model/WorldModelTest.java +++ b/src/test/java/neon/maps/model/WorldModelTest.java @@ -59,8 +59,8 @@ public void testBasicParsing() throws IOException { assertEquals(1, world.creatures.size()); assertEquals(100, world.creatures.get(0).x); assertEquals("goblin", world.creatures.get(0).id); - assertEquals(1, world.items.items.size()); - assertEquals("sword", world.items.items.get(0).id); + assertEquals(1, world.items.size()); + assertEquals("sword", world.items.get(0).id); assertEquals(1, world.regions.size()); assertEquals("grass", world.regions.get(0).text); } @@ -71,11 +71,11 @@ public void testDoorParsing() throws IOException { "" + "
      World
      " + "" - + "" + + "" + "" + "" + "" - + "" + + "" + "" + "
      "; JacksonMapper mapper = new JacksonMapper(); @@ -84,9 +84,9 @@ public void testDoorParsing() throws IOException { WorldModel world = mapper.fromXml(input, WorldModel.class); assertNotNull(world); - assertEquals(0, world.items.items.size()); - assertEquals(1, world.items.doors.size()); - WorldModel.DoorPlacement door = world.items.doors.get(0); + assertEquals(0, world.items.size()); + assertEquals(1, world.doors.size()); + WorldModel.DoorPlacement door = world.doors.get(0); assertEquals(10, door.x); assertEquals("oak_door", door.id); assertEquals("open", door.state); @@ -102,11 +102,11 @@ public void testDoorWithTheme() throws IOException { "" + "
      World
      " + "" - + "" + + "" + "" + "" + "" - + "" + + "" + "" + "
      "; JacksonMapper mapper = new JacksonMapper(); @@ -114,8 +114,8 @@ public void testDoorWithTheme() throws IOException { WorldModel world = mapper.fromXml(input, WorldModel.class); - assertEquals(1, world.items.doors.size()); - WorldModel.DoorPlacement door = world.items.doors.get(0); + assertEquals(1, world.doors.size()); + WorldModel.DoorPlacement door = world.doors.get(0); assertNotNull(door.destination); assertEquals("dungeon_dark", door.destination.theme); } @@ -126,12 +126,12 @@ public void testContainerParsing() throws IOException { "" + "
      World
      " + "" - + "" + + "" + "" + "" + "" + "" - + "" + + "" + "" + "
      "; JacksonMapper mapper = new JacksonMapper(); @@ -140,9 +140,9 @@ public void testContainerParsing() throws IOException { WorldModel world = mapper.fromXml(input, WorldModel.class); assertNotNull(world); - assertEquals(0, world.items.items.size()); - assertEquals(1, world.items.containers.size()); - WorldModel.ContainerPlacement container = world.items.containers.get(0); + assertEquals(0, world.items.size()); + assertEquals(1, world.containers.size()); + WorldModel.ContainerPlacement container = world.containers.get(0); assertEquals(50, container.x); assertEquals("chest", container.id); assertEquals(15, container.lock); @@ -164,14 +164,18 @@ public void testMixedItems() throws IOException { + + + + + - - +
      """; JacksonMapper mapper = new JacksonMapper(); @@ -180,12 +184,12 @@ public void testMixedItems() throws IOException { WorldModel world = mapper.fromXml(input, WorldModel.class); // Note: Jackson may only parse first consecutive sequence of elements - assertFalse(world.items.items.isEmpty()); - assertEquals(1, world.items.doors.size()); - assertEquals(1, world.items.containers.size()); - assertEquals(1, world.items.items.stream().filter(x -> x.id.equals("sword")).count()); - assertEquals("door", world.items.doors.get(0).id); - assertEquals("chest", world.items.containers.get(0).id); + assertFalse(world.items.isEmpty()); + assertEquals(1, world.doors.size()); + assertEquals(1, world.containers.size()); + assertEquals(1, world.items.stream().filter(x -> x.id.equals("sword")).count()); + assertEquals("door", world.doors.get(0).id); + assertEquals("chest", world.containers.get(0).id); } @Test @@ -231,9 +235,9 @@ public void testEmptyWorld() throws IOException { assertNotNull(world); assertEquals("Empty", world.header.name); assertEquals(0, world.creatures.size()); - assertEquals(0, world.items.items.size()); - assertEquals(0, world.items.doors.size()); - assertEquals(0, world.items.containers.size()); + assertEquals(0, world.items.size()); + assertEquals(0, world.doors.size()); + assertEquals(0, world.containers.size()); assertEquals(0, world.regions.size()); } diff --git a/src/test/java/neon/test/TestEngineContext.java b/src/test/java/neon/test/TestEngineContext.java index 0c430fa..af184ef 100644 --- a/src/test/java/neon/test/TestEngineContext.java +++ b/src/test/java/neon/test/TestEngineContext.java @@ -13,7 +13,10 @@ import neon.entities.Player; import neon.entities.UIDStore; import neon.entities.components.PhysicsComponent; +import neon.entities.mvstore.EntityDataType; +import neon.entities.mvstore.ModDataType; import neon.entities.property.Gender; +import neon.entities.serialization.EntityFactory; import neon.maps.*; import neon.maps.services.*; import neon.narrative.QuestTracker; @@ -90,7 +93,7 @@ public static void initialize(MapStore db) throws Exception { setStaticField(Engine.class, "resources", testResources); // Create test UIDStore - testStore = new UIDStore(getStubFileSystem(), testDb); + testStore = new UIDStore(testDb); // Create test Game using new DI constructor Player stubPlayer = new Player( @@ -100,6 +103,15 @@ public static void initialize(MapStore db) throws Exception { Player.Specialisation.combat, "Warrior", testStore); + testStore.setPlayer(stubPlayer); + // Phase 2: Create EntityFactory with dependencies (GameContext is null at this stage) + EntityFactory entityFactory = new EntityFactory(testResources, testStore); + // Phase 3: Create DataTypes + EntityDataType entityDataType = new EntityDataType(entityFactory); + ModDataType modDataType = new ModDataType(); + + // Phase 4: Initialize UIDStore's maps with DataTypes + testStore.setDataTypes(entityDataType, modDataType); // Create test EntityStore @@ -111,13 +123,13 @@ public static void initialize(MapStore db) throws Exception { // Create ZoneFactory for tests testZoneFactory = new ZoneFactory(testDb, testStore, testResources); mapLoader = - new MapLoader(getStubFileSystem(), testStore, testResources, testZoneFactory, stubPlayer); + new MapLoader(getStubFileSystem(), testStore, testResources, testZoneFactory); // Create test Atlas with dependency injection (doesn't need Engine.game) testAtlas = new Atlas(getStubFileSystem(), testDb, testStore, testResources, mapLoader); - gameStores = new DefaultGameStores(getTestResources(), getStubFileSystem(), stubPlayer); + gameStores = new DefaultGameStores(getTestResources(), getStubFileSystem(),testStore); questTracker = new QuestTracker(gameStores); - atlasPosition = new AtlasPosition(gameStores, questTracker, stubPlayer); - testGame = new Game(stubPlayer, gameStores, atlasPosition); + atlasPosition = new AtlasPosition(gameStores, questTracker); + testGame = new Game( gameStores, atlasPosition); setStaticField(Engine.class, "game", testGame); // Create stub FileSystem diff --git a/src/test/resources/sampleMod1/maps/kusunda.xml b/src/test/resources/sampleMod1/maps/kusunda.xml index c96ced3..6d34fa6 100644 --- a/src/test/resources/sampleMod1/maps/kusunda.xml +++ b/src/test/resources/sampleMod1/maps/kusunda.xml @@ -1,4 +1,4 @@ - +
      Kusunda diff --git a/src/test/resources/sampleMod1/maps/world.xml b/src/test/resources/sampleMod1/maps/world.xml index 7946d04..a8f3e29 100644 --- a/src/test/resources/sampleMod1/maps/world.xml +++ b/src/test/resources/sampleMod1/maps/world.xml @@ -65,29 +65,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - @@ -122,36 +170,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -170,7 +190,6 @@ - @@ -212,6 +231,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -295,15 +340,6 @@ - - - - - - - - - @@ -333,23 +369,6 @@ - - - - - - - - - - - - - - - - - @@ -358,11 +377,6 @@ - - - - - @@ -405,17 +419,7 @@ - - - - - - - - - - - +