From 8249af0bbc21544b0ea4de405758e60582800764 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Thu, 5 Sep 2019 22:09:50 -0700 Subject: [PATCH] Init --- .../dldungeons/res/themes/chests.cfg | 241 +++++ .../dldungeons/res/themes/classic.cfg | 106 +++ .../dldungeons/res/themes/common.cfg | 107 +++ .../res/themes/continentalShelf.cfg | 111 +++ .../dldungeons/res/themes/dank.cfg | 109 +++ .../dldungeons/res/themes/desert.cfg | 111 +++ .../dldungeons/res/themes/frozen.cfg | 107 +++ .../dldungeons/res/themes/jungle.cfg | 107 +++ .../dldungeons/res/themes/mesa.cfg | 125 +++ .../jaredbgreat/dldungeons/res/themes/nbt.cfg | 64 ++ .../dldungeons/res/themes/nether.cfg | 112 +++ .../dldungeons/res/themes/oceanic.cfg | 113 +++ .../dldungeons/res/themes/oceanic_chests.cfg | 240 +++++ .../dldungeons/res/themes/template.cfg | 114 +++ .../dldungeons/res/themes/urban.cfg | 108 +++ .../dldungeons/res/themes/villagelike.cfg | 103 +++ .../dldungeons/res/themes/volcanic.cfg | 111 +++ src/com/gmail/nossr50/util/ItemUtils.java | 678 ++++++++++++++ src/jaredbgreat/dldungeons/ConfigHandler.java | 554 +++++++++++ src/jaredbgreat/dldungeons/Difficulty.java | 132 +++ .../dldungeons/GenerationHandler.java | 162 ++++ src/jaredbgreat/dldungeons/Info.java | 20 + src/jaredbgreat/dldungeons/ReadAPI.java | 181 ++++ .../dldungeons/builder/Builder.java | 98 ++ .../dldungeons/builder/DBlock.java | 359 ++++++++ .../dldungeons/parser/CharSet.java | 199 ++++ .../dldungeons/parser/Tokenizer.java | 268 ++++++ .../dldungeons/pieces/Doorway.java | 108 +++ .../dldungeons/pieces/Rectangle.java | 394 ++++++++ src/jaredbgreat/dldungeons/pieces/Shape.java | 225 +++++ src/jaredbgreat/dldungeons/pieces/Shapes.java | 84 ++ .../dldungeons/pieces/Spawner.java | 63 ++ .../dldungeons/pieces/chests/BasicChest.java | 122 +++ .../pieces/chests/LootCategory.java | 209 +++++ .../dldungeons/pieces/chests/LootHandler.java | 51 + .../dldungeons/pieces/chests/LootItem.java | 403 ++++++++ .../dldungeons/pieces/chests/LootList.java | 69 ++ .../dldungeons/pieces/chests/LootListSet.java | 421 +++++++++ .../dldungeons/pieces/chests/LootResult.java | 26 + .../dldungeons/pieces/chests/LootType.java | 26 + .../pieces/chests/TreasureChest.java | 144 +++ .../dldungeons/pieces/chests/WeakChest.java | 53 ++ .../pieces/entrances/AbstractEntrance.java | 46 + .../pieces/entrances/SimpleEntrance.java | 60 ++ .../pieces/entrances/SpiralStair.java | 88 ++ .../dldungeons/pieces/entrances/TopRoom.java | 332 +++++++ .../dldungeons/planner/Dungeon.java | 500 ++++++++++ src/jaredbgreat/dldungeons/planner/Node.java | 41 + .../dldungeons/planner/RoomSeed.java | 235 +++++ src/jaredbgreat/dldungeons/planner/Route.java | 292 ++++++ .../dldungeons/planner/SpawnerCounter.java | 49 + .../dldungeons/planner/Symmetry.java | 120 +++ .../dldungeons/planner/astar/AStar.java | 192 ++++ .../dldungeons/planner/astar/AStar2.java | 181 ++++ .../dldungeons/planner/astar/DoorChecker.java | 228 +++++ .../dldungeons/planner/astar/DoorQueue.java | 38 + .../dldungeons/planner/astar/RoomBFS.java | 64 ++ .../dldungeons/planner/astar/Step.java | 98 ++ .../dldungeons/planner/astar/Step2.java | 30 + .../dldungeons/planner/features/Cutout.java | 130 +++ .../planner/features/Depression.java | 26 + .../planner/features/FeatureAdder.java | 61 ++ .../planner/features/IslandPlatform.java | 140 +++ .../planner/features/IslandRoom.java | 146 +++ .../dldungeons/planner/features/Pillar.java | 91 ++ .../dldungeons/planner/features/Pool.java | 131 +++ .../dldungeons/planner/mapping/MapMatrix.java | 245 +++++ .../dldungeons/planner/mapping/Tile.java | 45 + .../dldungeons/rooms/AbstractRoom.java | 199 ++++ src/jaredbgreat/dldungeons/rooms/Cave.java | 203 ++++ src/jaredbgreat/dldungeons/rooms/Room.java | 757 +++++++++++++++ .../dldungeons/rooms/RoomList.java | 88 ++ .../dldungeons/rooms/RoomType.java | 20 + .../dldungeons/setup/Externalizer.java | 210 +++++ .../dldungeons/themes/Autoselectable.java | 17 + .../dldungeons/themes/Autoselecting.java | 30 + .../dldungeons/themes/BiomeSets.java | 558 +++++++++++ src/jaredbgreat/dldungeons/themes/Degree.java | 51 + .../dldungeons/themes/Element.java | 84 ++ .../dldungeons/themes/Setting.java | 43 + .../dldungeons/themes/SizeElement.java | 61 ++ src/jaredbgreat/dldungeons/themes/Sizes.java | 37 + src/jaredbgreat/dldungeons/themes/Theme.java | 245 +++++ .../dldungeons/themes/ThemeFlags.java | 24 + .../dldungeons/themes/ThemeReader.java | 868 ++++++++++++++++++ .../dldungeons/themes/ThemeType.java | 214 +++++ src/me/zhehe/BiomeDictionary.java | 288 ++++++ src/me/zhehe/Configuration.java | 183 ++++ src/me/zhehe/Constant.java | 20 + src/me/zhehe/DungeonPopulator.java | 52 ++ src/me/zhehe/IProperty.java | 70 ++ src/me/zhehe/Logging.java | 19 + src/me/zhehe/Main.java | 95 ++ src/me/zhehe/WorldConfig.java | 64 ++ src/plugin.yml | 10 + 95 files changed, 15257 insertions(+) create mode 100644 resources/jaredbgreat/dldungeons/res/themes/chests.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/classic.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/common.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/continentalShelf.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/dank.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/desert.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/frozen.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/jungle.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/mesa.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/nbt.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/nether.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/oceanic.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/oceanic_chests.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/template.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/urban.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/villagelike.cfg create mode 100644 resources/jaredbgreat/dldungeons/res/themes/volcanic.cfg create mode 100644 src/com/gmail/nossr50/util/ItemUtils.java create mode 100644 src/jaredbgreat/dldungeons/ConfigHandler.java create mode 100644 src/jaredbgreat/dldungeons/Difficulty.java create mode 100644 src/jaredbgreat/dldungeons/GenerationHandler.java create mode 100644 src/jaredbgreat/dldungeons/Info.java create mode 100644 src/jaredbgreat/dldungeons/ReadAPI.java create mode 100644 src/jaredbgreat/dldungeons/builder/Builder.java create mode 100644 src/jaredbgreat/dldungeons/builder/DBlock.java create mode 100644 src/jaredbgreat/dldungeons/parser/CharSet.java create mode 100644 src/jaredbgreat/dldungeons/parser/Tokenizer.java create mode 100644 src/jaredbgreat/dldungeons/pieces/Doorway.java create mode 100644 src/jaredbgreat/dldungeons/pieces/Rectangle.java create mode 100644 src/jaredbgreat/dldungeons/pieces/Shape.java create mode 100644 src/jaredbgreat/dldungeons/pieces/Shapes.java create mode 100644 src/jaredbgreat/dldungeons/pieces/Spawner.java create mode 100644 src/jaredbgreat/dldungeons/pieces/chests/BasicChest.java create mode 100644 src/jaredbgreat/dldungeons/pieces/chests/LootCategory.java create mode 100644 src/jaredbgreat/dldungeons/pieces/chests/LootHandler.java create mode 100644 src/jaredbgreat/dldungeons/pieces/chests/LootItem.java create mode 100644 src/jaredbgreat/dldungeons/pieces/chests/LootList.java create mode 100644 src/jaredbgreat/dldungeons/pieces/chests/LootListSet.java create mode 100644 src/jaredbgreat/dldungeons/pieces/chests/LootResult.java create mode 100644 src/jaredbgreat/dldungeons/pieces/chests/LootType.java create mode 100644 src/jaredbgreat/dldungeons/pieces/chests/TreasureChest.java create mode 100644 src/jaredbgreat/dldungeons/pieces/chests/WeakChest.java create mode 100644 src/jaredbgreat/dldungeons/pieces/entrances/AbstractEntrance.java create mode 100644 src/jaredbgreat/dldungeons/pieces/entrances/SimpleEntrance.java create mode 100644 src/jaredbgreat/dldungeons/pieces/entrances/SpiralStair.java create mode 100644 src/jaredbgreat/dldungeons/pieces/entrances/TopRoom.java create mode 100644 src/jaredbgreat/dldungeons/planner/Dungeon.java create mode 100644 src/jaredbgreat/dldungeons/planner/Node.java create mode 100644 src/jaredbgreat/dldungeons/planner/RoomSeed.java create mode 100644 src/jaredbgreat/dldungeons/planner/Route.java create mode 100644 src/jaredbgreat/dldungeons/planner/SpawnerCounter.java create mode 100644 src/jaredbgreat/dldungeons/planner/Symmetry.java create mode 100644 src/jaredbgreat/dldungeons/planner/astar/AStar.java create mode 100644 src/jaredbgreat/dldungeons/planner/astar/AStar2.java create mode 100644 src/jaredbgreat/dldungeons/planner/astar/DoorChecker.java create mode 100644 src/jaredbgreat/dldungeons/planner/astar/DoorQueue.java create mode 100644 src/jaredbgreat/dldungeons/planner/astar/RoomBFS.java create mode 100644 src/jaredbgreat/dldungeons/planner/astar/Step.java create mode 100644 src/jaredbgreat/dldungeons/planner/astar/Step2.java create mode 100644 src/jaredbgreat/dldungeons/planner/features/Cutout.java create mode 100644 src/jaredbgreat/dldungeons/planner/features/Depression.java create mode 100644 src/jaredbgreat/dldungeons/planner/features/FeatureAdder.java create mode 100644 src/jaredbgreat/dldungeons/planner/features/IslandPlatform.java create mode 100644 src/jaredbgreat/dldungeons/planner/features/IslandRoom.java create mode 100644 src/jaredbgreat/dldungeons/planner/features/Pillar.java create mode 100644 src/jaredbgreat/dldungeons/planner/features/Pool.java create mode 100644 src/jaredbgreat/dldungeons/planner/mapping/MapMatrix.java create mode 100644 src/jaredbgreat/dldungeons/planner/mapping/Tile.java create mode 100644 src/jaredbgreat/dldungeons/rooms/AbstractRoom.java create mode 100644 src/jaredbgreat/dldungeons/rooms/Cave.java create mode 100644 src/jaredbgreat/dldungeons/rooms/Room.java create mode 100644 src/jaredbgreat/dldungeons/rooms/RoomList.java create mode 100644 src/jaredbgreat/dldungeons/rooms/RoomType.java create mode 100644 src/jaredbgreat/dldungeons/setup/Externalizer.java create mode 100644 src/jaredbgreat/dldungeons/themes/Autoselectable.java create mode 100644 src/jaredbgreat/dldungeons/themes/Autoselecting.java create mode 100644 src/jaredbgreat/dldungeons/themes/BiomeSets.java create mode 100644 src/jaredbgreat/dldungeons/themes/Degree.java create mode 100644 src/jaredbgreat/dldungeons/themes/Element.java create mode 100644 src/jaredbgreat/dldungeons/themes/Setting.java create mode 100644 src/jaredbgreat/dldungeons/themes/SizeElement.java create mode 100644 src/jaredbgreat/dldungeons/themes/Sizes.java create mode 100644 src/jaredbgreat/dldungeons/themes/Theme.java create mode 100644 src/jaredbgreat/dldungeons/themes/ThemeFlags.java create mode 100644 src/jaredbgreat/dldungeons/themes/ThemeReader.java create mode 100644 src/jaredbgreat/dldungeons/themes/ThemeType.java create mode 100644 src/me/zhehe/BiomeDictionary.java create mode 100644 src/me/zhehe/Configuration.java create mode 100644 src/me/zhehe/Constant.java create mode 100644 src/me/zhehe/DungeonPopulator.java create mode 100644 src/me/zhehe/IProperty.java create mode 100644 src/me/zhehe/Logging.java create mode 100644 src/me/zhehe/Main.java create mode 100644 src/me/zhehe/WorldConfig.java create mode 100644 src/plugin.yml diff --git a/resources/jaredbgreat/dldungeons/res/themes/chests.cfg b/resources/jaredbgreat/dldungeons/res/themes/chests.cfg new file mode 100644 index 0000000..35abb5a --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/chests.cfg @@ -0,0 +1,241 @@ +# What goes in the chests +# Each line contains: +# type, level, modid.name, minimum amount, maximum amount, NBT tag (from nbt.cfg) +# +# type must be gear, heal (food / health), or loot (treasure) +# level must be an integer from 1 to 8 representing the value / difficulty of guarding mobs +# Normally this should be 1 to 7, a value of 8 will appear only in rare teasure chests +# modid is the official ID of the mod; for vanilla items the modid is "item" +# name is the in-code, unlocalized name +# minimum and maximum determine the stacks sizes +# +# You can now create alternate version in the SpecialChests folder and attach those to +# dungeon themes. + +gear, 1, minecraft:stone_sword, 1, 1 +gear, 1, minecraft:leather_helmet, 1, 1 +gear, 1, minecraft:leather_leggings, 1, 1 +gear, 1, minecraft:leather_boots, 1, 1 +gear, 1, minecraft:leather_chestplate, 1, 1 +gear, 1, minecraft:arrow, 4, 12 +gear, 1, minecraft:torch, 4, 12 + +gear, 2, minecraft:stone_sword, 1, 1 +gear, 2, minecraft:iron_sword, 1, 1 +gear, 2, minecraft:stone_pickaxe, 1, 1 +gear, 2, minecraft:stone_axe, 1, 1 +gear, 2, minecraft:bow, 1, 1 +gear, 2, minecraft:shield, 1, 1 +gear, 2, minecraft:leather_helmet, 1, 1 +gear, 2, minecraft:leather_leggings, 1, 1 +gear, 2, minecraft:leather_boots, 1, 1 +gear, 2, minecraft:leather_chestplate, 1, 1 +gear, 2, minecraft:iron_helmet, 1, 1 +gear, 2, minecraft:iron_leggings, 1, 1 +gear, 2, minecraft:iron_boots, 1, 1 +gear, 2, minecraft:iron_chestplate, 1, 1 +gear, 2, minecraft:arrow, 4, 12 +gear, 2, minecraft:torch, 4, 12 +gear, 2, minecraft:torch, 4, 24 + +gear, 3, minecraft:iron_sword, 1, 1 +gear, 3, minecraft:iron_pickaxe, 1, 1 +gear, 3, minecraft:iron_axe, 1, 1 +gear, 3, minecraft:bow, 1, 1 +gear, 3, minecraft:shield, 1, 1 +gear, 3, minecraft:iron_helmet, 1, 1 +gear, 3, minecraft:iron_leggings, 1, 1 +gear, 3, minecraft:iron_boots, 1, 1 +gear, 3, minecraft:iron_chestplate, 1, 1 +gear, 3, minecraft:arrow, 4, 12 +gear, 3, minecraft:torch, 4, 12 +gear, 3, minecraft:arrow, 8, 16 +gear, 3, minecraft:torch, 12, 16 +gear, 3, minecraft:torch, 16, 32 + +gear, 4, minecraft:iron_sword, 1, 1 +gear, 4, minecraft:diamond_sword, 1, 1 +gear, 4, minecraft:bow, 1, 1 +gear, 4, minecraft:shield, 1, 1 +gear, 4, minecraft:iron_helmet, 1, 1 +gear, 4, minecraft:iron_leggings, 1, 1 +gear, 4, minecraft:iron_boots, 1, 1 +gear, 4, minecraft:iron_chestplate, 1, 1 +gear, 4, minecraft:diamond_helmet, 1, 1 +gear, 4, minecraft:diamond_leggings, 1, 1 +gear, 4, minecraft:diamond_boots, 1, 1 +gear, 4, minecraft:diamond_chestplate, 1, 1 +gear, 4, minecraft:arrow, 4, 12 +gear, 4, minecraft:torch, 4, 12 +gear, 4, minecraft:arrow, 8, 16 +gear, 4, minecraft:torch, 12, 16 +gear, 4, minecraft:torch, 16, 32 + +gear, 5, minecraft:diamond_sword, 1, 1 +gear, 5, minecraft:diamond_pickaxe, 1, 1 +gear, 5, minecraft:diamond_axe, 1, 1 +gear, 5, minecraft:diamond_helmet, 1, 1 +gear, 5, minecraft:diamond_leggings, 1, 1 +gear, 5, minecraft:diamond_boots, 1, 1 +gear, 5, minecraft:diamond_chestplate, 1, 1 +gear, 2, minecraft:shield, 1, 1 +gear, 5, minecraft:arrow, 8, 16 +gear, 5, minecraft:torch, 4, 12 +gear, 5, minecraft:arrow, 8, 16 +gear, 5, minecraft:torch, 16, 24 +gear, 5, minecraft:torch, 16, 48 + +gear, 6, minecraft:diamond_sword, 1, 1 +gear, 6, minecraft:diamond_sword, 1, 1, SLSW +gear, 6, minecraft:diamond_helmet, 1, 1 +gear, 6, minecraft:diamond_leggings, 1, 1 +gear, 6, minecraft:diamond_boots, 1, 1 +gear, 6, minecraft:diamond_chestplate, 1, 1 +gear, 6, minecraft:arrow, 16, 48 +gear, 6, minecraft:arrow, 8, 16 +gear, 6, minecraft:torch, 16, 24 +gear, 6, minecraft:torch, 32, 64 + +gear, 7, minecraft:diamond_sword, 1, 1 +gear, 7, minecraft:diamond_pickaxe, 1, 1 +gear, 7, minecraft:diamond_helmet, 1, 1 +gear, 7, minecraft:diamond_leggings, 1, 1 +gear, 7, minecraft:diamond_boots, 1, 1 +gear, 7, minecraft:diamond_chestplate, 1, 1 +gear, 7, minecraft:arrow, 16, 48 +gear, 7, minecraft:torch, 32, 64 + +heal, 1, minecraft:bread, 1, 2 + +heal, 2, minecraft:bread, 1, 3 +heal, 2, minecraft:apple, 1, 2 +heal, 2, minecraft:cooked_chicken, 1, 3 + +heal, 3, minecraft:bread, 2, 4 +heal, 3, minecraft:apple, 1, 2 +heal, 3, minecraft:cooked_chicken, 1, 3 +heal, 3, minecraft:cooked_beef, 1, 3 +heal, 3 minecraft:potion, 1, 1, HEALTH1 + +heal, 4, minecraft:bread, 2, 4 +heal, 4, minecraft:apple, 1, 3 +heal, 4, minecraft:apple, 1, 4 +heal, 4, minecraft:cooked_chicken, 1, 3 +heal, 4, minecraft:cooked_beef, 1, 3 +heal, 4, minecraft:golden_apple, 1, 1 +heal, 4 minecraft:potion, 1, 1, HEALTH1 +heal, 4 minecraft:potion, 1, 1,HEALTH2 +heal, 4 minecraft:potion, 1, 1, REGEN1 + +heal, 5, minecraft:bread, 2, 4 +heal, 5, minecraft:pumpkin_pie, 1, 2 +heal, 5, minecraft:apple, 2, 4 +heal, 5, minecraft:cooked_chicken, 2, 4 +heal, 5, minecraft:cooked_beef, 2 4 +heal, 5, minecraft:golden_apple, 1, 1 +heal, 5, minecraft:golden_apple, 1, 1 +heal, 5, minecraft:potion, 1, 1, HEALTH2 +heal, 5, minecraft:potion, 1, 1, REGEN1 +heal, 5, minecraft:potion, 1, 1, REGENX + +heal, 6, minecraft:pumpkin_pie, 1, 3 +heal, 6, minecraft:apple, 3, 7 +heal, 6, minecraft:cooked_beef, 4, 8 +heal, 6, minecraft:golden_apple, 1, 2 +heal, 6, minecraft:potion, 1, 1, HEALTH2 +heal, 6, minecraft:potion, 1, 1, REGEN2 +heal, 6, minecraft:potion, 1, 1, REGENX + +heal, 7, minecraft:apple, 3, 7 +heal, 7, minecraft:cooked_beef, 4, 8 +heal, 7, minecraft:pumpkin_pie, 2, 7 +heal, 7, minecraft:enchanted_golden_apple, 1, 1 +heal, 7, minecraft:golden_apple, 1, 3 +heal, 7, minecraft:potion, 1, 1, REGEN2 +heal, 7, minecraft:potion, 1, 1, REGENX + +loot, 1, minecraft:iron_ingot, 1, 8 +loot, 1, minecraft:gold_ingot, 1, 1 +loot, 1, minecraft:book, 1, 1 +loot, 1, minecraft:apple, 1, 3 +loot, 1, minecraft:torch, 4, 12 + +loot, 2, minecraft:book, 1, 1 +loot, 2, minecraft:book, 2, 5 +loot, 2, minecraft:iron_ingot, 1, 8 +loot, 2, minecraft:gold_ingot, 1, 1 +loot, 2, minecraft:gold_ingot, 2, 5 +loot, 2, minecraft:name_tag, 1, 1 + +loot, 3, minecraft:book, 2, 5 +loot, 3, minecraft:gold_ingot, 2, 5 +loot, 3, minecraft:diamond, 1, 1 +loot, 3, minecraft:iron_ingot, 3, 12 +loot, 3, minecraft:emerald, 1, 1 +loot, 3, minecraft:saddle 1, 1 +loot, 3, minecraft:name_tag, 1, 1 +loot, 3, minecraft:jukebox, 1, 1 +loot, 3, minecraft:iron_horse_armor, 1, 1 +loot, 3, minecraft:clock, 1, 1 + +loot, 4, minecraft:golden_apple, 1, 1 +loot, 4, minecraft:blaze_rod, 1, 3 +loot, 4, minecraft:book, 3, 8 +loot, 4, minecraft:ender_pearl, 1, 9 +loot, 4, minecraft:iron_ingot, 3, 12 +loot, 4, minecraft:gold_ingot, 2, 5 +loot, 4, minecraft:diamond, 1, 1 +loot, 4, minecraft:diamond, 1, 4 +loot, 4, minecraft:emerald, 1, 1 +loot, 4, minecraft:emerald, 1, 4 +loot, 4, minecraft:saddle 1, 1 +loot, 4, minecraft:name_tag, 1, 1 +loot, 4, minecraft:brewing_stand, 1, 1 +loot, 4, minecraft:golden_horse_armor, 1, 1 + +loot, 5, minecraft:book, 3, 8 +loot, 5, minecraft:blaze_rod, 1, 3 +loot, 5, minecraft:golden_apple, 1, 1 +loot, 5, minecraft:ender_eye, 1, 2 +loot, 5, minecraft:ender_pearl, 1, 9 +loot, 5, minecraft:iron_ingot, 3, 12 +loot, 5, minecraft:gold_ingot, 3, 8 +loot, 5, minecraft:diamond, 1, 4 +loot, 5, minecraft:emerald, 1, 1 +loot, 5, minecraft:emerald, 1, 8 +loot, 5, minecraft:saddle 1, 1 +loot, 5, minecraft:name_tag, 1, 2 +loot, 5, minecraft:enchanting_table, 1, 1 +loot, 5, minecraft:diamond_horse_armor, 1, 1 +loot, 5, minecraft:purple_shulker_box, 1, 1 + +loot, 6, minecraft:book, 3, 8 +loot, 6, minecraft:ender_eye, 1, 2 +loot, 6, minecraft:ender_pearl, 1, 9 +loot, 6, minecraft:golden_apple, 1, 3 +loot, 6, minecraft:iron_ingot, 3, 12 +loot, 6, minecraft:gold_ingot, 3, 8 +loot, 6, minecraft:diamond, 1, 6 +loot, 6, minecraft:emerald, 1, 12 +loot, 6, minecraft:saddle 1, 1 +loot, 6, minecraft:name_tag, 1, 3 +loot, 6, minecraft:diamond_horse_armor, 1, 1 +loot, 6, minecraft:purple_shulker_box, 1, 1 + +loot, 7, minecraft:gold_ingot, 3, 8 +loot, 7, minecraft:diamond_block, 1, 2 +loot, 7, minecraft:emerald_block, 1, 3 +loot, 7, minecraft:ender_eye, 1, 2 +loot, 7, minecraft:enchanted_golden_apple, 1, 1 +loot, 7, minecraft:saddle 1, 1 +loot, 7, minecraft:name_tag, 1, 4 +loot, 7, minecraft:totem_of_undying, 1, 1 +loot, 7, minecraft:elytra, 1, 1 +loot, 7, minecraft:wither_skeleton_skull, 1, 1 + +loot, 8, minecraft:nether_star, 1, 1 +loot, 8, minecraft:diamond_block, 1, 12 +loot, 8, minecraft:emerald_block, 1, 12 +loot, 8, minecraft:wither_skeleton_skull, 1, 8 +loot, 8, minecraft:beacon, 1, 1, +loot, 8, minecraft:diamond_pickaxe, 1, 1, VANILLAWORLD diff --git a/resources/jaredbgreat/dldungeons/res/themes/classic.cfg b/resources/jaredbgreat/dldungeons/res/themes/classic.cfg new file mode 100644 index 0000000..a82c26b --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/classic.cfg @@ -0,0 +1,106 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = FOREST, PLAINS, MOUNTAINS, HILLS, DESERT, FROZEN, WASTELAND +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END, MESA, SWAMP + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values includ DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = DUNGEON + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 30 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 1, 30, 50, 20, 10, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 5, 10, 25, 20, 10, 0 +# How many entrances to place +entrances = 2, 5, 25, 50, 15, 3 +naturals = 25, 5, 20, 5, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:stone_bricks, minecraft:cobblestone, minecraft:sandstone, minecraft:bricks +# The main block for building floors +floors = minecraft:stone_bricks, minecraft:cobblestone, minecraft:dirt, minecraft:stone +# The main block for lining ceilings +ceilings = minecraft:stone_bricks, minecraft:cobblestone, minecraft:oak_planks, minecraft:stone_slab +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:cobblestone_wall, minecraft:oak_fence +# Block to represent liquids; fill pools +liquid = minecraft:water, minecraft:lava +# Block from which to build pillars +pillarBlock = minecraft:stone_bricks, minecraft:cobblestone, minecraft:sandstone, minecraft:oak_planks, minecraft:stone_slab +# Block found in cave-like areas +caveblock = minecraft:stone, minecraft:stone, minecraft:sandstone +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/common.cfg b/resources/jaredbgreat/dldungeons/res/themes/common.cfg new file mode 100644 index 0000000..6ad314c --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/common.cfg @@ -0,0 +1,107 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = FOREST, PLAINS, MOUNTAINS, HILLS, DESERT, FROZEN, WASTELAND +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END, MESA, SAWMP + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values includ DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = DUNGEON + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 25 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 1, 30, 50, 20, 10, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 5, 10, 25, 20, 10, 0 +# How many entrances to place +entrances = 2, 5, 25, 50, 15, 3 +naturals = 5, 10, 25, 10, 15, 5 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:stone_bricks, minecraft:cobblestone, minecraft:cracked_stone_bricks, minecraft:cobblestone +# The main block for building floors +floors = minecraft:stone_bricks, minecraft:cobblestone, minecraft:cracked_stone_bricks, minecraft:dirt, minecraft:stone +# The main block for lining ceilings +ceilings = minecraft:stone_bricks, minecraft:cobblestone, minecraft:cracked_stone_bricks, minecraft:oak_planks, minecraft:stone_slab +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:cobblestone_wall +# Block to represent liquids; fill pools +liquid = minecraft:water, minecraft:lava +# Block from which to build pillars +pillarBlock = minecraft:stone_bricks, minecraft:cracked_stone_bricks, minecraft:sandstone, minecraft:oak_planks, minecraft:stone_slab, minecraft:polished_andesite, minecraft:polished_diorite, minecraft:granite +# Block found in cave-like areas +caveblock = minecraft:stone + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/continentalShelf.cfg b/resources/jaredbgreat/dldungeons/res/themes/continentalShelf.cfg new file mode 100644 index 0000000..5649a12 --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/continentalShelf.cfg @@ -0,0 +1,111 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +biomes = WATER +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END, SWAMP + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values includ DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = DUNGEON + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 10 +# Highest level a floor can be at +maxY = 15 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# Should a foundation of pedestal be built between rooms and the ground; mostly +# for surface dungeons (including Nether dungeons). +buildFoundation = false + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 5, 15, 5, 1, 0 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 0, 10, 30, 50, 20, 10 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 5, 10, 25, 20, 10, 0 +# How many entrances to place +entrances = 2, 0, 0, 0, 0, 0 +# Frequency of cave-like areas +naturals = 25, 20, 15, 10, 5, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:stone, minecraft:cobblestone, minecraft:sandstone, minecraft:stone +# The main block for building floors +floors = minecraft:stone, minecraft:cobblestone, minecraft:dirt, minecraft:stone +# The main block for lining ceilings +ceilings = minecraft:stone, minecraft:cobblestone, minecraft:sandstone, minecraft:stone +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:cobblestone_wall, minecraft:oak_fence +# Block to represent liquids; fill pools +liquid = minecraft:water, minecraft:lava +# Block from which to build pillars +pillarBlock = minecraft:stone_bricks, minecraft:cobblestone, minecraft:sandstone, minecraft:oak_planks, minecraft:stone_slab +# Block found in cave-like areas +caveblock = minecraft:stone + + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/dank.cfg b/resources/jaredbgreat/dldungeons/res/themes/dank.cfg new file mode 100644 index 0000000..951f139 --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/dank.cfg @@ -0,0 +1,109 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = SWAMP, WET, JUNGLE +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END, DRY + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values includ DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = SWAMP +Flags = SWAMPY + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 40 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 0, 0, 0, 5, 10, 85 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 0, 5, 50, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 25, 50, 20, 5, 0, 0 +# How many entrances to place +entrances = 2, 5, 25, 50, 15, 3 +naturals = 25, 20, 5, 0, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:mossy_cobblestone, minecraft:mossy_stone_bricks +# The main block for building floors +floors = minecraft:mossy_cobblestone, minecraft:dirt, minecraft:oak_planks, minecraft:water, minecraft:water +floors = minecraft:mossy_stone_bricks, minecraft:mossy_stone_bricks +# The main block for lining ceilings +ceilings = minecraft:mossy_cobblestone, minecraft:oak_planks, minecraft:oak_planks, minecraft:mossy_stone_bricks +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:mossy_cobblestone_wall, minecraft:oak_fence +# Block to represent liquids; fill pools +liquid = minecraft:water, minecraft:water, minecraft:water +# Block from which to build pillars +pillarBlock = minecraft:mossy_stone_bricks, minecraft:oak_planks, minecraft:oak_log +# Block found in cave-like areas +caveblock = minecraft:stone, minecraft:stone, minecraft:mossy_cobblestone + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/desert.cfg b/resources/jaredbgreat/dldungeons/res/themes/desert.cfg new file mode 100644 index 0000000..df442a7 --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/desert.cfg @@ -0,0 +1,111 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = DESERT, DRY, SANDY +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END, WET, MESA + +Type = DESERT + + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 35 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 10, 50, 30, 10, 1, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 5, 10, 25, 20, 10, 0 +# How many entrances to place +entrances = 2, 5, 25, 50, 15, 3 +naturals = 25, 5, 20, 5, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:sandstone, minecraft:cut_sandstone +# The main block for building floors +floors = minecraft:sandstone, minecraft:sandstone, minecraft:sandstone, minecraft:sandstone, minecraft:sandstone +florrs = minecraft:cobblestone, minecraft:cobblestone, minecraft:stone_slab +# The main block for lining ceilings +ceilings = minecraft:sandstone, minecraft:sandstone, minecraft:oak_planks, minecraft:stone_slab +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:oak_fence +# Block to represent liquids; fill pools +liquid = minecraft:water, minecraft:lava, minecraft:air, minecraft:air, minecraft:sand +# Block from which to build pillars +pillarBlock = minecraft:chiseled_sandstone, minecraft:cut_sandstone, minecraft:lapis_block, minecraft:oak_planks, minecraft:oak_log +# Block found in cave-like areas +caveblock = minecraft:sandstone, minecraft:sandstone, minecraft:sandstone, minecraft:sandstone + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/frozen.cfg b/resources/jaredbgreat/dldungeons/res/themes/frozen.cfg new file mode 100644 index 0000000..9a2247c --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/frozen.cfg @@ -0,0 +1,107 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = COLD, SNOWY +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values includ DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = FROZEN + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 30 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 1, 30, 50, 20, 10, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 5, 10, 25, 20, 10, 0 +# How many entrances to place +entrances = 2, 5, 25, 50, 15, 3 +naturals = 20, 5, 25, 5, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:stone_bricks, minecraft:cobblestone, minecraft:packed_ice +# The main block for building floors +floors = minecraft:stone_bricks, minecraft:cobblestone, minecraft:ice, minecraft:snow, minecraft:packed_ice +# The main block for lining ceilings +ceilings = minecraft:stone_bricks, minecraft:stone, minecraft:packed_ice +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:cobblestone_wall, minecraft:oak_fence +# Block to represent liquids; fill pools +liquid = minecraft:ice +# Block from which to build pillars +pillarBlock = minecraft:stone_bricks, minecraft:ice, minecraft:packed_ice +# Block found in cave-like areas +caveblock = minecraft:stone, minecraft:packed_ice + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/jungle.cfg b/resources/jaredbgreat/dldungeons/res/themes/jungle.cfg new file mode 100644 index 0000000..2d89bc0 --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/jungle.cfg @@ -0,0 +1,107 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = JUNGLE, LUSH +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values includ DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = JUNGLE + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 25 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 0, 20, 50, 30, 10, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 0, 20, 60, 60, 40, 5 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 0, 0, 0, 75, 25, 5 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 0, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 0, 0, 15, 75, 10, 0 +# How much variation in the Y should be found +verticle = 5, 10, 25, 20, 10, 0 +# How many entrances to place +entrances = 0, 2, 5, 25, 50, 15 +naturals = 20, 5, 25, 5, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:stone_bricks, minecraft:mossy_cobblestone +# The main block for building floors +floors = minecraft:stone_bricks, minecraft:mossy_cobblestone, minecraft:dirt, minecraft:stone +# The main block for lining ceilings +ceilings = minecraft:stone_bricks, minecraft:mossy_cobblestone, minecraft:stone_slab +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:mossy_cobblestone_wall +# Block to represent liquids; fill pools +liquid = minecraft:water, minecraft:lava +# Block from which to build pillars +pillarBlock = minecraft:stone_bricks, minecraft:chiseled_stone_bricks +# Block found in cave-like areas +caveblock = minecraft:stone + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/mesa.cfg b/resources/jaredbgreat/dldungeons/res/themes/mesa.cfg new file mode 100644 index 0000000..6b9467a --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/mesa.cfg @@ -0,0 +1,125 @@ +Version 1.7 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = MESA +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END + +Type = DESERT, URBAN, MAGICAL + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 35 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 10, 50, 30, 10, 1, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 5, 10, 25, 20, 10, 0 +# How many entrances to place +entrances = 2, 5, 25, 50, 15, 3 +naturals = 25, 5, 20, 5, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:terracotta, minecraft:terracotta, minecraft:terracotta, minecraft:orange_terracotta +walls = minecraft:gray_terracotta, minecraft:black_terracotta, minecraft:white_terracotta +walls = minecraft:orange_terracotta, minecraft:magenta_terracotta, minecraft:light_blue_terracotta +walls = minecraft:yellow_terracotta, minecraft:lime_terracotta, minecraft:pink_terracotta +walls = minecraft:gray_terracotta, minecraft:light_gray_terracotta, minecraft:cyan_terracotta +walls = minecraft:purple_terracotta, minecraft:blue_terracotta, minecraft:brown_terracotta +walls = minecraft:green_terracotta, minecraft:red_terracotta, minecraft:black_terracotta +# The main block for building floors +floors = minecraft:terracotta, minecraft:terracotta, minecraft:terracotta, minecraft:orange_terracotta +floors = minecraft:gray_terracotta, minecraft:black_terracotta, minecraft:white_terracotta +floors = minecraft:orange_terracotta, minecraft:magenta_terracotta, minecraft:light_blue_terracotta +floors = minecraft:yellow_terracotta, minecraft:lime_terracotta, minecraft:pink_terracotta +floors = minecraft:gray_terracotta, minecraft:light_gray_terracotta, minecraft:cyan_terracotta +floors = minecraft:purple_terracotta, minecraft:blue_terracotta, minecraft:brown_terracotta +floors = minecraft:green_terracotta, minecraft:red_terracotta, minecraft:black_terracotta +# The main block for lining ceilings +ceilings = minecraft:oak_planks, minecraft:terracotta, minecraft:terracotta, minecraft:terracotta +ceilings = minecraft:orange_terracotta, minecraft:gray_terracotta, minecraft:black_terracotta +ceilings = minecraft:white_terracotta, minecraft:orange_terracotta, minecraft:magenta_terracotta +ceilings = minecraft:light_blue_terracotta, minecraft:yellow_terracotta, minecraft:lime_terracotta +ceilings = minecraft:pink_terracotta, minecraft:gray_terracotta, minecraft:light_gray_terracotta +ceilings = minecraft:cyan_terracotta, minecraft:purple_terracotta, minecraft:blue_terracotta +ceilings = minecraft:brown_terracotta, minecraft:green_terracotta, minecraft:red_terracotta +ceilings = minecraft:black_terracotta +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:oak_fence +# Block to represent liquids; fill pool +liquid = minecraft:water, minecraft:water, minecraft:lava, minecraft:air, minecraft:air, minecraft:sand +liquid = minecraft:water, minecraft:lava, minecraft:air, minecraft:red_sand, minecraft:red_sand +# Block from which to build pillars +pillarBlock = minecraft:white_terracotta, minecraft:orange_terracotta, minecraft:magenta_terracotta +pillarBlock = minecraft:light_blue_terracotta, minecraft:yellow_terracotta, minecraft:lime_terracotta +pillarBlock = minecraft:pink_terracotta, minecraft:gray_terracotta, minecraft:light_gray_terracotta +pillarBlock = minecraft:cyan_terracotta, minecraft:purple_terracotta, minecraft:blue_terracotta +pillarBlock = minecraft:brown_terracotta, minecraft:green_terracotta, minecraft:red_terracotta +pillarBlock = minecraft:black_terracotta, minecraft:oak_planks, minecraft:oak_log + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/nbt.cfg b/resources/jaredbgreat/dldungeons/res/themes/nbt.cfg new file mode 100644 index 0000000..986006a --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/nbt.cfg @@ -0,0 +1,64 @@ +#Each line is has the following components: +#label type name data +# +#label is what you use to add it to an itam or combine it with othe tags (must be unique) +#type is the NBT data type -- and valid type but list can be used +#name is the name of the data field in the NBT file +#data is what it holds +# +#I'm not giving a full NBT course here -- I'm just learning that myself, but below are some examples. +#More info can be found online in places such as the Minecraft Wiki +#This is a good start: http://minecraft.gamepedia.com/Player.dat_format#Item_structure +# +#Whether or not this might latter be applicable to blocks or mobs has not been decided; +#For now NBT can only be used for loot items. +# +#In addition to normal NBT tags there is an Ench tag as a convenience for enchanting... +# label ench id lvl +#...and a Group options that simply allows several additions to be put into on label. +# +#WARNING: This can be easy to mess-up, and there is no error checking (but the game may crash on start-up) +# +#For defining entire NBT tags in one go, the json "type" can be used. To define a tag, copy the output of a command +#like "/blockdata {}", pointed at a chest containing desired items, then put the NBT tag of the item you want to copy. +#Do not define a name for this type. +#If you have CraftTweaker, holding the item with wanted data and doing "/ct nbt" +#will output a clickable link to copy the NBT data to paste in here. + + +#Basic Potions +HEALTH1 Json {Potion: "minecraft:healing"} +HEALTH2 Json {Potion: "minecraft:strong_healing"} +REGEN1 Json {Potion: "minecraft:regeneration"} +REGEN2 Json {Potion: "minecraft:strong_regeneration"} +REGENX Json {Potion: "minecraft:long_regeneration"} + +# Oceanic Potions +WBREATH1 Json {Potion: "minecraft:water_breathing"} +WBREATH2 Json {Potion: "minecraft:long_water_breathing"} +NEYE1 Json {Potion: "minecraft:night_vision"} +NEYE2 Json {Potion: "minecraft:long_night_vision"} + +#Hard way to make a custom enchant +SHARP Short id 16 +LOOT Short id 21 +SILK Short id 33 +LVL1 Short lvl 1 +LVL3 Short lvl 3 +SLICE String Name "Clean Slicer" +SLNM Compound display SLICE + +SHARP3 Compound 0 SHARP,LVL3 +LOOT1 Compound 1 LOOT,LVL1 +SILK1 Compound 2 SILK,LVL1 +SLEN List ench SHARP3,LOOT1,SILK1 +SLSW Group Slice SLEN,SLNM + +#Easy way to make a custom enchant +ETERNAL Byte Unbreakable 1 +EEGG1 Ench 35 3 +EEGG3 Ench 32 5 +EEGG5 String Name "Fortuna Major" +EEGG6 Compound display EEGG5 +VANILLAWORLD Group EasterEgg EEGG1,EEGG3,EEGG6,ETERNAL + diff --git a/resources/jaredbgreat/dldungeons/res/themes/nether.cfg b/resources/jaredbgreat/dldungeons/res/themes/nether.cfg new file mode 100644 index 0000000..ea89879 --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/nether.cfg @@ -0,0 +1,112 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = NETHER +# NotInBiomes = FOREST, PLAINS, MOUNTAINS, HILLS, SWAMP, WATER, DESER, FROZEN, JUNGLE, WASTELAND + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values includ DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = NETHER +Flags = HARD + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 32 +# Highest level a floor can be at +maxY = 64 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# Should a foundation of pedestal be built between rooms and the ground; mostly +# for surface dungeons (including Nether dungeons). +buildFoundation = true + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 15, 25, 20, 10, 5, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 1, 30, 50, 20, 10, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 0, 0, 0, 0, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 5, 10, 25, 20, 10, 0 +# How many entrances to place +entrances = 10, 0, 0, 0, 0, 0 +naturals = 25, 5, 20, 5, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:nether_bricks +# The main block for building floors +floors = minecraft:nether_bricks +# The main block for lining ceilings +ceilings = minecraft:nether_bricks +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:nether_brick_fence +# Block to represent liquids; fill pools +liquid = minecraft:lava +# Block from which to build pillars +pillarBlock = minecraft:nether_bricks, minecraft:obsidian, minecraft:nether_bricks, minecraft:obsidian, minecraft:quartz_block +# Block found in cave-like areas +caveblock = minecraft:nether_bricks, minecraft:netherrack + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:skeleton, minecraft:magma_cube +# Tougher mobs everyday mobs +hardMobs = minecraft:wither_skeleton, minecraft:blaze +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss (the nether theme is tagged as "HARD" so it treats everything as harder than its level). +eliteMobs = minecraft:wither +bossMobs = minecraft:wither + diff --git a/resources/jaredbgreat/dldungeons/res/themes/oceanic.cfg b/resources/jaredbgreat/dldungeons/res/themes/oceanic.cfg new file mode 100644 index 0000000..f514891 --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/oceanic.cfg @@ -0,0 +1,113 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = OCEAN, WATER +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values includ DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = WATER +Flags = WATER, HARD + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 40 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = oceanic_chests.cfg + + +# Should a foundation of pedestal be built between rooms and the ground; mostly +# for surface dungeons (including Nether dungeons). +buildFoundation = true + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 2, 20, 10, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 0, 0, 0, 0, 0, 100 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 25, 75, 50, 25, 5, 0 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 5, 10, 25, 20, 10, 0 +# How many entrances to place +entrances = 2, 0, 0, 0, 0, 0 +naturals = 25, 10, 5, 0, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:stone_bricks, minecraft:cobblestone, minecraft:sandstone, minecraft:bricks +# The main block for building floors +floors = minecraft:stone_bricks, minecraft:cobblestone, minecraft:dirt, minecraft:stone +# The main block for lining ceilings +ceilings = minecraft:stone_bricks, minecraft:cobblestone, minecraft:water, minecraft:stone_slab +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:stone_bricks, minecraft:cobblestone, minecraft:sandstone +fencing = minecraft:bricks, minecraft:dirt, minecraft:stone +# Block to represent liquids; fill pools +liquid = minecraft:water, minecraft:gravel +# Block from which to build pillars +pillarBlock = minecraft:stone_bricks, minecraft:cobblestone, minecraft:sandstone, minecraft:oak_planks, minecraft:stone_slab +# Block found in cave-like areas +caveblock = minecraft:stone, minecraft:stone, minecraft:cobblestone, minecraft:sandstone, + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:guardian +# Tougher mobs everyday mobs +hardMobs = minecraft:guardian +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:elder_guardian +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = minecraft:elder_guardian +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/oceanic_chests.cfg b/resources/jaredbgreat/dldungeons/res/themes/oceanic_chests.cfg new file mode 100644 index 0000000..586529b --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/oceanic_chests.cfg @@ -0,0 +1,240 @@ +# What goes in the chests +# Each line contains: +# type, level, modid.name, minimum amount, maximum amount, NBT tag (from nbt.cfg) +# +# type must be gear, heal (food / health), or loot (treasure) +# level must be an integer from 1 to 8 representing the value / difficulty of guarding mobs +# Normally this should be 1 to 7, a value of 8 will appear only in rare teasure chests +# modid is the official ID of the mod; for vanilla items the modid is "item" +# name is the in-code, unlocalized name +# minimum and maximum determine the stacks sizes +# +# You can now create alternate version in the SpecialChests folder and attach those to +# dungeon themes. + +gear, 1, minecraft:stone_sword, 1, 1 +gear, 1, minecraft:leather_helmet, 1, 1 +gear, 1, minecraft:leather_leggings, 1, 1 +gear, 1, minecraft:leather_boots, 1, 1 +gear, 1, minecraft:leather_chestplate, 1, 1 +gear, 1, minecraft:arrow, 4, 12 +gear, 1, minecraft:potion, 1, 1, WBREATH1 +gear, 1, minecraft:potion, 1, 1, NEYE1 + +gear, 2, minecraft:stone_sword, 1, 1 +gear, 2, minecraft:iron_sword, 1, 1 +gear, 2, minecraft:stone_pickaxe, 1, 1 +gear, 2, minecraft:stone_axe, 1, 1 +gear, 2, minecraft:bow, 1, 1 +gear, 2, minecraft:shield, 1, 1 +gear, 2, minecraft:leather_helmet, 1, 1 +gear, 2, minecraft:leather_leggings, 1, 1 +gear, 2, minecraft:leather_boots, 1, 1 +gear, 2, minecraft:leather_chestplate, 1, 1 +gear, 2, minecraft:iron_helmet, 1, 1 +gear, 2, minecraft:iron_leggings, 1, 1 +gear, 2, minecraft:iron_boots, 1, 1 +gear, 2, minecraft:iron_chestplate, 1, 1 +gear, 2, minecraft:arrow, 4, 12 +gear, 2, minecraft:potion, 1, 1, WBREATH1 +gear, 2, minecraft:potion, 1, 1, WBREATH1 +gear, 2, minecraft:potion, 1, 1, NEYE1 + +gear, 3, minecraft:iron_sword, 1, 1 +gear, 3, minecraft:iron_pickaxe, 1, 1 +gear, 3, minecraft:iron_axe, 1, 1 +gear, 3, minecraft:bow, 1, 1 +gear, 3, minecraft:shield, 1, 1 +gear, 3, minecraft:iron_helmet, 1, 1 +gear, 3, minecraft:iron_leggings, 1, 1 +gear, 3, minecraft:iron_boots, 1, 1 +gear, 3, minecraft:iron_chestplate, 1, 1 +gear, 3, minecraft:arrow, 4, 12 +gear, 3, minecraft:potion, 1, 1, WBREATH1 +gear, 3, minecraft:potion, 1, 1, NEYE1 +gear, 3, minecraft:potion, 1, 1, WBREATH2 +gear, 3, minecraft:potion, 1, 1, NEYE2 + +gear, 4, minecraft:iron_sword, 1, 1 +gear, 4, minecraft:diamond_sword, 1, 1 +gear, 4, minecraft:bow, 1, 1 +gear, 4, minecraft:shield, 1, 1 +gear, 4, minecraft:iron_helmet, 1, 1 +gear, 4, minecraft:iron_leggings, 1, 1 +gear, 4, minecraft:iron_boots, 1, 1 +gear, 4, minecraft:iron_chestplate, 1, 1 +gear, 4, minecraft:diamond_helmet, 1, 1 +gear, 4, minecraft:diamond_leggings, 1, 1 +gear, 4, minecraft:diamond_boots, 1, 1 +gear, 4, minecraft:diamond_chestplate, 1, 1 +gear, 4, minecraft:arrow, 8, 16 +gear, 4, minecraft:potion, 1, 1, WBREATH2 +gear, 4, minecraft:potion, 1, 1, WBREATH2 +gear, 4, minecraft:potion, 1, 1, NEYE2 + +gear, 5, minecraft:diamond_sword, 1, 1 +gear, 5, minecraft:diamond_pickaxe, 1, 1 +gear, 5, minecraft:diamond_axe, 1, 1 +gear, 5, minecraft:diamond_helmet, 1, 1 +gear, 5, minecraft:diamond_leggings, 1, 1 +gear, 5, minecraft:diamond_boots, 1, 1 +gear, 5, minecraft:diamond_chestplate, 1, 1 +gear, 2, minecraft:shield, 1, 1 +gear, 5, minecraft:arrow, 8, 16 +gear, 5, minecraft:potion, 1, 1, WBREATH2 +gear, 5, minecraft:potion, 1, 1, WBREATH2 +gear, 5, minecraft:potion, 1, 1, NEYE2 + +gear, 6, minecraft:diamond_sword, 1, 1 +gear, 6, minecraft:diamond_sword, 1, 1, SLSW +gear, 6, minecraft:diamond_helmet, 1, 1 +gear, 6, minecraft:diamond_leggings, 1, 1 +gear, 6, minecraft:diamond_boots, 1, 1 +gear, 6, minecraft:diamond_chestplate, 1, 1 +gear, 6, minecraft:arrow, 16, 48 +gear, 6, minecraft:potion, 1, 1, WBREATH2 +gear, 6, minecraft:potion, 1, 1, NEYE2 + +gear, 7, minecraft:diamond_sword, 1, 1 +gear, 7, minecraft:diamond_pickaxe, 1, 1 +gear, 7, minecraft:diamond_helmet, 1, 1 +gear, 7, minecraft:diamond_leggings, 1, 1 +gear, 7, minecraft:diamond_boots, 1, 1 +gear, 7, minecraft:diamond_chestplate, 1, 1 +gear, 7, minecraft:potion, 1, 1, WBREATH2 +gear, 7, minecraft:potion, 1, 1, NEYE2 + +heal, 1, minecraft:bread, 1, 2 + +heal, 2, minecraft:bread, 1, 3 +heal, 2, minecraft:apple, 1, 2 +heal, 2, minecraft:cooked_chicken, 1, 3 + +heal, 3, minecraft:bread, 2, 4 +heal, 3, minecraft:apple, 1, 2 +heal, 3, minecraft:cooked_chicken, 1, 3 +heal, 3, minecraft:cooked_beef, 1, 3 +heal, 3 minecraft:potion, 1, 1, HEALTH1 + +heal, 4, minecraft:bread, 2, 4 +heal, 4, minecraft:apple, 1, 3 +heal, 4, minecraft:apple, 1, 4 +heal, 4, minecraft:cooked_chicken, 1, 3 +heal, 4, minecraft:cooked_beef, 1, 3 +heal, 4, minecraft:golden_apple, 1, 1 +heal, 4 minecraft:potion, 1, 1, HEALTH1 +heal, 4 minecraft:potion, 1, 1,HEALTH2 +heal, 4 minecraft:potion, 1, 1, REGEN1 + +heal, 5, minecraft:bread, 2, 4 +heal, 5, minecraft:pumpkin_pie, 1, 2 +heal, 5, minecraft:apple, 2, 4 +heal, 5, minecraft:cooked_chicken, 2, 4 +heal, 5, minecraft:cooked_beef, 2 4 +heal, 5, minecraft:golden_apple, 1, 1 +heal, 5, minecraft:golden_apple, 1, 1 +heal, 5, minecraft:potion, 1, 1, HEALTH2 +heal, 5, minecraft:potion, 1, 1, REGEN1 +heal, 5, minecraft:potion, 1, 1, REGENX + +heal, 6, minecraft:pumpkin_pie, 1, 3 +heal, 6, minecraft:apple, 3, 7 +heal, 6, minecraft:cooked_beef, 4, 8 +heal, 6, minecraft:golden_apple, 1, 2 +heal, 6, minecraft:potion, 1, 1, HEALTH2 +heal, 6, minecraft:potion, 1, 1, REGEN2 +heal, 6, minecraft:potion, 1, 1, REGENX + +heal, 7, minecraft:apple, 3, 7 +heal, 7, minecraft:cooked_beef, 4, 8 +heal, 7, minecraft:pumpkin_pie, 2, 7 +heal, 7, minecraft:enchanted_golden_apple, 1, 1 +heal, 7, minecraft:golden_apple, 1, 3 +heal, 7, minecraft:potion, 1, 1, REGEN2 +heal, 7, minecraft:potion, 1, 1, REGENX + +loot, 1, minecraft:iron_ingot, 1, 8 +loot, 1, minecraft:gold_ingot, 1, 1 +loot, 1, minecraft:book, 1, 1 +loot, 1, minecraft:apple, 1, 3 +loot, 1, minecraft:torch, 4, 12 + +loot, 2, minecraft:book, 1, 1 +loot, 2, minecraft:book, 2, 5 +loot, 2, minecraft:iron_ingot, 1, 8 +loot, 2, minecraft:gold_ingot, 1, 1 +loot, 2, minecraft:gold_ingot, 2, 5 +loot, 2, minecraft:name_tag, 1, 1 + +loot, 3, minecraft:book, 2, 5 +loot, 3, minecraft:gold_ingot, 2, 5 +loot, 3, minecraft:diamond, 1, 1 +loot, 3, minecraft:iron_ingot, 3, 12 +loot, 3, minecraft:emerald, 1, 1 +loot, 3, minecraft:saddle 1, 1 +loot, 3, minecraft:name_tag, 1, 1 +loot, 3, minecraft:jukebox, 1, 1 +loot, 3, minecraft:iron_horse_armor, 1, 1 +loot, 3, minecraft:clock, 1, 1 + +loot, 4, minecraft:golden_apple, 1, 1 +loot, 4, minecraft:blaze_rod, 1, 3 +loot, 4, minecraft:book, 3, 8 +loot, 4, minecraft:ender_pearl, 1, 9 +loot, 4, minecraft:iron_ingot, 3, 12 +loot, 4, minecraft:gold_ingot, 2, 5 +loot, 4, minecraft:diamond, 1, 1 +loot, 4, minecraft:diamond, 1, 4 +loot, 4, minecraft:emerald, 1, 1 +loot, 4, minecraft:emerald, 1, 4 +loot, 4, minecraft:saddle 1, 1 +loot, 4, minecraft:name_tag, 1, 1 +loot, 4, minecraft:brewing_stand, 1, 1 +loot, 4, minecraft:golden_horse_armor, 1, 1 + +loot, 5, minecraft:book, 3, 8 +loot, 5, minecraft:blaze_rod, 1, 3 +loot, 5, minecraft:golden_apple, 1, 1 +loot, 5, minecraft:ender_eye, 1, 2 +loot, 5, minecraft:ender_pearl, 1, 9 +loot, 5, minecraft:iron_ingot, 3, 12 +loot, 5, minecraft:gold_ingot, 3, 8 +loot, 5, minecraft:diamond, 1, 4 +loot, 5, minecraft:emerald, 1, 1 +loot, 5, minecraft:emerald, 1, 8 +loot, 5, minecraft:saddle 1, 1 +loot, 5, minecraft:name_tag, 1, 2 +loot, 5, minecraft:enchanting_table, 1, 1 +loot, 5, minecraft:diamond_horse_armor, 1, 1 +loot, 5, minecraft:purple_shulker_box, 1, 1 + +loot, 6, minecraft:book, 3, 8 +loot, 6, minecraft:ender_eye, 1, 2 +loot, 6, minecraft:ender_pearl, 1, 9 +loot, 6, minecraft:golden_apple, 1, 3 +loot, 6, minecraft:iron_ingot, 3, 12 +loot, 6, minecraft:gold_ingot, 3, 8 +loot, 6, minecraft:diamond, 1, 6 +loot, 6, minecraft:emerald, 1, 12 +loot, 6, minecraft:saddle 1, 1 +loot, 6, minecraft:name_tag, 1, 3 +loot, 6, minecraft:diamond_horse_armor, 1, 1 +loot, 6, minecraft:purple_shulker_box, 1, 1 + +loot, 7, minecraft:gold_ingot, 3, 8 +loot, 7, minecraft:diamond_block, 1, 2 +loot, 7, minecraft:emerald_block, 1, 3 +loot, 7, minecraft:ender_eye, 1, 2 +loot, 7, minecraft:enchanted_golden_apple, 1, 1 +loot, 7, minecraft:saddle 1, 1 +loot, 7, minecraft:name_tag, 1, 4 +loot, 7, minecraft:totem_of_undying, 1, 1 +loot, 7, minecraft:elytra, 1, 1 +loot, 7, minecraft:wither_skeleton_skull, 1, 1 + +loot, 8, minecraft:nether_star, 1, 1 +loot, 8, minecraft:diamond_block, 1, 12 +loot, 8, minecraft:emerald_block, 1, 12 +loot, 8, minecraft:wither_skeleton_skull, 1, 8 +loot, 8, minecraft:beacon, 1, 1, +loot, 8, minecraft:diamond_pickaxe, 1, 1, VANILLAWORLD diff --git a/resources/jaredbgreat/dldungeons/res/themes/template.cfg b/resources/jaredbgreat/dldungeons/res/themes/template.cfg new file mode 100644 index 0000000..5fd0b23 --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/template.cfg @@ -0,0 +1,114 @@ +# This is the version of the mod; anything before 1.5 is considers "0" (since versioning wasn't available) +Version 1.8 +# This file is a template that will never be read. For reference it has my classic default that was first hard-code as a theme. +# To make other themes copy this into a theme with the name you want and edit it to your preference. +# +# Biome types to use this theme in +# Any forge dictionary type can be included here, though beach will be treated as water +# +# Biomes types where it should be used +biomes = FOREST, PLAINS, MOUNTAINS, HILLS, DESERT, FROZEN, JUNGLE, WASTELAND +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values include DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, TECH, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = DUNGEON + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# Special dungeon instructions; Curently this can be "WATER" (flooded / water instead of air), "SWAMPY" (pools +# less deep / high water table), or "SURFACE" (currently does nothing), HARD (better loot; for harder mobs or hazrads) +Flags = + +# Altitude ranges +# +# Lowest level a floor can be at +minY = 30 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 1, 30, 50, 20, 10, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 5, 10, 25, 20, 10, 0 +# How many entrances to place +entrances = 2, 5, 25, 50, 15, 3 +# Frequency of cave-like areas +naturals = 25, 5, 20, 5, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:stone_bricks, minecraft:cobblestone, minecraft:sandstone, minecraft:bricks +# The main block for building floors +floors = minecraft:stone_bricks, minecraft:cobblestone, minecraft:dirt, minecraft:stone +# The main block for lining ceilings +ceilings = minecraft:stone_bricks, minecraft:cobblestone, minecraft:oak_planks, minecraft:stone_slab +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:cobblestone_wall, minecraft:oak_fence +# Block to represent liquids; fill pools +liquid = minecraft:water, minecraft:lava +# Block from which to build pillars +pillarBlock = minecraft:stone_bricks, minecraft:cobblestone, minecraft:sandstone, minecraft:oak_planks, minecraft:stone_slab +# Block found in cave-like areas +caveblock = minecraft:stone + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/urban.cfg b/resources/jaredbgreat/dldungeons/res/themes/urban.cfg new file mode 100644 index 0000000..b2e6958 --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/urban.cfg @@ -0,0 +1,108 @@ +Version 1.7 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = PLAINS, DRY, SPARSE +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END, WASTELAND, MESA, SWAMP, WET + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values includ DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = URBAN, DUNGEON + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 30 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 10, 30, 50, 20, 1, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 0, 0, 0, 25, 50, 25 +# Frequency of trying to place a mini-room inside a larger room +islands = 0, 0, 0, 10, 90, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 0, 5, 15, 75, 25, 5 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 15, 25, 20, 10, 0, 0 +# How many entrances to place +entrances = 2, 5, 25, 50, 15, 3 +# Frequency of cave-like areas +naturals = 50, 0, 0, 0, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:bricks, minecraft:stone_bricks, minecraft:bricks, minecraft:sandstone, minecraft:bricks +# The main block for building floors +floors = minecraft:stone_bricks, minecraft:cobblestone, minecraft:bricks, minecraft:stone_slab +# The main block for lining ceilings +ceilings = minecraft:stone_bricks, minecraft:cobblestone, minecraft:oak_planks, minecraft:stone_slab +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:cobblestone_wall, minecraft:oak_fence +# Block to represent liquids; fill pools +liquid = minecraft:water, minecraft:lava +# Block from which to build pillars +pillarBlock = minecraft:stone_bricks, minecraft:cobblestone, minecraft:sandstone, minecraft:stone_slab +# Block found in cave-like areas +caveblock = minecraft:stone + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/villagelike.cfg b/resources/jaredbgreat/dldungeons/res/themes/villagelike.cfg new file mode 100644 index 0000000..181c4ac --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/villagelike.cfg @@ -0,0 +1,103 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = FOREST, PLAINS, SAVANNA +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END, WASTELAND, SPOOKY, DEAD + +Type = URBAN, PLAINS, FOREST + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 30 +# Highest level a floor can be at +maxY = 50 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 2, 5, 10, 5, 1 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 10, 30, 50, 20, 0, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 0, 5, 50, 50, 20, 5 +# How many pillars to use +pillars = 30, 60, 40, 20, 5, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 5, 15, 30, 75, 25, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 50, 5, 15, 50, 10, 0 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 15, 25, 20, 10, 0, 0 +# How many entrances to place +entrances = 2, 5, 25, 50, 15, 3 +# Frequency of cave-like areas +naturals = 50, 5, 0, 0, 0, 0 + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:cobblestone, minecraft:oak_planks +# The main block for building floors +floors = minecraft:cobblestone, minecraft:dirt, minecraft:cobblestone, minecraft:dirt, minecraft:oak_planks +# The main block for lining ceilings +ceilings = minecraft:oak_planks, minecraft:oak_planks, minecraft:stone_slab +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:cobblestone_wall, minecraft:oak_fence +# Block to represent liquids; fill pools +liquid = minecraft:water +# Block from which to build pillars +pillarBlock = minecraft:oak_planks, minecraft:cobblestone, minecraft:oak_log, minecraft:oak_log, minecraft:oak_log +# Block found in cave-like areas +caveblock = minecraft:stone + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:enderman, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/resources/jaredbgreat/dldungeons/res/themes/volcanic.cfg b/resources/jaredbgreat/dldungeons/res/themes/volcanic.cfg new file mode 100644 index 0000000..14b386a --- /dev/null +++ b/resources/jaredbgreat/dldungeons/res/themes/volcanic.cfg @@ -0,0 +1,111 @@ +Version 1.8 +# Biome types to use this theme in +# Valid types are = FOREST, PLAINS, MOUNTAIN, HILLS, SWAMP, WATER, DESERT, FROZEN, JUNGLE, WASTELAND, NETHER, END, MUSHROOM, and MAGICAL +# (BEACH is consider the same as WATER here.) +# +# Biomes types where it should be used +biomes = MOUNTAIN, HILLS, WASTELAND +# Biome types where it should never appear, even if the biome also fit one of the above types +NotInBiomes = NETHER, END, SWAMP, WATER, MESA + +# This determines the type of dungeon this should be, for the purpose of adding mobs through the API; +# Its basically like a biome dictionary for dungeons. Valid values includ DUNGEON, NECRO, URBAN, FOREST, +# PLAINS, MOUNTAIN, SWAMP, WATER, DESERT, WASTELAND, JUNGLE, FROZEN, FIERY, NETHER, END, MUSHROOM, MAGICAL, +# SHADOW, and PARADISE. Most should have one or two types, not more than 3 or (very rarely) 4; API user +# should be more liberal with there assigning mosters to types, not the other way around. +Type = FIERY, MOUNTAIN +# Not sure mountains should be there... +#Type = FIERY + + +# Either ALL or list of comma delimited dimension IDs +DimensionWhitelist = ALL + +# +# Altitude ranges +# +# Lowest level a floor can be at +minY = 10 +# Highest level a floor can be at +maxY = 25 + +# This is the chest file to be used; if it is chest.cfg its will be under DLDungeonsJBG, +# other chests files will be under DLDungeonsJBG/SpecialChests +ChestsFile = chests.cfg + + +# +# Size ranges = This should contain 5 numbers, at least one of which must not be 0. +# These are relative probabilities for a tiny, small, medium, large, and huge dungeon (in that oreder) +sizes = 0, 15, 30, 5, 0 + +# +# Style elements = These must each contain 6 numbers +# in order they must be for none, few, some, plenty, heaps, and always (not literally) +# They are relative probabilites, as before +# +# Roofless, wall-less rooms; mostly for surface dungeons +outside = 25, 0, 0, 0, 0, 0 +# Amount of liquid blocks (pools) on the floor +liquids = 0, 0, 5, 85, 10, 0 +# Number of extra doors which may lead to rooms off the main route +subrooms = 5, 20, 50, 45, 5, 0 +# Frequency of trying to place a mini-room inside a larger room +islands = 5, 50, 10, 50, 20, 0 +# How many pillars to use +pillars = 5, 30, 60, 40, 20, 0 +# Not used, but will be the number of fences around outdoor rooms +fences = 5, 15, 30, 75, 25, 0 +# How generally semetric and organized roosm appear +symmetry = 20, 30, 75, 25, 0, 0 +# How much variability in the blocks to be used +variability = 5, 10, 25, 75, 50, 25 +# Idea borrowed from Greymerk's Roguelike dungeons; chance of not building over airblocks +degeneracy = 0, 5, 15, 50, 50, 10 +# How many feature to add to rooms +complexity = 5, 10, 25, 75, 15, 0 +# How much variation in the Y should be found +verticle = 0, 0, 5, 55, 15, 0 +# How many entrances to place +entrances = 50, 25, 15, 5, 0, 0 +# Frequency of cave-like areas +naturals = 0, 0, 10, 25, 15, + +# +# Block elements +# Thes are just lists of blocks to uses in building rooms +# Warning = Versions for version fo Minecraft before 1.7 are not compatible with 1.7+ +# For 1.5.2 or 1.6.4 these must be block ids +# for version 1.7+ these are the proper, in-code names for the blocks +# Each of these must contain at least one block, but can contain as many as you like +# +# The main block for building walls +walls = minecraft:cobblestone, minecraft:stone, minecraft:stone, minecraft:cracked_stone_bricks +# The main block for building floors +floors = minecraft:cracked_stone_bricks, minecraft:stone, minecraft:stone, minecraft:obsidian, minecraft:dirt +# The main block for lining ceilings +ceilings = minecraft:cracked_stone_bricks, minecraft:stone +# Blocks to be used as outdoor fences (not yet used) +fencing = minecraft:cobblestone_wall +# Block to represent liquids; fill pools +liquid = minecraft:lava +# Block from which to build pillars +pillarBlock = minecraft:cracked_stone_bricks, minecraft:stone_bricks, minecraft:stone +# Block found in cave-like areas +caveblock = minecraft:stone,minecraft:stone, minecraft:stone, minecraft:obsidian + +# +# Mob fields +# +# These are lists of mobs, and most be in their officialm, in code names +# +# Weak, basic mobs; by default +commonMobs = minecraft:zombie, minecraft:skeleton, minecraft:spider +# Tougher mobs everyday mobs +hardMobs = minecraft:creeper, minecraft:blaze, minecraft:cave_spider +# Really tough mobs, Minefantasy brutes, mid-level Dungeons Mobs, and many of Lycanite's mobs go here +bruteMobs = minecraft:witch +# The baddest of the bad, Minefantasy dragon, Dungeon Mobs rakshasa, and all bosses go here; empty by default in the overworld +# but for The Nether this has Wither Boss. +eliteMobs = +bossMobs = diff --git a/src/com/gmail/nossr50/util/ItemUtils.java b/src/com/gmail/nossr50/util/ItemUtils.java new file mode 100644 index 0000000..394339b --- /dev/null +++ b/src/com/gmail/nossr50/util/ItemUtils.java @@ -0,0 +1,678 @@ +package com.gmail.nossr50.util; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.FurnaceRecipe; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.meta.ItemMeta; + +public final class ItemUtils { + private ItemUtils() {} + + /** + * Checks if the item is a bow. + * + * @param item Item to check + * @return true if the item is a bow, false otherwise + */ + public static boolean isBow(ItemStack item) { + Material type = item.getType(); + + switch (type) { + case BOW: + return true; + + default: + return false; + } + } + + public static boolean hasItemInEitherHand(Player player, Material material) { + return player.getInventory().getItemInMainHand().getType() == material || player.getInventory().getItemInOffHand().getType() == material; + } + + /** + * Checks if the item is a sword. + * + * @param item Item to check + * @return true if the item is a sword, false otherwise + */ + public static boolean isSword(ItemStack item) { + Material type = item.getType(); + + switch (type) { + case DIAMOND_SWORD: + case GOLDEN_SWORD: + case IRON_SWORD: + case STONE_SWORD: + case WOODEN_SWORD: + return true; + + default: + return false; + } + } + + /** + * Checks if the item is a hoe. + * + * @param item Item to check + * @return true if the item is a hoe, false otherwise + */ + public static boolean isHoe(ItemStack item) { + Material type = item.getType(); + + switch (type) { + case DIAMOND_HOE: + case GOLDEN_HOE: + case IRON_HOE: + case STONE_HOE: + case WOODEN_HOE: + return true; + + default: + return false; + } + } + + /** + * Checks if the item is a shovel. + * + * @param item Item to check + * @return true if the item is a shovel, false otherwise + */ + public static boolean isShovel(ItemStack item) { + Material type = item.getType(); + + switch (type) { + case DIAMOND_SHOVEL: + case GOLDEN_SHOVEL: + case IRON_SHOVEL: + case STONE_SHOVEL: + case WOODEN_SHOVEL: + return true; + + default: + return false; + } + } + + /** + * Checks if the item is an axe. + * + * @param item Item to check + * @return true if the item is an axe, false otherwise + */ + public static boolean isAxe(ItemStack item) { + Material type = item.getType(); + + switch (type) { + case DIAMOND_AXE: + case GOLDEN_AXE: + case IRON_AXE: + case STONE_AXE: + case WOODEN_AXE: + return true; + + default: + return false; + } + } + + /** + * Checks if the item is a pickaxe. + * + * @param item Item to check + * @return true if the item is a pickaxe, false otherwise + */ + public static boolean isPickaxe(ItemStack item) { + Material type = item.getType(); + + switch (type) { + case DIAMOND_PICKAXE: + case GOLDEN_PICKAXE: + case IRON_PICKAXE: + case STONE_PICKAXE: + case WOODEN_PICKAXE: + return true; + + default: + return false; + } + } + + /** + * Checks if the item counts as unarmed. + * + * @param item Item to check + * @return true if the item counts as unarmed, false otherwise + */ + public static boolean isUnarmed(ItemStack item) { + return item.getType() == Material.AIR; + } + + /** + * Checks if the item is a helmet. + * + * @param item Item to check + * @return true if the item is a helmet, false otherwise + */ + public static boolean isHelmet(ItemStack item) { + Material type = item.getType(); + + switch (type) { + case DIAMOND_HELMET: + case GOLDEN_HELMET: + case IRON_HELMET: + case CHAINMAIL_HELMET: + case LEATHER_HELMET: + return true; + + default: + return false; + } + } + + /** + * Checks if the item is a chestplate. + * + * @param item Item to check + * @return true if the item is a chestplate, false otherwise + */ + public static boolean isChestplate(ItemStack item) { + Material type = item.getType(); + + switch (type) { + case DIAMOND_CHESTPLATE: + case GOLDEN_CHESTPLATE: + case IRON_CHESTPLATE: + case CHAINMAIL_CHESTPLATE: + case LEATHER_CHESTPLATE: + return true; + + default: + return false; + } + } + + /** + * Checks if the item is a pair of pants. + * + * @param item Item to check + * @return true if the item is a pair of pants, false otherwise + */ + public static boolean isLeggings(ItemStack item) { + Material type = item.getType(); + + switch (type) { + case DIAMOND_LEGGINGS: + case GOLDEN_LEGGINGS: + case IRON_LEGGINGS: + case CHAINMAIL_LEGGINGS: + case LEATHER_LEGGINGS: + return true; + + default: + return false; + } + } + + /** + * Checks if the item is a pair of boots. + * + * @param item Item to check + * @return true if the item is a pair of boots, false otherwise + */ + public static boolean isBoots(ItemStack item) { + Material type = item.getType(); + + switch (type) { + case DIAMOND_BOOTS: + case GOLDEN_BOOTS: + case IRON_BOOTS: + case CHAINMAIL_BOOTS: + case LEATHER_BOOTS: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a wearable armor piece. + * + * @param item Item to check + * @return true if the item is armor, false otherwise + */ + public static boolean isArmor(ItemStack item) { + return isHelmet(item) || isChestplate(item) || isLeggings(item) || isBoots(item); + } + + /** + * Checks to see if an item is a wearable *vanilla* armor piece. + * + * @param item Item to check + * @return true if the item is armor, false otherwise + */ + public static boolean isMinecraftArmor(ItemStack item) { + return isLeatherArmor(item) || isGoldArmor(item) || isIronArmor(item) || isDiamondArmor(item) || isChainmailArmor(item); + } + + /** + * Checks to see if an item is a leather armor piece. + * + * @param item Item to check + * @return true if the item is leather armor, false otherwise + */ + public static boolean isLeatherArmor(ItemStack item) { + switch (item.getType()) { + case LEATHER_BOOTS: + case LEATHER_CHESTPLATE: + case LEATHER_HELMET: + case LEATHER_LEGGINGS: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a gold armor piece. + * + * @param item Item to check + * @return true if the item is gold armor, false otherwise + */ + public static boolean isGoldArmor(ItemStack item) { + switch (item.getType()) { + case GOLDEN_BOOTS: + case GOLDEN_CHESTPLATE: + case GOLDEN_HELMET: + case GOLDEN_LEGGINGS: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is an iron armor piece. + * + * @param item Item to check + * @return true if the item is iron armor, false otherwise + */ + public static boolean isIronArmor(ItemStack item) { + switch (item.getType()) { + case IRON_BOOTS: + case IRON_CHESTPLATE: + case IRON_HELMET: + case IRON_LEGGINGS: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a diamond armor piece. + * + * @param item Item to check + * @return true if the item is diamond armor, false otherwise + */ + public static boolean isDiamondArmor(ItemStack item) { + switch (item.getType()) { + case DIAMOND_BOOTS: + case DIAMOND_CHESTPLATE: + case DIAMOND_HELMET: + case DIAMOND_LEGGINGS: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a chainmail armor piece. + * + * @param item Item to check + * @return true if the item is chainmail armor, false otherwise + */ + public static boolean isChainmailArmor(ItemStack item) { + switch (item.getType()) { + case CHAINMAIL_BOOTS: + case CHAINMAIL_CHESTPLATE: + case CHAINMAIL_HELMET: + case CHAINMAIL_LEGGINGS: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a *vanilla* tool. + * + * @param item Item to check + * @return true if the item is a tool, false otherwise + */ + public static boolean isMinecraftTool(ItemStack item) { + return isStoneTool(item) || isWoodTool(item) || isGoldTool(item) || isIronTool(item) || isDiamondTool(item) || isStringTool(item) || item.getType() == Material.TRIDENT; + } + + /** + * Checks to see if an item is a stone tool. + * + * @param item Item to check + * @return true if the item is a stone tool, false otherwise + */ + public static boolean isStoneTool(ItemStack item) { + switch (item.getType()) { + case STONE_AXE: + case STONE_HOE: + case STONE_PICKAXE: + case STONE_SHOVEL: + case STONE_SWORD: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a wooden tool. + * + * @param item Item to check + * @return true if the item is a wooden tool, false otherwise + */ + public static boolean isWoodTool(ItemStack item) { + switch (item.getType()) { + case WOODEN_AXE: + case WOODEN_HOE: + case WOODEN_PICKAXE: + case WOODEN_SHOVEL: + case WOODEN_SWORD: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a string tool. + * + * @param item Item to check + * @return true if the item is a string tool, false otherwise + */ + public static boolean isStringTool(ItemStack item) { + switch (item.getType()) { + case BOW: + case CARROT_ON_A_STICK: + case FISHING_ROD: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a gold tool. + * + * @param item Item to check + * @return true if the item is a stone tool, false otherwise + */ + public static boolean isGoldTool(ItemStack item) { + switch (item.getType()) { + case GOLDEN_AXE: + case GOLDEN_HOE: + case GOLDEN_PICKAXE: + case GOLDEN_SHOVEL: + case GOLDEN_SWORD: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is an iron tool. + * + * @param item Item to check + * @return true if the item is an iron tool, false otherwise + */ + public static boolean isIronTool(ItemStack item) { + switch (item.getType()) { + case BUCKET: + case FLINT_AND_STEEL: + case IRON_AXE: + case IRON_HOE: + case IRON_PICKAXE: + case IRON_SHOVEL: + case IRON_SWORD: + case SHEARS: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a diamond tool. + * + * @param item Item to check + * @return true if the item is a diamond tool, false otherwise + */ + public static boolean isDiamondTool(ItemStack item) { + switch (item.getType()) { + case DIAMOND_AXE: + case DIAMOND_HOE: + case DIAMOND_PICKAXE: + case DIAMOND_SHOVEL: + case DIAMOND_SWORD: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is enchantable. + * + * @param item Item to check + * @return true if the item is enchantable, false otherwise + */ + public static boolean isEnchantable(ItemStack item) { + switch (item.getType()) { + case ENCHANTED_BOOK: + case SHEARS: + case FISHING_ROD: + case CARROT_ON_A_STICK: + case FLINT_AND_STEEL: + case TRIDENT: + return true; + + default: + return isArmor(item) || isSword(item) || isAxe(item) || isShovel(item) || isPickaxe(item) || isBow(item); + } + } + + /** + * Checks to see if an item is a mining drop. + * + * @param item Item to check + * @return true if the item is a mining drop, false otherwise + */ + public static boolean isMiningDrop(ItemStack item) { + //TODO: 1.14 This needs to be updated + switch (item.getType()) { + case COAL: + case COAL_ORE: + case DIAMOND: + case DIAMOND_ORE: + case EMERALD: + case EMERALD_ORE: + case GOLD_ORE: + case IRON_ORE: + case LAPIS_ORE: + case REDSTONE_ORE: // Should we also have Glowing Redstone Ore here? + case REDSTONE: + case GLOWSTONE_DUST: // Should we also have Glowstone here? + case QUARTZ: + case NETHER_QUARTZ_ORE: + case LAPIS_LAZULI: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a herbalism drop. + * + * @param item Item to check + * @return true if the item is a herbalism drop, false otherwise + */ + public static boolean isHerbalismDrop(ItemStack item) { + //TODO: 1.14 This needs to be updated + switch (item.getType()) { + case WHEAT: + case WHEAT_SEEDS: + case CARROT: + case CHORUS_FRUIT: + case CHORUS_FLOWER: + case POTATO: + case BEETROOT: + case BEETROOT_SEEDS: + case NETHER_WART: + case BROWN_MUSHROOM: + case RED_MUSHROOM: + case ROSE_BUSH: + case DANDELION: + case CACTUS: + case SUGAR_CANE: + case MELON: + case MELON_SEEDS: + case PUMPKIN: + case PUMPKIN_SEEDS: + case LILY_PAD: + case VINE: + case TALL_GRASS: + case COCOA_BEANS: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a mob drop. + * + * @param item Item to check + * @return true if the item is a mob drop, false otherwise + */ + public static boolean isMobDrop(ItemStack item) { + //TODO: 1.14 This needs to be updated + switch (item.getType()) { + case STRING: + case FEATHER: + case CHICKEN: + case COOKED_CHICKEN: + case LEATHER: + case BEEF: + case COOKED_BEEF: + case PORKCHOP: + case COOKED_PORKCHOP: + case WHITE_WOOL: + case BLACK_WOOL: + case BLUE_WOOL: + case BROWN_WOOL: + case CYAN_WOOL: + case GRAY_WOOL: + case GREEN_WOOL: + case LIGHT_BLUE_WOOL: + case LIGHT_GRAY_WOOL: + case LIME_WOOL: + case MAGENTA_WOOL: + case ORANGE_WOOL: + case PINK_WOOL: + case PURPLE_WOOL: + case RED_WOOL: + case YELLOW_WOOL: + case IRON_INGOT: + case SNOWBALL: + case BLAZE_ROD: + case SPIDER_EYE: + case GUNPOWDER: + case ENDER_PEARL: + case GHAST_TEAR: + case MAGMA_CREAM: + case BONE: + case ARROW: + case SLIME_BALL: + case NETHER_STAR: + case ROTTEN_FLESH: + case GOLD_NUGGET: + case EGG: + case ROSE_BUSH: + case COAL: + return true; + + default: + return false; + } + } + + /** + * Checks to see if an item is a woodcutting drop. + * + * @param item Item to check + * @return true if the item is a woodcutting drop, false otherwise + */ + public static boolean isWoodcuttingDrop(ItemStack item) { + switch (item.getType()) { + case ACACIA_LOG: + case BIRCH_LOG: + case DARK_OAK_LOG: + case JUNGLE_LOG: + case OAK_LOG: + case SPRUCE_LOG: + case STRIPPED_ACACIA_LOG: + case STRIPPED_BIRCH_LOG: + case STRIPPED_DARK_OAK_LOG: + case STRIPPED_JUNGLE_LOG: + case STRIPPED_OAK_LOG: + case STRIPPED_SPRUCE_LOG: + case ACACIA_SAPLING: + case SPRUCE_SAPLING: + case BIRCH_SAPLING: + case DARK_OAK_SAPLING: + case JUNGLE_SAPLING: + case OAK_SAPLING: + case ACACIA_LEAVES: + case BIRCH_LEAVES: + case DARK_OAK_LEAVES: + case JUNGLE_LEAVES: + case OAK_LEAVES: + case SPRUCE_LEAVES: + case APPLE: + return true; + + default: + return false; + } + } +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/ConfigHandler.java b/src/jaredbgreat/dldungeons/ConfigHandler.java new file mode 100644 index 0000000..db848ea --- /dev/null +++ b/src/jaredbgreat/dldungeons/ConfigHandler.java @@ -0,0 +1,554 @@ +package jaredbgreat.dldungeons; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.builder.Builder; +import jaredbgreat.dldungeons.pieces.chests.BasicChest; +import jaredbgreat.dldungeons.pieces.chests.TreasureChest; +import jaredbgreat.dldungeons.planner.mapping.MapMatrix; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.setup.Externalizer; +import jaredbgreat.dldungeons.themes.ThemeReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import me.zhehe.BiomeDictionary.Type; +import me.zhehe.Configuration; +import me.zhehe.Logging; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; + +//import net.minecraft.block.Block; +//import net.minecraft.entity.EntityList; +//import net.minecraft.item.Item; +//import net.minecraft.util.ResourceLocation; +//import net.minecraftforge.common.BiomeDictionary.Type; +//import net.minecraftforge.common.config.Configuration; + + +/** + * This class reads and holds data from the main configuration file. + * + * It might have been better to store many of these with the class they + * directly influence, but this is not likely to be changed as the current + * system is already in place the rest of the code base is already mature. + * + * In addition to reading and holding config data, this class also contains + * utility methods output information that can be useful in setting up + * configurations and writing theme files. + */ +public final class ConfigHandler { + +// private static File mainConfig; + private static File themesDir; + private static File listsDir; + public static File configDir; + + private static final int DEFAULT_SCALE = 8; + private static final int DEFAULT_MINXZ = 16; + private static final int DEFAULT_DIF = 3; + + private static final int[] DEFAULT_DIMS = {0, -1}; + + private static final boolean DEFAULT_WRITE_LISTS = false; + private static final boolean DEFAULT_NATURAL_SPAWN = true; + private static final boolean DEFAULT_OBEY_RULE = true; + private static final boolean DEFAULT_POSITIVE_DIMS = true; + private static final boolean DEFAULT_ANNOUNCE_COMMANDS = true; + private static final boolean DEFAULT_THIN_SPAWNERS = true; + + // Vanilla loot will not be added in version of Mincraft 1.9+ + // Instead all dungeons will have some loot enchanted. + private static final boolean DEFAULT_VANILLA_LOOT = false; + private static final boolean EASY_FIND = true; + private static final boolean SINGLE_ENTRANCE = true; + + private static final boolean DISABLE_API = false; + private static final boolean NO_MOB_CHANGES = false; + + public static boolean disableAPI = DISABLE_API; + public static boolean noMobChanges = NO_MOB_CHANGES; + + private static final String[] NEVER_IN_BIOMES = new String[]{"END"}; + private static String[] neverInBiomes = NEVER_IN_BIOMES; + public static HashSet biomeExclusions = new HashSet<>(); + + protected static boolean writeLists = DEFAULT_WRITE_LISTS; + protected static boolean naturalSpawn = DEFAULT_NATURAL_SPAWN; + protected static boolean obeyRule = DEFAULT_OBEY_RULE; + protected static boolean positiveDims = DEFAULT_POSITIVE_DIMS; + + public static boolean easyFind = EASY_FIND; + public static boolean singleEntrance = SINGLE_ENTRANCE; + + public static boolean announceCommands = DEFAULT_ANNOUNCE_COMMANDS; + public static boolean vanillaLoot = DEFAULT_VANILLA_LOOT; + public static boolean thinSpawners = DEFAULT_THIN_SPAWNERS; + + private static final boolean PROFILE = false; + protected static boolean profile; + + private static final boolean FAILFAST = false; + public static boolean failfast = FAILFAST; + + private static final boolean INSTALL_THEMES = true; + public static boolean installThemes = INSTALL_THEMES; + + private static final boolean INSTALL_CMD = true; + public static boolean installCmd = INSTALL_CMD; + + public static Difficulty difficulty; + + // All methods and data are static. + // There is no reason this should ever be instantiated. + private ConfigHandler(){/*Do nothing*/} + + + /** + * This will read the them file and apply the themes. + */ + public static void init() { + File file = new File(ConfigHandler.configDir.toString() + + File.separator + Info.OLD_ID + ".cfg"); + Configuration config = new Configuration(file); + config.load(); + + // General configuration + config.addCustomCategoryComment("General", "Main config settings"); + int freqScale = config.get("General", "FrequencyScale", DEFAULT_SCALE, + "Determines the average distance between dungeons (+2 is twice as far appart)").getInt(); + if((freqScale > 30) || (freqScale < 4)) freqScale = DEFAULT_SCALE; + GenerationHandler.setFrequency(freqScale); + Logging.logInfo("Frequency Scaling Factor Set To: " + freqScale); + + int minXZ = config.get("General", "MinChunkXY", DEFAULT_MINXZ, + "Spawn protection: this is the minimum number of chunks from spawn before dungeon generate") + .getInt(); + if(minXZ < 0) minXZ = DEFAULT_MINXZ; + GenerationHandler.setMinXZ(minXZ); + Logging.logInfo("Minimum X Factor Set To: " + minXZ); + + int diff = config.get("General", "Difficulty", DEFAULT_DIF, + "How hard: 0 = empty, 1 = baby, 2 = easy, 3 = normal, 4= hard, 5 = nightmare") + .getInt(); + if((diff < 0) || (diff > 5)) diff = DEFAULT_DIF; + parseDiff(diff); + Logging.logInfo("Difficulty set to: " + difficulty.label); + + int[] dims = config.get("General", "Dimensions", DEFAULT_DIMS, + "These dimensions either lack dungeons or only they have them " + + "(see OnlySpawnInListedDimensions)") + .getIntList(); + GenerationHandler.setDimensions(dims); + System.out.print("Dimensions listed in config file: "); + for(int i = 0; i < dims.length; i++) System.out.print(dims[i] + ", "); + System.out.println(); + + naturalSpawn = config.get("General", "SpawnWithWordgen", DEFAULT_NATURAL_SPAWN, + "True to have dungeons generate naturally, false otherwise.").getBoolean(true); + Logging.logInfo("Will spawn dungeons in with world generation? " + naturalSpawn); + + obeyRule = config.get("General", "ObeyFeatureSpawningRule", DEFAULT_OBEY_RULE, + "If true worlds that are set to not generate (vanilla) structures " + + "will also not have these dungesons") + .getBoolean(true); + Logging.logInfo("Will spawn dungeons even with structures disabled? " + !obeyRule); + + positiveDims = config.get("General", "OnlySpawnInListedDims", DEFAULT_POSITIVE_DIMS, + "Determines if the dimesions list is black list of white list; " + + System.lineSeparator() + "if true only listed dimensions have dungeons, " + + System.lineSeparator() + "otherswise all but those will have them").getBoolean(true); + if(positiveDims) System.out.print("Will only spawn in these dimensions: "); + else System.out.print("Will never spawn in these dimensions: "); + for(int i = 0; i < dims.length; i++) System.out.print(dims[i] + ", "); + System.out.println(); + + writeLists = config.get("General", "ExportLists", DEFAULT_WRITE_LISTS, + "If true a \"lists\" folder will be created and files showing names and ideas for all " + + System.lineSeparator() + "mobs / items / blocks will be made. This is good for editing " + + System.lineSeparator() + "themes.").getBoolean(DEFAULT_WRITE_LISTS); + Logging.logInfo("Will export item, block, and mob lists? " + writeLists); + + announceCommands = config.get("General", "AnnounceCommands", DEFAULT_ANNOUNCE_COMMANDS, + "If true, console commands from the mod will be annouced in chat") + .getBoolean(DEFAULT_ANNOUNCE_COMMANDS); + Logging.logInfo("Will announce use of OP/cheat commands? " + announceCommands); + + easyFind = config.get("General", "EasyFind", EASY_FIND, + "If true dungeons will all have an entrance with a room or ruin, unless the theme " + + System.lineSeparator() + "is one that never has entrances.").getBoolean(EASY_FIND); + Logging.logInfo("Will dungeons be easy to find? " + easyFind); + + singleEntrance = config.get("General", "SingleEntrances", SINGLE_ENTRANCE, + "If true all dungeons will exactly one entrance (if the theme allows entrances), " + + System.lineSeparator() + + "like a typical dungeon crawler (Dungeons will be harder but much no more, no less, " + + System.lineSeparator() + + "better loot.) If false entrance are random (how the mod originally worked). ") + .getBoolean(SINGLE_ENTRANCE); + Logging.logInfo("Will dungeon all have single entrances? " + singleEntrance); + + installThemes = config.get("General", "InstallThemes", INSTALL_THEMES, + "If true themes will automaticall be (re)installed if the themes folder is empty.") + .getBoolean(INSTALL_THEMES); + Logging.logInfo("Will themes be automatically install if themes folder is empty? " + + installThemes); + + installCmd = config.get("General", "InstallThemesByCommand", INSTALL_CMD, + "If true themes can be (re)installed by the console commands \"\\dldInstallThemes\" " + + System.lineSeparator() + "and \"\\dldForceInstallThemes.\"").getBoolean(INSTALL_CMD); + Logging.logInfo("Can themes be (re)installed by command? " + installCmd); + + thinSpawners = config.get("General", "ThinSpawners", DEFAULT_THIN_SPAWNERS, + "If true smaller dungeons will have some of there spawners removed to " + + "make them more like larger dungeons.") + .getBoolean(DEFAULT_THIN_SPAWNERS); + + neverInBiomes = config.get("General", "NeverInBiomeTypes", NEVER_IN_BIOMES, + "Dungeons will not generate in these biome types (uses Forge biome dictionary") + .getStringList(); + processBiomeExclusions(neverInBiomes); + + + // API Stuff + config.addCustomCategoryComment("API", "Turns some API calls on or off"); + disableAPI = config.get("API", "DisableApiCalls", DISABLE_API, + "If true the API is disabled") + .getBoolean(DISABLE_API); + Logging.logInfo("Will use API? " + !disableAPI); + + noMobChanges = config.get("API", "DontAllowApiOnMobs", NO_MOB_CHANGES, + "If false other mods that use the API can add mobs to the dungeons, if true they cannot. " + + System.lineSeparator() + "(This is good if hand designing custom themes for a mod pack.)") + .getBoolean(NO_MOB_CHANGES); + Logging.logInfo("Will allow API base mob change? " + !noMobChanges); + + + // Debugging + + config.addCustomCategoryComment("Debugging", + "Things for debugging the mod; you should probably leave these all off, " + + System.lineSeparator() + + "some are cheats, so cause lots of lag."); + Builder.setDebugPole(config.get("Debugging", "BuildPole", false, + "CHEAT: If true all dungeons will have a giant quarts pole through the middle and be " + + System.lineSeparator() + "surrounded by a boarder of floating llapis, This is to make " + + System.lineSeparator() + "them easy to find when testing.") + .getBoolean(false)); + + MapMatrix.setDrawFlyingMap(config.get("Debugging", "BuildFlyingMap", false, + "CHEAT: If true the layout of the dungeon will be built from floating glowstone (etc.) " + + System.lineSeparator() + "-- on some versions it also causes *EXTREME LAG*!") + .getBoolean(false)); + + failfast = config.get("Debugging", "FailfastLoot", false, + "If true this will cause the system to crash on loot config errors." + + System.lineSeparator() + "This is good for debugging modpac.") + .getBoolean(false); + + profile = config.get("Debugging", "AutoProfilingOn", PROFILE, + "If true reports on dungeon planning and build times will be exproted to files and the commandline") + .getBoolean(PROFILE); + Logging.logInfo("Will self-profile? " + profile); + + //Loot + int a, b, c; + config.addCustomCategoryComment("Loot", + "This will change the value and quantity of loo; be careful, too " + + System.lineSeparator() + + "could cause a crash if there isn't enough room in the chest. " + + System.lineSeparator() + + "The basic chest formula is for the whole cheset, the treasure " + + System.lineSeparator() + + "chest formula is per loot normal category -- you get 3 time that " + + System.lineSeparator() + + "many items."); + a = config.getInt("A1", "Loot", 3, 0, 9, + "Part of the loot quantity numbers for basic chests; " + + System.lineSeparator() + + " random.nextInt(A1 + (RoomDifficulty / B1)) + C1"); + b = config.getInt("B1", "Loot", 1, 0, 9, + "Part of the loot quantity numbers for basic chests; " + + System.lineSeparator() + + " random.nextInt(A1 + (RoomDifficulty / B1)) + C1"); + c = config.getInt("C1", "Loot", 3, 0, 9, + "Part of the loot quantity numbers for basic chests; " + + System.lineSeparator() + + " random.nextInt(A1 + (RoomDifficulty / B1)) + C1"); + BasicChest.setBasicLootNumbers(a, b, c); + a = config.getInt("A2", "Loot", 2, 0, 9, + "Part of the loot quantity numbers for treasure chests; " + + System.lineSeparator() + + " random.nextInt(A2 + (RoomDifficulty / B2)) + C2"); + b = config.getInt("B2", "Loot", 3, 0, 9, + "Part of the loot quantity numbers for treasure chests; " + + System.lineSeparator() + + " random.nextInt(A2 + (RoomDifficulty / B2)) + C2"); + c = config.getInt("C2", "Loot", 2, 0, 9, + "Part of the loot quantity numbers for treasure chests; " + + System.lineSeparator() + + " random.nextInt(A2 + (RoomDifficulty / B2)) + C2"); + TreasureChest.setBasicLootNumbers(a, b, c); + Room.setLootBonus(config.getInt("Loot Bonus", "Loot", 1, -9, 9, + "This modifies the value of the loot, in case you think default is " + + System.lineSeparator() + "too generous or too stingy.")); + + // Saving it all + openThemesDir(); + config.save(); + } + + + /** + * This will reload the config data; really just + * wraps init. + */ + public static void reload() { + init(); + } + + + /** + * This will output lists of blocks, items, and mobs know to the + * game with their proper, unlocalized names. This data is useful + * in editing theme files. + */ + public static void generateLists() { + if(!writeLists) return; + listsDir = new File(configDir.toString() + File.separator + "lists"); + + if(!listsDir.exists()) { + listsDir.mkdir(); + } + if(!listsDir.exists()) { + Logging.logInfo("Warning: Could not create " + listsDir + "."); + } else if (!listsDir.isDirectory()) { + Logging.logInfo("Warning: " + listsDir + + " is not a directory (folder); no themes loaded."); + } else { + listMobs(); + listItems(); + listBlocks(); + } + } + + + /** + * This will list all mobs, using there unlocalized names, writing + * the data to the file lists/mobs.txt. + */ + public static void listMobs() { + ArrayList mobs = new ArrayList(); + for(EntityType mob : EntityType.values()) { + mobs.add(mob.toString()); + } + Collections.sort(mobs); + + BufferedWriter outstream = null; + File moblist = new File(listsDir.toString() + File.separator + "entities.txt"); + if(moblist.exists()) moblist.delete(); + try { + outstream = new BufferedWriter(new + FileWriter(moblist.toString())); + + for(String mob : mobs){ + outstream.write(mob.toString()); + outstream.newLine(); + } + + if(outstream != null) outstream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + /** + * This will list all items, using their complete unlocalized names + * with mod id's, and write them the file lists/items.txt. This + * is useful for writing theme files. + */ + public static void listItems() { + BufferedWriter outstream = null; + File itemlist = new File(listsDir.toString() + File.separator + "items.txt"); + if(itemlist.exists()) itemlist.delete(); + try { + outstream = new BufferedWriter(new + FileWriter(itemlist.toString())); + + for(Material item : Material.values()){ + if(!item.isItem()) continue; + String name = item.toString(); + if(true) { + outstream.write(name); + outstream.newLine(); + } + } + + if(outstream != null) outstream.close(); + } catch (IOException e) { + System.err.println("Error: Could not write file items.txt"); + e.printStackTrace(); + } + } + + + /** + * This will list all blocks using their correct, unlocalized names, complete with + * mod id's, and write them to the file lists/blocks.txt. This is useful for editing + * theme files. + */ + public static void listBlocks() { + BufferedWriter outstream = null; + File itemlist = new File(listsDir.toString() + File.separator + "blocks.txt"); + if(itemlist.exists()) itemlist.delete(); + try { + outstream = new BufferedWriter(new + FileWriter(itemlist.toString())); + + for(Material block : Material.values()){ + String name = block.toString(); + if(true) {; + outstream.write(name); + outstream.newLine(); + } + } + + if(outstream != null) outstream.close(); + } catch (IOException e) { + System.err.println("Error: Could not write file blocks.txt"); + e.printStackTrace(); + } + } + + + /** + * This will open the theme's directory for some general housekeeping + * purposes. I does not read the theme files, as this called by init + * during pre-init phase of mod loading, while themes are loaded + * post-init to allow other mods a chance to load and register their + * content. + */ + private static void openThemesDir() { + Externalizer exporter; + String themesDirName = configDir.toString() + File.separator + + "themes" + File.separator; + Logging.logInfo("themesdir will be set to " + themesDirName); + themesDir = new File(themesDirName); + Logging.logInfo("themesdir File is be set to " + themesDir); + if(!themesDir.exists()) { + themesDir.mkdir(); + } + if(!themesDir.exists()) { + Logging.logInfo("Warning: Could not create " + themesDirName + "."); + } else if (!themesDir.isDirectory()) { + Logging.logInfo("Warning: " + themesDirName + + " is not a directory (folder); no themes loaded."); + } else ThemeReader.setThemesDir(themesDir); + File chestDir = new File(configDir.toString() + File.separator + ThemeReader.chestDirName); + if(!chestDir.exists()) { + chestDir.mkdir(); + } + exporter = new Externalizer(configDir.toString() + File.separator); + exporter.makeChestCfg(); + } + + + /** + * This convert difficulty setting from an integer to a + * Difficulty enum constant. + * + * @param diff + */ + protected static void parseDiff(int diff) { + switch(diff) { + case 0: + difficulty = Difficulty.NONE; + break; + case 1: + difficulty = Difficulty.BABY; + break; + case 2: + difficulty = Difficulty.NOOB; + break; + case 4: + difficulty = Difficulty.HARD; + break; + case 5: + difficulty = Difficulty.NUTS; + break; + case 3: + default: + difficulty = Difficulty.NORM; + + break; + } + } + + + /** + * This looks for the mods config directory, and attempts to + * create it if it does not exist. It will them set this as + * the config directory and return it as a File. + * + * @param fd + * @return the config directory / folder + */ +// public static File findConfigDir(File fd) { +// File out = new File(fd.toString() + File.separator + Info.OLD_ID); +// if(!out.exists()) out.mkdir(); +// +// if(!out.exists()) { +// System.err.println("ERROR: Could not create config directory"); +// } else if(!out.isDirectory()) { +// System.err.println("ERROR: Config directory is not a directory!"); +// } else { +// configDir = out; +// ThemeReader.setConfigDir(out); +// } +// return out; +// } + + + /** + * This will put biome types in the string array into the list of + * types where no dungeons show everr generate. + * + * @param array + */ + private static void processBiomeExclusions(String[] array) { + for(String str : array) { + str = str.toUpperCase(); + Logging.logInfo("adding " + str + " to excusion list"); + try { + Type value = Type.getType(str); + if(value != null) { + biomeExclusions.add(value); + } + } catch(Exception e) { + System.err.println("Error in config! " + str + " is not valid biome dictionary type!"); + e.printStackTrace(); + } + } + } + + + /** + * Returns the full path of the config directory as a String. + * + * @return + */ + public static String getConfigDir() { + return configDir + File.separator; + } +} diff --git a/src/jaredbgreat/dldungeons/Difficulty.java b/src/jaredbgreat/dldungeons/Difficulty.java new file mode 100644 index 0000000..ea6cc19 --- /dev/null +++ b/src/jaredbgreat/dldungeons/Difficulty.java @@ -0,0 +1,132 @@ +package jaredbgreat.dldungeons; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import java.util.Random; + +/** + * An enumeration of difficulty setting for the mod. + * + * This includes all the variable that effect dungeon + * generation on the basis of difficulty. Basically + * that means how many mobs spawners to add and how + * hard the mobs will be. + * + * Note that difficulty is partially depending on themes, + * as without some harder modded mobs there is not enough + * difficulty range in the mobs to fully realize the harder + * difficulties. + * + * @author Jared Blackburn + * + */ +public enum Difficulty { + + NONE (0, 0, 0, 0, 0, -1, false, "No spawners."), + BABY (3, 0, 0, 0, 0, 884, false, "Baby mode."), + NOOB (4, 1, 1, 1, 1, 590, false, "Not too hard."), + NORM (5, 2, 1, 1, 2, 427, false, "Normal difficulty."), + HARD (6, 3, 2, 2, 3, 323, true, "Super violent."), + NUTS (7, 5, 2, 2, 4, 100, true, "Insane horror!"); + + + public final int spawners; + public final int promote; + public final int maxlev; + public final int nodelev; + public final int bosslev; + public final int blocksPerSpawner; + public final boolean entrancemobs; + public final String label; + + + private Difficulty(int spawners, int promote, int mobmax, int nodelev, + int bosslev, int blocksPerSpawner, boolean entrancemobs, + String label) { + this.spawners = spawners; + this.promote = promote; + this.maxlev = mobmax; + this.nodelev = nodelev; + this.bosslev = bosslev; + this.blocksPerSpawner = blocksPerSpawner; + this.entrancemobs = entrancemobs; + this.label = label; + } + + + /** + * Should a rooms have (a) spawner(s). + * + * @param random + * @return + */ + public boolean addmob(Random random) { + return(random.nextInt(10) < spawners); + } + + + /** + * Should a room with spawners have more than + * one? + * + * @param random + * @return + */ + public boolean multimob(Random random) { + return(random.nextInt(20) < (spawners + promote)); + } + + + /** + * Should a the difficulty of a mob be increased to a + * higher level? + * + * @param random + * @return + */ + private boolean promote(Random random) { + return(random.nextInt(10) < promote); + } + + + /** + * What level mob should be placed in the spawner. + * + * @param random + * @return + */ + public int moblevel(Random random) { + int lev = 0; + boolean pr = true; + while(pr && (lev < maxlev)) { + if(random.nextInt(10) < promote) { + lev++; + } else pr = false; + } + return lev; + } + + + /** + * What monster level to place the central extra spawner + * below the treasure chest in destination (aka, "boss") + * rooms. + * + * @param random + * @return + */ + public int nodelevel(Random random) { + int lev = nodelev; + boolean pr = true; + while(pr && (lev < bosslev)) { + if(random.nextInt(10) < promote) { + lev++; + } else pr = false; + } + return lev; + } +} + diff --git a/src/jaredbgreat/dldungeons/GenerationHandler.java b/src/jaredbgreat/dldungeons/GenerationHandler.java new file mode 100644 index 0000000..fb7ece0 --- /dev/null +++ b/src/jaredbgreat/dldungeons/GenerationHandler.java @@ -0,0 +1,162 @@ +package jaredbgreat.dldungeons; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import static jaredbgreat.dldungeons.builder.Builder.placeDungeon; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import me.zhehe.BiomeDictionary; +import me.zhehe.BiomeDictionary.Type; +import org.bukkit.World; + +//import net.minecraft.util.math.BlockPos; +//import net.minecraft.world.World; +//import net.minecraft.world.chunk.IChunkProvider; +//import net.minecraft.world.gen.IChunkGenerator; +//import net.minecraftforge.common.BiomeDictionary; +//import net.minecraftforge.common.BiomeDictionary.Type; +//import net.minecraftforge.fml.common.IWorldGenerator; +//import net.minecraftforge.fml.common.registry.GameRegistry; + +/** + * The class responcible for determine where dungeons generate. More + * specifically, it wil(IWorldGenerator) l determine if a chunk being generated should be + * the technical (not geometric) center of a dungeon. + * + * @author Jared Blackburn + * + */ +public class GenerationHandler { + private static int frequency; + private static int factor = 6; + private static int minXZ; + private static Random mrand; + private static HashSet dimensions; + + +// public GenerationHandler() { +// GameRegistry.registerWorldGenerator(this, 100); +// } + + + /** + * Called when a new chunk generates to determine if a dungeon should be + * built centered on that chunk. + * + * First it will make sure dungeons are aloud, including all config setting + * and world setting as well as the dimension and biome of the chunk. + * + * If dungeons are allowed here then it will check if the chunk is the one + * in its area to have a dungeon. To do this the map is logically divided + * into square areas the size of which depend on the frequency scale. One + * chunk in each area is the technical center around with a dungeon will + * generate. The chunk coordinates are divided by the area's width using + * integer division to round so that all chunks in the same area are given + * the same two numbers. These numbers are then used to create a random + * seeds from which coordinates from 0 to the area width are generated. If + * the coords match the remainder of chunk coordinate divided by the width + * of the area this chunk will have a dungeon; since all chunks in the area + * will use the same random seed and thus have the same number one and only + * one of them will have a dungeon (assuming dungeons are allowed in the + * worlds and in that chunk). + * + * This allows dungeons to be placed randomly while ensuring a more consistent + * distribution than simply giving each a random probability to have one. + */ + public void generate(Random random, int chunkX, int chunkZ, World world) { + // Prevent bad spawns + boolean blockedBiome = false; + Set types = BiomeDictionary.getTypes(world.getBiome(chunkX * 16, chunkZ * 16)); + for(Type type : types) { + blockedBiome = ConfigHandler.biomeExclusions.contains(type) || blockedBiome; + } + if(blockedBiome) return; + if((Math.abs(chunkX - (world.getSpawnLocation().getX() / 16)) < minXZ) + || (Math.abs(chunkZ - (world.getSpawnLocation().getZ() / 16)) < minXZ)) return; + + mrand = new Random(world.getSeed() + + (2027 * (long)(chunkX / factor)) + + (1987 * (long)(chunkZ / factor))); + int xrand = mrand.nextInt(); + int zrand = mrand.nextInt(); + int xuse = ((chunkX + xrand) % factor); + int zuse = ((chunkZ + zrand) % factor); + + if((xuse == 0) && (zuse == 0)) { + try { + placeDungeon(random, chunkX, chunkZ, world); + } catch (Throwable e) { + System.err.println("[DLDUNGEONS] Danger! Failed to finalize a dungeon after building!"); + e.printStackTrace(); + } + } + } + + + /** + * Sets the frequency scale and converts into the + * width (and height) of the areas for which dungeons + * are generated. + * + * @param freqScale + */ + public static void setFrequency(int freqScale) { + if((freqScale % 2) == 0) factor = 2; + else factor = 3; + System.out.println("freqScale = " + freqScale); + factor = (1 << (freqScale / 2)) * factor; + System.out.println("factor = " + factor); + } + + + /** + * Sets the minimum number of chunks from spawn a dungeon center must be. + * + * @param value + */ + public static void setMinXZ(int value) { + minXZ = value; + } + + + /** + * Sets list of dimension id's to check for dungeons being allowed. + * + * @param value + */ + public static void setDimensions(int[] value) { + dimensions = new HashSet(); + for(int i = 0; i < value.length; i++) { + dimensions.add(Integer.valueOf(value[i])); + } + } + + + /** + * Add a dimension id to the list of dimension to consider when + * check if a dungeon is allowed. (What this means can vary.) + * + * @param value + */ + public static void addDimension(int value) { + dimensions.add(Integer.valueOf(value)); + } + + + /** + * Remove a dimension id from the list of those to consider when potentially + * placing a dungeons. (What this means can vary.) + * + * @param value + */ + public static void subDimension(int value) { + dimensions.remove(Integer.valueOf(value)); + } +} diff --git a/src/jaredbgreat/dldungeons/Info.java b/src/jaredbgreat/dldungeons/Info.java new file mode 100644 index 0000000..d1ba25f --- /dev/null +++ b/src/jaredbgreat/dldungeons/Info.java @@ -0,0 +1,20 @@ +package jaredbgreat.dldungeons; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +public final class Info { + + public static final String OLD_ID = "DLDungeonsJBG"; + public static final String ID = "dldungeonsjbg"; + public static final String NAME = "Doomlike Dungeons"; + public static final String VERSION = "1.12.10"; + public static final String MINECRAFT = "1.12.2"; + public static final String CHANNEL = "JBGDungeons"; + public static final String LOG_NAME = "DLDUNGEONS"; + +} diff --git a/src/jaredbgreat/dldungeons/ReadAPI.java b/src/jaredbgreat/dldungeons/ReadAPI.java new file mode 100644 index 0000000..70671e6 --- /dev/null +++ b/src/jaredbgreat/dldungeons/ReadAPI.java @@ -0,0 +1,181 @@ +package jaredbgreat.dldungeons; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import static jaredbgreat.dldungeons.builder.Builder.placeDungeon; +import jaredbgreat.dldungeons.themes.ThemeReader; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Random; +import org.bukkit.World; + +//import net.minecraft.world.World; + +public class ReadAPI { + + /** + * This will spawn a dungeon at the given chunk coordinates. The dungeon will not use the world seed; + * this is the same as using the /dldspawn command. + */ + public static void spawnDungeon(World world, int chunkX, int chunkZ) { + if(ConfigHandler.disableAPI) return; + try { + placeDungeon(new Random(), chunkX, chunkZ, world); + } catch (Throwable e) { + System.err.println("[DLDUNGEONS] Danger! Failed to finalize a dungeon after building!"); + e.printStackTrace(); + } + } + + + /** + * This will spawn a dungeon at the given chunk coordinates. It will use the seed given, + * which should typically be derived in some way from the world seed, but should NEVER be + * the actual world seed itself. A simple way to do this is to use nextLong() on an instance + * of Random that is itself based on the world seed. + */ + public static void spawnDungeon(World world, int chunkX, int chunkZ, long seed) { + if(ConfigHandler.disableAPI) return; + try { + placeDungeon(new Random(seed), chunkX, chunkZ, world); + } catch (Throwable e) { + System.err.println("[DLDUNGEONS] Danger! Failed to finalize a dungeon after building!"); + e.printStackTrace(); + } + } + + + /** + * This will spawn a dungeon at the given chunk coordinates, using a random number + * generated that is passed to it. Usually this is better than passing a seed unless the + * seed is derived in a specialized way for some reason. + */ + public static void spawnDungeon(World world, int chunkX, int chunkZ, Random random) { + if(ConfigHandler.disableAPI) return; + try { + placeDungeon(random, chunkX, chunkZ, world); + } catch (Throwable e) { + System.err.println("[DLDUNGEONS] Danger! Failed to finalize a dungeon after building!"); + e.printStackTrace(); + } + } + + + /** + * This will add a dimension to the list the blacklist / whitelist. + */ + public static void addDimension(byte dim) { + if(ConfigHandler.disableAPI) return; + GenerationHandler.addDimension(dim); + } + + + /** + * This will remove a dimension to the list the blacklist / whitelist. + * + */ + public static void subDimension(int dim) { + if(ConfigHandler.disableAPI) return; + GenerationHandler.subDimension(dim); + } + + + /** + * This will replace the dimension list (whitelist or blacklist with + * a new list. It will take a list as a string in the format: + */ + public static void setDimensions(int[] dims) { + if(ConfigHandler.disableAPI) return; + GenerationHandler.setDimensions(dims); + } + + + /** + * This will set the difficulty of dungeons being generated to + * the value passed. + */ + public static void setDifficulty(int diff) { + if(ConfigHandler.disableAPI) return; + ConfigHandler.parseDiff(diff); + } + + + /** + * This will load a theme at run time. It takes the path of the theme + * file as a parameter. + */ + public static void loadTheme(String file) { + if(ConfigHandler.disableAPI) return; + File theme = new File(file); + BufferedReader instream = null; + try { + instream = new BufferedReader(new + FileReader(ConfigHandler.configDir.toString() + File.separator + file.toString())); + System.out.println("[DLDUNGEONS] Loading theme file " + file.toString()); + ThemeReader.parseTheme(instream, file.toString()); + if(instream != null) instream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + /** + * This will set the dimension list to act as a blacklist. This should be + * used with caution, since players may have set it to act as a whitelist + * for reason dealing with mods other than the one calling the method. + */ + public static void blacklistDimensions() { + if(ConfigHandler.disableAPI) return; + ConfigHandler.positiveDims = false; + } + + + /** + * This will set the dimension list to act as a whitelist. This should be + * used with caution, since players may have set it to act as a blacklist + * for reason dealing with mods other than the one calling the method. + */ + public static void whitelistDimensions() { + if(ConfigHandler.disableAPI) return; + ConfigHandler.positiveDims = true; + } + + + /** + * Sets the the save directory to that used by Minecraft for the world, + * and returns. + * + * @param world + */ +// public static File saveWorldData(World world) { +// File saveDir = world.getSaveHandler().getWorldDirectory(); +// return saveDir; +// } +// + + /** + * This will reload the config file, effectively erasing any changes made during runtime. + * Alternately, if the config has been edited it will bring up the new settings. + */ + public static void reloadConfig() { + if(ConfigHandler.disableAPI) return; + ConfigHandler.reload(); + } + + + /** + * Returns true if the API is not disabled, or false if it is disables. + * + * @return disableAPI + */ + public static boolean apiOn() { + return !ConfigHandler.disableAPI; + } + +} diff --git a/src/jaredbgreat/dldungeons/builder/Builder.java b/src/jaredbgreat/dldungeons/builder/Builder.java new file mode 100644 index 0000000..a45988c --- /dev/null +++ b/src/jaredbgreat/dldungeons/builder/Builder.java @@ -0,0 +1,98 @@ +package jaredbgreat.dldungeons.builder; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import static jaredbgreat.dldungeons.builder.DBlock.*; +import jaredbgreat.dldungeons.planner.Dungeon; +import java.util.Arrays; +import java.util.Random; +import java.util.logging.Level; +import org.bukkit.Bukkit; +import org.bukkit.World; + + +public class Builder { + + private static boolean debugPole = false; + + + /** + * This will place a dungeon into the world, and is called to create the dungeon object + * (which plans the dungeon) when a dungeon is cheated in by command or generated through + * the API and have the dungeon built. Basically, this is used any time and dungeons is + * generated without the use of IChunkGenerator and IChunkProvider objects, that is, not + * through an IWorldGenerator. + * + * @param random + * @param chunkX + * @param chunkZ + * @param world + * @throws Throwable + */ + public static void placeDungeon(Random random, int chunkX, int chunkZ, World world) throws Throwable { +// if(world.isRemote) return; // Do not perform world-gen on the client! +// if (MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.PlaceDungeonBegin(random, chunkX, chunkZ, world))) return; +// DoomlikeDungeons.profiler.startTask("Create Dungeons"); + Dungeon dungeon = new Dungeon(random, + world.getBiome(chunkX * 16, chunkZ * 16), + world, chunkX, chunkZ); + buildDungeon(dungeon); + dungeon.preFinalize(); + dungeon = null; +// MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.PlaceDungeonFinish(random, chunkX, chunkZ, world, dungeon)); +// DoomlikeDungeons.profiler.endTask("Create Dungeons"); + } + + + /** + * This will build the dungeon into the world, technically by having the dungeons map + * build itself. + * + * @param dungeon + */ + public static void buildDungeon(Dungeon dungeon /*TODO: Parameters*/) { + //System.out.println("[DLDUNGONS] Inside Builder.placeDungeon; building dungeon"); + if(dungeon.theme != null) dungeon.map.build(dungeon); +// else Bukkit.getLogger().log(Level.SEVERE, "ERROR1"); //$$$ + } + + + /** + * This will build a quartz pillar to appear in the center of the dungeon from y=16 to y=240, + * and a lapis lazuli boarder to appear around the area allotted for the dungeon at y=80. + * + * This is only called if debugPole == true. + * + * @param world + * @param chunkX + * @param chunkZ + * @param dungeon + */ + public static void debuggingPole(World world, int chunkX, int chunkZ, Dungeon dungeon) { + int x = (chunkX * 16) + 8; + int z = (chunkZ * 16) + 8; + for(int y = 16; y <= 241; y++) placeBlock(world, x, y, z, quartz); + for(int i = -dungeon.size.radius; i <= dungeon.size.radius; i++) { + placeBlock(world, x - dungeon.size.radius, 80, z + i, lapis); + placeBlock(world, x + dungeon.size.radius, 80, z + i, lapis); + placeBlock(world, x + i, 80, z - dungeon.size.radius, lapis); + placeBlock(world, x + i, 80, z + dungeon.size.radius, lapis); + } + } + + + /** + * Set the debugPole variable. Setting this to true will cause a quartz pillar to appear in the + * center of the dungeon from y=16 to y=240, and a lapis lazuli boarder to appear around the area + * allotted for the dungeon at y=80. + * + * @param val + */ + public static void setDebugPole(boolean val) { + debugPole = val; + } +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/builder/DBlock.java b/src/jaredbgreat/dldungeons/builder/DBlock.java new file mode 100644 index 0000000..0b75d2e --- /dev/null +++ b/src/jaredbgreat/dldungeons/builder/DBlock.java @@ -0,0 +1,359 @@ +package jaredbgreat.dldungeons.builder; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import java.util.ArrayList; +import java.util.NoSuchElementException; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.EntityType; + +public final class DBlock { + private final String id; // The name + private final Material block; // The Minecraft block + + // Block constants used by the mod for various purposes, usually for placement + public static final Material spawner = Material.SPAWNER; + public static final Material chest = Material.CHEST; + public static final Material portal1 = Material.END_PORTAL_FRAME; + public static final Material portal2 = Material.END_PORTAL; + public static final Material quartz = Material.QUARTZ_BLOCK; + public static final Material lapis = Material.LAPIS_BLOCK; + public static final Material water = Material.WATER; + public static final Material air = Material.AIR; + + // Block IDs, used for comparison to tell if the block is allowed to be replaced +// public static final int chestid = Block.getIdFromBlock(chest); +// public static final int spawnerid = Block.getIdFromBlock(spawner); +// public static final int portal1id = Block.getIdFromBlock(portal1); +// public static final int portal2id = Block.getIdFromBlock(portal2); + + // All blocks, complete with meta-data used by the mod + public static final ArrayList registry = new ArrayList(); + + + /** + * Gets the item named by the string "in" -- hacky, but might work + * for now, hopefully.... + * + * @param in + * @return + */ +// private static Item getItem(String in) { +// return Item.REGISTRY.getObject(new ResourceLocation(in)); +// } + + + /** + * Construct a dungeon block using a theme format from version 1.7 of the mod + * or newer. + * + * @param id + */ + private DBlock(String id) throws NoSuchElementException { + this.id = id; + this.block = Bukkit.createBlockData(id).getMaterial(); +// Block theBlock; +// int meta; +// StringTokenizer nums = new StringTokenizer(id, ":({[]})"); +// String modid = nums.nextToken(); +// ResourceLocation name = new ResourceLocation(modid +// + ":" + nums.nextToken()); +// theBlock = GameRegistry.findRegistry(Block.class).getValue(name); +// if(theBlock == null) { +// String error = "[DLDUNGEONS] ERROR! Block read as \"" + id +// + "\" was was not in registry (returned null)."; +// Logging.logError(error); +// throw new NoSuchElementException(error); +// } +// if(nums.hasMoreElements()) { +// meta = Integer.parseInt(nums.nextToken()); +// } else { +// meta = 0; +// } +// block = theBlock.getStateFromMeta(meta); +// if(block.toString().contains("minecraft:air") +// && !id.contains("minecraft:air")) { +// String error = "[DLDUNGEONS] ERROR! Block read as \"" + id +// + "\" parsed into an air block!"; +// Logging.logError(error); +// throw new NoSuchElementException(error); +// } + } + + + /** + * This is the same as just place(), and will use the full block state. It + * is maintained for compatibility, but no longer has a real purpose. + * + * @param world + * @param x + * @param y + * @param z + */ +// @Deprecated +// public void placeNoMeta(World world, int x, int y, int z) { +// if(isProtectedBlock(world, x, y, z)) return; +// BlockPos pos = new BlockPos(x, y, z); +// if (MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.PlaceDBlock(world, pos, this))) return; +// world.setBlockState(new BlockPos(x, y, z), block); +// } + + + /** + * Places the block in the world, including its correct meta-data. This wrapping allow + * for changes in block / state representation and method signatures to be easily + * adapted and for meta-blocks to easily be used in dungeons. + * + * @param world + * @param x + * @param y + * @param z + */ + public void place(World world, int x, int y, int z) { + if(isProtectedBlock(world, x, y, z)) return; + world.getBlockAt(x, y, z).setType(block); + } + + + /************************************************************************************/ + /* STATIC UTILITIES BELOW (non-static methods above) */ + /************************************************************************************/ + + + /** + * This will place a block from the DBlock registry into the world based on its internal + * ID (i.e., its registry index). + * + * @param world + * @param x + * @param y + * @param z + * @param block + */ + public static void place(World world, int x, int y, int z, int block) { + if(!isProtectedBlock(world, x, y, z)) + registry.get(block).place(world, x, y, z); + } + + + /** + * Turns a string labeling the block into a DBlock and adds it to the registry if + * its not already present. It will return the new DBlocks registry index for + * use as an internal id. + * + * This is for use with mod versions newer that 1.7. + * + * + * @param id + * @param version + * @return + * @throws NoSuchElementException + */ + public static int add(String id) throws NoSuchElementException { + DBlock block = new DBlock(id); + if(!registry.contains(block)) { + registry.add(block); + } + return registry.indexOf(block); + } + + + /** + * Purely a wrapper for block/state placing/setting methods typically found in world, + * allowing easier updating when block representation or method signature / location + * changes. + * + * @param world + * @param x + * @param y + * @param z + * @param block + */ + public static boolean placeBlock(World world, int x, int y, int z, BlockData block) { + if(isProtectedBlock(world, x, y, z)) return false; +// BlockPos pos = new BlockPos(x, y, z); +// if (MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.PlaceBlock(world, pos, block))) return false; + world.getBlockAt(x, y, z).setBlockData(block); +// world.setBlockState(pos, block.getDefaultState()); + + return true; + } + public static boolean placeBlock(World world, int x, int y, int z, Material block) { + if(isProtectedBlock(world, x, y, z)) return false; +// BlockPos pos = new BlockPos(x, y, z); +// if (MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.PlaceBlock(world, pos, block))) return false; + world.getBlockAt(x, y, z).setType(block); +// world.setBlockState(pos, block.getDefaultState()); + + return true; + } + + + /** + * Purely a wrapper for block/state placing/setting methods typically found in world, + * allowing easier updating when block representation or method signature / location + * changes. + * + * @param world + * @param x + * @param y + * @param z + * @param block + */ +// public static void placeBlock(World world, int x, int y, int z, Block block, int a, int b) { +// if(isProtectedBlock(world, x, y, z)) return; +// world.setBlockState(new BlockPos(x, y, z), block.getStateFromMeta(a)); +// } + + + /** + * A wrapper for setting a block to air. + * + * @param world + * @param x + * @param y + * @param z + */ + public static void deleteBlock(World world, int x, int y, int z) { + if(isProtectedBlock(world, x, y, z)) return; +// world.setBlockToAir(new BlockPos(x, y, z)); + world.getBlockAt(x, y, z).setType(air); + } + + + /** + * Almost a wrapper for setting the block to air in world, but will alternately set + * blocks to water instead if a dungeons is flooded. + * + * @param world + * @param x + * @param y + * @param z + * @param flooded + */ + public static void deleteBlock(World world, int x, int y, int z, boolean flooded) { + if(isProtectedBlock(world, x, y, z)) return; + if(flooded) placeBlock(world, x, y, z, water); + else world.getBlockAt(x, y, z).setType(air); + } + + + /** + * Simply a wrapper for placing a chest. + * + * @param world + * @param x + * @param y + * @param z + */ + public static void placeChest(World world, int x, int y, int z) { + placeBlock(world, x, y, z, chest); + } + + + /** + * This will place a spawner and set it to spawn the mob named. + * + * @param world + * @param x + * @param y + * @param z + * @param mob + */ + public static void placeSpawner(World world, int x, int y, int z, EntityType mob) { + // Place spawner block +// BlockPos pos = new BlockPos(x, y, z); +// if (MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.BeforePlaceSpawner(world, pos, mob))) return; + if(isProtectedBlock(world, x, y, z)) return; + if(!placeBlock(world, x, y, z, spawner)) return; + + Block b = world.getBlockAt(x, y, z); + CreatureSpawner sp = (CreatureSpawner ) b.getState(); + sp.setSpawnedType(mob); + sp.update(); +// TileEntityMobSpawner theSpawner = (TileEntityMobSpawner)world.getTileEntity(pos); + + // Set up spawner logic +// MobSpawnerBaseLogic logic = theSpawner.getSpawnerBaseLogic(); +// NBTTagCompound spawnData = new NBTTagCompound(); +// spawnData.setString("id", mob); +// logic.setNextSpawnData(new WeightedSpawnerEntity(1, spawnData)); + } + + + /** + * True if the block Material is ground, grass, iron, sand, rock, or clay. This is + * used to determine if building under a structure should stop because it has reached + * the ground, so true really mean "stop building now." + * + * @param world + * @param x + * @param y + * @param z + * @return + */ + public static boolean isGroundBlock(World world, int x, int y, int z) { + Material mat = world.getBlockAt(x, y, z).getType(); + return (mat == Material.GRASS) + || (mat == Material.IRON_BLOCK) + || (mat == Material.DIRT) + || (mat == Material.SAND) + || (mat == Material.STONE) + || (mat == Material.CLAY + // Failsafe, it can never go into the void, or become an infinite loop + || (y < 0)); + } + + + /** + * True if the block is one that should not be built over; specifically a chest, + * spawner, or any part of the End portal. + * + * @param world + * @param x + * @param y + * @param z + * @return + */ + public static boolean isProtectedBlock(World world, int x, int y, int z) { +// int block = Block.getIdFromBlock(world.getBlockState(new BlockPos(x, y, z)).getBlock()); + Material block = world.getBlockAt(x, y, z).getType(); + return (block == chest || block == spawner + || block == portal1 || block == portal2); + } + + + /************************************************************************************/ + /* BASIC OVERIDEN METHODS FROM OBJECT */ + /************************************************************************************/ + + + /** + * Returns true if the other object is a DBlock the holds the same block with + * the same meta-data. + */ + @Override + public boolean equals(Object other) { + if(!(other instanceof DBlock)) return false; + return (block.equals(((DBlock)other).block)); + } + + + /** + * Returns a hash code derived from the block id and meta data; it will only produce + * the same hash code if these are both equal, that is, equal hash codes implies equals() + * is true. + */ + @Override + public int hashCode() { + return block.hashCode(); + } +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/parser/CharSet.java b/src/jaredbgreat/dldungeons/parser/CharSet.java new file mode 100644 index 0000000..de63fa0 --- /dev/null +++ b/src/jaredbgreat/dldungeons/parser/CharSet.java @@ -0,0 +1,199 @@ +package jaredbgreat.dldungeons.parser; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +/** + * A set class (not based on Set) for characters stored as type char. + * + * This is not intended to be thread safe. + * + * Note that this only works with extended ASCII (values from 0 to 255). + * + * As this uses 10 ints (8 for data, 2 for processing) it should use 40 + * bytes if data, This is more than for a short String or char[], but it + * should be faster and difference should be negligible in a game using + * a gigabyte by default. Then, the speed should also be negligible, + * especially at load time, but I wanted to try this anyway. + * + * @author JaredBGreat (Jared Blackburn) + */ +public class CharSet { + private static final int BYTES = 256 / 32; + private int[] data; + + // Space kept to avoid memory allocation / deallocation; + // this is not thread safe but this should not be called + // concurrently from multiple threads. + private int bit; + private int loc; + + /** + * Creates a new, empty CharSet. + */ + public CharSet() { + data = new int[BYTES]; + } + + + /** + * Creates a new char set contain the characters in the array. + * + * @param in + */ + public CharSet(char[] in) { + data = new int[BYTES]; + add(in); + } + + + /** + * Creates a new char set contain the characters in the String. + * + * @param in + */ + public CharSet(String in) { + data = new int[BYTES]; + add(in.toCharArray()); + } + + + /** + * Adds the character to the CharSet. + * + * @param in + */ + public void add(char in) { + if(in > 255) return; + bit = ((int) in) % 32; + loc = ((int) in) / 32; + if((data[loc] & (1 << bit)) == 0) { + data[loc] |= (1 << bit); + } + } + + + /** + * Removes the character from the charset. + * @param in + */ + public void remove(char in) { + if(in > 255) return; + bit = ((int) in) % 32; + loc = ((int) in) / 32; + if((data[loc] & (1 << bit)) != 0) { + data[loc] &= ~(1 << bit); + } + } + + + /** + * Adds all the characters in the array to the CharSet. + * + * @param in + */ + public void add(char[] in) { + for(int i = 0; i < in.length; i++) { + add(in[i]); + } + } + + + /** + * Removes all the characters in the array from the CharSet. + * + * @param in + */ + public void remove(char[] in) { + for(int i = 0; i < in.length; i++) { + remove(in[i]); + } + } + + + /** + * Adds all the characters in the other CharSet to this CharSet. + * + * @param in + */ + public void add(CharSet in) { + for(int i = 0; i < BYTES; i++) { + data[i] |= in.data[i]; + } + } + + + /** + * Removes all the characters in the other CharSet from this CharSet. + * + * @param in + */ + public void remove(CharSet in) { + for(int i = 0; i < BYTES; i++) { + data[i] &= ~in.data[i]; + } + } + + + /** + * Return the union of this CharSet and the input. + * + * @param in + * @return + */ + public CharSet union(CharSet in) { + CharSet out = new CharSet(); + for(int i = 0; i < BYTES; i++) { + out.data[i] = in.data[i] | data[i]; + } + return out; + } + + + /** + * Return the intersection of this CharSet and the input. + * + * @param in + * @return + */ + public CharSet intersection(CharSet in) { + CharSet out = new CharSet(); + for(int i = 0; i < BYTES; i++) { + out.data[i] = in.data[i] & data[i]; + } + return out; + } + + + /** + * Return the complement of this CharSet. + * + * @param in + * @return + */ + public CharSet complement() { + CharSet out = new CharSet(); + for(int i = 0; i < data.length; i++) { + out.data[i] = ~data[i]; + } + return out; + } + + + /** + * Returns true if and only if the character in a member of the + * CharSet. + * + * @param in + * @return + */ + public boolean contains(char in) { + if(in > 255) return false; + bit = ((int) in) % 32; + loc = ((int) in) / 32; + return (data[loc] & (1 << bit)) != 0; + } + +} diff --git a/src/jaredbgreat/dldungeons/parser/Tokenizer.java b/src/jaredbgreat/dldungeons/parser/Tokenizer.java new file mode 100644 index 0000000..8d69783 --- /dev/null +++ b/src/jaredbgreat/dldungeons/parser/Tokenizer.java @@ -0,0 +1,268 @@ +package jaredbgreat.dldungeons.parser; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import java.util.Arrays; + +/** + * A custom alternative to Java's StringTokenizer class. This allows for + * the use of quotations and escape sequences. Basically, its this makes + * it possible to use white space inside strings. Anything inside quotation + * marks will be read in, processing escape sequences normally but without + * tokenizing the quoted text. All the escape sequences found in Java are also + * recognized, along wiht an \s sequences the become a single white space (an + * alternative to quoted strings). + * + * @author JaredBGreat (Jared Blackburn) + * + */ +public class Tokenizer { + private static final CharSet hex = new CharSet(new + char[]{'1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', + 'A', 'B', 'C', 'D', 'E', 'F'}); + private final CharSet delim; + private String[] tokens; + private int token = 0; + + // variable for processing + private String in; + private int position = 0; + private int size = 0; + private char next = 0; + private char[] scratchpad; + boolean onTokens = false; + boolean atEnd = false; + + + public Tokenizer(String input, String delims) { + delim = new CharSet(delims); + in = input; + readTokens(); + } + + + /** + * This will find the the next character, and process escape characters. + */ + private void nextChar() { + next = in.charAt(position); + if(next == '\\') { + readEscape(); + } + position++; + } + + + /** + * Reads the line of text and turns it into tokens. + */ + private void readTokens() { + tokens = new String[(in.length() / 5) + 1]; + scratchpad = new char[in.length()]; + while(position < in.length()) { + nextChar(); + if(delim.contains(next)) { + if(onTokens) { + addToken(); + onTokens = false; + size = 0; + } + } + else if(!atEnd) { + onTokens = true; + if(next == '\"') { + readQuote(); + } else { + scratchpad[size] = next; + size++; + } + } + } + if(onTokens) { + addToken(); + onTokens = false; + size = 0; + } + tokens = (String[])Arrays.copyOf(tokens, token); + token = 0; + } + + + /** + * Adds a token that has been found. + */ + private void addToken() { + if(token >= tokens.length) { + int newCapacity = Math.min(tokens.length * 2, tokens.length + 16); + tokens = (String[])Arrays.copyOf(tokens, newCapacity); + } + tokens[token] = new String(scratchpad, 0, size); + token++; + } + + + /** + * This will read every thing from the until the basis character is + * encountered again, ignoring all delimeters. The basis should always + * be the same character that started the quote section, which should + * usually be either a single or double quote (" or '), with double + * quotes preferred. + * + * Note that escape sequences are not read literally. but still treated as + * escaped. + * + * Also not that the quotation character itself in not included; to used + * these are part of a string its required to include and escaped version. + * + * @param basis + */ + private void readQuote() { + onTokens = true; + nextChar(); + while((position < in.length()) && (next != '\"')) { + scratchpad[size] = next; + size++; + nextChar(); + } + } + + + /** + * This will change a two character escape sequence into the correct + * chracter, allowing quotes (among other things) to be used. Note + * that this uses the standered backslash as and that an literal + * backslash must thus be represented as a double backslash. + */ + private void readEscape() { + do { + onTokens = true; + position++; + if(position >= in.length()) return; + next = in.charAt(position); + switch(next) { + case '"': + scratchpad[size] = '"'; + break; + case '\'': + scratchpad[size] = '\''; + break; + case 'n': + scratchpad[size] = '\n'; + break; + case 'r': + scratchpad[size] = '\r'; + break; + case 't': + scratchpad[size] = '\t'; + break; + case 'f': + scratchpad[size] = '\f'; + break; + case 'b': + scratchpad[size] = '\b'; + break; + case '0': + scratchpad[size] = '\0'; + break; + case 's': + scratchpad[size] = ' '; + break; + case 'u': + scratchpad[size] = parseUnicode(); + break; + // Any character not otherwise defined will be preserved as-is; + // this also automatically covers the use of double backslash. + default: + scratchpad[size] = next; + break; + } + size++; + position++; + if(position >= in.length()) { + atEnd = true; + return; + } + next = in.charAt(position); + } while(next == '\\'); + } + + + private char parseUnicode() { + nextChar(); + StringBuilder nstring = new StringBuilder(); + while((position < in.length()) && (hex.contains(in.charAt(position)))) { + nextChar(); + nstring.append(next); + } + // Without this it will skip ahead. + position--; + return (char)Integer.parseUnsignedInt(nstring.toString().toLowerCase(), 16); + } + + + /** + * Returns the number of tokens. + * + * @return number of tokens + */ + public int countTokens() { + return tokens.length; + } + + + /** + * Returns whether or not there are more tokens + * + * @return + */ + public boolean hasMoreTokens() { + return token < tokens.length; + } + + + /** + * Returns the next available token. If there are no more tokens it + * will return null. + * + * @return the next token + */ + public String nextToken() { + if(hasMoreTokens()) { + return tokens[token++]; + } else return null; + } + + + /** + * Resets the to the first token + */ + public void reset() { + token = 0; + } + + + /** + * Gets the token at the given index. If an index is out of range this + * will return null. + * + * @param index + * @return the token at the give index + */ + public String getToken(int index) { + if(index >= 0 && index < tokens.length) { + return tokens[index]; + } else return null; + } + + /** + * Gets the raw input string. + * @return the input + */ + public String getString() { + return in; + } +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/pieces/Doorway.java b/src/jaredbgreat/dldungeons/pieces/Doorway.java new file mode 100644 index 0000000..8504dfc --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/Doorway.java @@ -0,0 +1,108 @@ +package jaredbgreat.dldungeons.pieces; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.planner.mapping.Tile; + + +/** + * This class represents a doorway for use with classes in the astar + * package, notable DoorChecker and AStar. + * + * Note that this represents the door in relation to a specific room; + * the same room will have a separate listing for each room it connects + * within that rooms list of doors. + * + * @author Jared Blackburn + * + */ +public class Doorway extends Tile implements Comparable { + /** + * True if aligned along the x axis, false if aligned along the z axis. + */ + public boolean xOriented; + /** + * How desirable this door is as the primary connection between rooms; this + * is effected by its position in relation to pool and its previous uses in + * connecting rooms. + */ + public int priority; + /** + * The id (index) of the room on the other side. + */ + public int otherside; + + + public Doorway(int x, int z, boolean xOriented) { + super(x, z); + this.xOriented = xOriented; + priority = 0; + } + + + public Doorway(Doorway door) { + super(door.x, door.z); + xOriented = door.xOriented; + priority = door.priority; + otherside = door.otherside; + } + + + public Doorway(Doorway door, int otherside) { + super(door.x, door.z); + xOriented = door.xOriented; + priority = door.priority; + this.otherside = otherside; + } + + + /** + * This will find the number of sides bordering a "liguid" + * pool and add it to the priority value; since the Java + * priority queue sorts to lowest value first increasing this + * effectively decreases the priority so that pools with no + * or fewer pools beside them will be chosen first as doors + * for AStar to connect. + * + * @param dungeon + * @param start + */ + public void prioritize(Dungeon dungeon, int start) { + if(xOriented) { + if(dungeon.map.hasLiquid[x+1][z]) priority++; + if(dungeon.map.hasLiquid[x-1][z]) priority++; + if(dungeon.map.room[x+1][z] == start) + otherside = dungeon.map.room[x-1][z]; + else otherside = dungeon.map.room[x+1][z]; + } else { + if(dungeon.map.hasLiquid[x][z+1]) priority++; + if(dungeon.map.hasLiquid[x][z-1]) priority++; + if(dungeon.map.room[x][z+1] == start) + otherside = dungeon.map.room[x][z-1]; + else otherside = dungeon.map.room[x][z+1]; + } + } + + + @Override + public int compareTo(Doorway o) { + return priority - o.priority; + } + + + /** + * Returns the same location represented as a Tile. + * + * @return basic tile at the same location + */ + public Tile getTile() { + return new Tile(x, z); + } + + + +} diff --git a/src/jaredbgreat/dldungeons/pieces/Rectangle.java b/src/jaredbgreat/dldungeons/pieces/Rectangle.java new file mode 100644 index 0000000..fa5b1b8 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/Rectangle.java @@ -0,0 +1,394 @@ +package jaredbgreat.dldungeons.pieces; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.themes.ThemeFlags; +import jaredbgreat.dldungeons.themes.ThemeType; + + +/** + * The building block for more complex shape-primitives represented + * by the Shape class, and thus the foundational class for all dungeon + * architecture. + * + * Each rectangle is, if used correctly, a sub-section of a unit square + * centered on 0,0 in the xz plane. This allows them, and thus shape + * built from them, to be stretched to a desired size and shape (rounded) + * by multiplication by the desired dimensions and placed by adding the + * coordinates of the center block (which could very well be a fractional + * block. + * + * All rectangles used are static final members of this class. The class + * is also immutable. + * + * @author Jared Blackburn + * + */ +public final class Rectangle { + + private final float xdim, zdim, xcoord, zcoord; // Width in each dimension and center coordinates + + + public Rectangle(float xdim, float zdim, float xcoord, float zcoord) { + this.xdim = xdim; + this.zdim = zdim; + this.xcoord = xcoord; + this.zcoord = zcoord; + } + + + /** + * Add the rectangle to the dungeon as pool of "liquid." + * + * @param dungeon + * @param room + * @param sx x coordinate + * @param sz z coordinate + * @param sdimx length on x + * @param sdimz length on z + * @param invertX + * @param invertZ + */ + public void drawLiquid(Dungeon dungeon, Room room, float sx, float sz, float sdimx, float sdimz, + boolean invertX, boolean invertZ) { + int drop; + if(dungeon.theme.flags.contains(ThemeFlags.SWAMPY)) drop = 1; + else drop = 2; + byte xbegin, xend, zbegin, zend; + + // Find actual beginning and ending coordinates + if(invertX) { + xbegin = (byte)(sx - ((sdimx * xdim) / 2.0f) - (xcoord * sdimx)); + xend = (byte)(sx + ((sdimx * xdim) / 2.0f) - (xcoord * sdimx)); + } else { + xbegin = (byte)(sx - ((sdimx * xdim) / 2.0f) + (xcoord * sdimx)); + xend = (byte)(sx + ((sdimx * xdim) / 2.0f) + (xcoord * sdimx)); + } + if(invertZ) { + zbegin = (byte)(sz - ((sdimz * zdim) / 2.0f) - (zcoord * sdimz)); + zend = (byte)(sz + ((sdimz * zdim) / 2.0f) - (zcoord * sdimz)); + } else { + zbegin = (byte)(sz - ((sdimz * zdim) / 2.0f) + (zcoord * sdimz)); + zend = (byte)(sz + ((sdimz * zdim) / 2.0f) + (zcoord * sdimz)); + } + + // Place floor, ceiling, and empty space + for(byte k = zbegin; k < zend; k++) + for(byte j = xbegin; j < xend; j++) { + if((j < 0) || (j >= dungeon.size.width) || (k < 0) || (k >= dungeon.size.width)) continue; + if(dungeon.map.room[j][k] != room.id) continue; + if(dungeon.map.floorY[j][k] > room.floorY) dungeon.map.floorY[j][k] = (byte)room.floorY; + dungeon.map.floorY[j][k] = (byte)(room.floorY - drop); + dungeon.map.hasLiquid[j][k] = true; + byte nFloorY = dungeon.map.nFloorY[j][k] < dungeon.map.floorY[j][k] ? + dungeon.map.nFloorY[j][k] : dungeon.map.floorY[j][k]; + dungeon.map.nFloorY[j][k] = nFloorY; + } + } + + + /** + * Add the rectangle to as a walkway (normal floor) through a previously added pool. + * + * @param dungeon + * @param room + * @param sx x coordinate + * @param sz z coordinate + * @param sdimx length in x + * @param sdimz length in z + * @param invertX + * @param invertZ + */ + public void drawWalkway(Dungeon dungeon, Room room, float sx, float sz, byte sdimx, byte sdimz, + boolean invertX, boolean invertZ) { + byte xbegin, xend, zbegin, zend; + int drop; + if(dungeon.theme.type.contains(ThemeType.SWAMP)) drop = 1; + else drop = 2; + //System.out.println("Writing rectange."); + if(invertX) { + xbegin = (byte)(sx - ((sdimx * xdim) / 2.0f) - (xcoord * sdimx)); + xend = (byte)(sx + ((sdimx * xdim) / 2.0f) - (xcoord * sdimx)); + } else { + xbegin = (byte)(sx - ((sdimx * xdim) / 2.0f) + (xcoord * sdimx)); + xend = (byte)(sx + ((sdimx * xdim) / 2.0f) + (xcoord * sdimx)); + } + if(invertZ) { + zbegin = (byte)(sz - ((sdimz * zdim) / 2.0f) - (zcoord * sdimz)); + zend = (byte)(sz + ((sdimz * zdim) / 2.0f) - (zcoord * sdimz)); + } else { + zbegin = (byte)(sz - ((sdimz * zdim) / 2.0f) + (zcoord * sdimz)); + zend = (byte)(sz + ((sdimz * zdim) / 2.0f) + (zcoord * sdimz)); + } + for(byte k = zbegin; k < zend; k++) + for(byte j = xbegin; j < xend; j++) { + if((j < 0) || (j >= dungeon.size.width) || (k < 0) || (k >= dungeon.size.width)) continue; + byte nFloorY = dungeon.map.nFloorY[j][k] < dungeon.map.floorY[j][k] ? + dungeon.map.nFloorY[j][k] : dungeon.map.floorY[j][k]; + dungeon.map.floorY[j][k] += drop; + dungeon.map.hasLiquid[j][k] = false; + dungeon.map.nFloorY[j][k] = nFloorY; + } + //System.out.println("Rectangle has been drawn."); + } + + + /** + * Adds the rectangle as a section filled with walls from floor to ceiling (an + * area cut out from the rooms actual space). + * + * @param dungeon + * @param room + * @param sx x coordinate + * @param sz z coordinate + * @param sdimx length on x + * @param sdimz length on z + * @param invertX + * @param invertZ + */ + public void drawCutout(Dungeon dungeon, Room room, float sx, float sz, float sdimx, float sdimz, + boolean invertX, boolean invertZ) { + byte xbegin, xend, zbegin, zend; + if(invertX) { + xbegin = (byte)(sx - ((sdimx * xdim) / 2.0f) - (xcoord * sdimx)); + xend = (byte)(sx + ((sdimx * xdim) / 2.0f) - (xcoord * sdimx)); + } else { + xbegin = (byte)(sx - ((sdimx * xdim) / 2.0f) + (xcoord * sdimx)); + xend = (byte)(sx + ((sdimx * xdim) / 2.0f) + (xcoord * sdimx)); + } + if(invertZ) { + zbegin = (byte)(sz - ((sdimz * zdim) / 2.0f) - (zcoord * sdimz)); + zend = (byte)(sz + ((sdimz * zdim) / 2.0f) - (zcoord * sdimz)); + } else { + zbegin = (byte)(sz - ((sdimz * zdim) / 2.0f) + (zcoord * sdimz)); + zend = (byte)(sz + ((sdimz * zdim) / 2.0f) + (zcoord * sdimz)); + } + for(byte k = zbegin; k < zend; k++) + for(byte j = xbegin; j < xend; j++) { + if((j < 0) || (j >= dungeon.size.width) || (k < 0) || (k >= dungeon.size.width)) continue; + if(dungeon.map.room[j][k] != room.id) continue; + dungeon.map.isWall[j][k] = true; + } + } + + + /** + * Add the rectangle as a area of empty space, that is, an area from which previously + * place walls have been removed. + * + * @param dungeon + * @param room + * @param sx x coordinate + * @param sz z coordinate + * @param sdimx length in x + * @param sdimz length in z + * @param invertX + * @param invertZ + */ + public void drawCutin(Dungeon dungeon, Room room, float sx, float sz, byte sdimx, byte sdimz, + boolean invertX, boolean invertZ) { + byte xbegin, xend, zbegin, zend; + if(invertX) { + xbegin = (byte)(sx - ((sdimx * xdim) / 2.0f) - (xcoord * sdimx)); + xend = (byte)(sx + ((sdimx * xdim) / 2.0f) - (xcoord * sdimx)); + } else { + xbegin = (byte)(sx - ((sdimx * xdim) / 2.0f) + (xcoord * sdimx)); + xend = (byte)(sx + ((sdimx * xdim) / 2.0f) + (xcoord * sdimx)); + } + if(invertZ) { + zbegin = (byte)(sz - ((sdimz * zdim) / 2.0f) - (zcoord * sdimz)); + zend = (byte)(sz + ((sdimz * zdim) / 2.0f) - (zcoord * sdimz)); + } else { + zbegin = (byte)(sz - ((sdimz * zdim) / 2.0f) + (zcoord * sdimz)); + zend = (byte)(sz + ((sdimz * zdim) / 2.0f) + (zcoord * sdimz)); + } + for(byte k = zbegin; k < zend; k++) + for(byte j = xbegin; j < xend; j++) { + if((j < 0) || (j >= dungeon.size.width) || (k < 0) || (k >= dungeon.size.width)) continue; + dungeon.map.isWall[j][k] = false; + } + } + + + /** + * This will add a platform built based on the rectangle and its specifications. + * The specifications include the scaling factors in x and z, coordinated to + * place it, and if it should be inverted. This technically resent the floor + * height, and is thus also used to add depression be setting the floor to a lower + * height rather than higher. + * + * @param dungeon + * @param room + * @param floorY The new floor height + * @param sx the x coordinate + * @param sz the z coordinate + * @param sdimx the length on x + * @param sdimz the length on z + * @param invertX + * @param invertZ + */ + public void drawPlatform(Dungeon dungeon, Room room, byte floorY, float sx, float sz, float sdimx, float sdimz, + boolean invertX, boolean invertZ) { + byte xbegin, xend, zbegin, zend; + if(invertX) { + xbegin = (byte)(sx - ((sdimx * xdim) / 2.0f) - (xcoord * sdimx)); + xend = (byte)(sx + ((sdimx * xdim) / 2.0f) - (xcoord * sdimx)); + } else { + xbegin = (byte)(sx - ((sdimx * xdim) / 2.0f) + (xcoord * sdimx)); + xend = (byte)(sx + ((sdimx * xdim) / 2.0f) + (xcoord * sdimx)); + } + if(invertZ) { + zbegin = (byte)(sz - ((sdimz * zdim) / 2.0f) - (zcoord * sdimz)); + zend = (byte)(sz + ((sdimz * zdim) / 2.0f) - (zcoord * sdimz)); + } else { + zbegin = (byte)(sz - ((sdimz * zdim) / 2.0f) + (zcoord * sdimz)); + zend = (byte)(sz + ((sdimz * zdim) / 2.0f) + (zcoord * sdimz)); + } + for(byte k = zbegin; k < zend; k++) + for(byte j = xbegin; j < xend; j++) { + if((j < 0) || (j >= dungeon.size.width) || (k < 0) || (k >= dungeon.size.width)) continue; + if(dungeon.map.room[j][k] != room.id) continue; + dungeon.map.floorY[j][k] = floorY; + dungeon.map.hasLiquid[j][k] = false; + } + } + + + + + + /***********************/ + /* Rectangles */ + /***********************/ + + + // Rectangle (Works) + public static final Rectangle simple = new Rectangle(1.0f, 1.0f, 0.0f, 0.0f); + + // 'L' (Works) + public static final Rectangle lback000 = new Rectangle(0.5f, 1.0f, -0.25f, 0.0f); + public static final Rectangle lbottom000 = new Rectangle(0.5f, 0.5f, 0.25f, -0.25f); + public static final Rectangle lback090 = new Rectangle(1.0f, 0.5f, 0.0f, -0.25f); + public static final Rectangle lbottom090 = new Rectangle(0.5f, 0.5f, 0.25f, 0.25f); + public static final Rectangle lback270 = new Rectangle(0.5f, 1.0f, 0.25f, 0.0f); + public static final Rectangle lbottom270 = new Rectangle(0.5f, 0.5f, -0.25f, 0.25f); + public static final Rectangle lback180 = new Rectangle(1.0f, 0.5f, 0.0f, -0.25f); + public static final Rectangle lbottom180 = new Rectangle(0.5f, 0.5f, 0.25f, 0.25f); + + // 'O' (Works) + public static final Rectangle oleft = new Rectangle(0.3333333333f, 1.0f, -0.3333333333f, 0.0f); + public static final Rectangle oright = new Rectangle(0.3333333333f, 1.0f, 0.3333333333f, 0.0f); + public static final Rectangle obottom = new Rectangle(0.3333333333f, 0.3333333333f, 0.0f, -0.3333333333f); + public static final Rectangle otop = new Rectangle(0.3333333333f, 0.3333333333f, 0.0f, 0.3333333333f); + + // 'T' (I think its working -- not sure out its orientation)... + public static final Rectangle ttop000 = new Rectangle(1.0f, 0.3333333333f, 0.0f, 0.3333333333f); + public static final Rectangle tbottom000 = new Rectangle(0.3333333333f, 0.6666666667f, 0.0f, -0.1666666667f); + public static final Rectangle ttop090 = new Rectangle(0.3333333333f, 1.0f, -0.3333333333f, 0.0f); + public static final Rectangle tbottom090 = new Rectangle(0.6666666667f, 0.3333333333f, 0.1666666667f, 0.0f); + public static final Rectangle ttop180 = new Rectangle(1.0f, 0.3333333333f, 0.0f, -0.3333333333f); + public static final Rectangle tbottom180 = new Rectangle(0.3333333333f, 0.6666666667f, 0.0f, 0.1666666667f); + public static final Rectangle ttop270 = new Rectangle(0.3333333333f, 1.0f, 0.3333333333f, 0.0f); + public static final Rectangle tbottom270 = new Rectangle(0.6666666667f, 0.3333333333f, -0.1666666667f, 0.0f); + + // 'E' / 'F' (Working) + public static final Rectangle eback000 = new Rectangle(0.3333333333f, 1.0f, -0.3333333333f, 0.0f); + public static final Rectangle etop000 = new Rectangle(0.6666666667f, 0.2f, 0.1666666667f, 0.4f); + public static final Rectangle emiddle000 = new Rectangle(0.6666666667f, 0.2f, 0.1666666667f, 0.0f); + public static final Rectangle ebottom000 = new Rectangle(0.6666666667f, 0.2f, 0.1666666667f, -0.4f); + public static final Rectangle eback090 = new Rectangle(1.0f, 0.3333333333f, 0.0f, -0.3333333333f); + public static final Rectangle etop090 = new Rectangle(0.2f, 0.6666666667f, -0.4f, 0.1666666667f); + public static final Rectangle emiddle090 = new Rectangle(0.2f, 0.6666666667f, 0.0f, 0.1666666667f); + public static final Rectangle ebottom090 = new Rectangle(0.2f, 0.6666666667f, 0.4f, 0.1666666667f); + public static final Rectangle eback180 = new Rectangle(0.3333333333f, 1.0f, 0.3333333333f, 0.0f); + public static final Rectangle etop180 = new Rectangle(0.6666666667f, 0.2f, -0.1666666667f, 0.4f); + public static final Rectangle emiddle180 = new Rectangle(0.6666666667f, 0.2f, -0.1666666667f, 0.0f); + public static final Rectangle ebottom180 = new Rectangle(0.6666666667f, 0.2f, -0.1666666667f, -0.4f); + public static final Rectangle eback270 = new Rectangle(1.0f, 0.3333333333f, 0.0f, 0.3333333333f); + public static final Rectangle etop270 = new Rectangle(0.2f, 0.6666666667f, 0.4f, -0.1666666667f); + public static final Rectangle emiddle270 = new Rectangle(0.2f, 0.6666666667f, 0.0f, -0.1666666667f); + public static final Rectangle ebottom270 = new Rectangle(0.2f, 0.6666666667f, -0.4f, -0.1666666667f); + + // 'I' / 'H' (Working) + public static final Rectangle itop = new Rectangle(1.0f, 0.3333333333f, 0.0f, 0.3333333333f); + public static final Rectangle imiddle = new Rectangle(0.3333333333f, 0.3333333333f, 0.0f, 0.0f); + public static final Rectangle ibottom = new Rectangle(1.0f, 0.3333333333f, 0.0f, -0.3333333333f); + public static final Rectangle iright = new Rectangle(0.3333333333f, 1.0f, 0.3333333333f, 0.0f); + public static final Rectangle ileft = new Rectangle(0.3333333333f, 1.0f, -0.3333333333f, 0.0f); + + // Plus-shape (Works) + public static final Rectangle crosstop = new Rectangle(0.3333333333f, 0.3333333333f, 0.0f, 0.3333333333f); + public static final Rectangle crossmiddle = new Rectangle(1.0f, 0.3333333333f, 0.0f, 0.0f); + public static final Rectangle crossbottom = new Rectangle(0.3333333333f, 0.3333333333f, 0.0f, -0.3333333333f); + + // 'U' (Works) + public static final Rectangle uleft000 = new Rectangle(0.3333333333f, 0.6666666667f, + -0.3333333333f, 0.1666666667f); + public static final Rectangle uright000 = new Rectangle(0.3333333333f, 0.6666666667f, + 0.3333333333f, 0.1666666667f); + public static final Rectangle ubottom000 = new Rectangle(1.0f, 0.3333333333f, + 0.0f, -0.3333333333f); + public static final Rectangle uleft090 = new Rectangle(0.6666666667f, 0.3333333333f, + 0.1666666667f, -0.3333333333f); + public static final Rectangle uright090 = new Rectangle(0.6666666667f, 0.3333333333f, + 0.1666666667f, 0.3333333333f); + public static final Rectangle ubottom090 = new Rectangle(0.3333333333f, 1.0f, + -0.3333333333f, 0.0f); + public static final Rectangle uright180 = new Rectangle(0.3333333333f, 0.6666666667f, + 0.3333333333f, -0.1666666667f); + public static final Rectangle uleft180 = new Rectangle(0.3333333333f, 0.6666666667f, + -0.3333333333f, -0.1666666667f); + public static final Rectangle ubottom180 = new Rectangle(1.0f, 0.3333333333f, + 0.0f, 0.3333333333f); + public static final Rectangle uright270 = new Rectangle(0.6666666667f, 0.3333333333f, + -0.1666666667f, -0.3333333333f); + public static final Rectangle uleft270 = new Rectangle(0.6666666667f, 0.3333333333f, + -0.1666666667f, 0.3333333333f); + public static final Rectangle ubottom270 = new Rectangle(0.3333333333f, 1.0f, + 0.333333333f, 0.0f); + + // 'S' (Working) + public static final Rectangle stop000 = new Rectangle(1.0f, 0.2f, 0.0f, -0.4f); + public static final Rectangle smiddle000 = new Rectangle(1.0f, 0.2f, 0.0f, 0.0f); + public static final Rectangle sbottom000 = new Rectangle(1.0f, 0.2f, 0.0f, 0.4f); + public static final Rectangle sleft000 = new Rectangle(0.2f, 0.2f, -0.4f, 0.2f); + public static final Rectangle sright000 = new Rectangle(0.2f, 0.2f, 0.4f, -0.2f); + public static final Rectangle stop090 = new Rectangle(0.2f, 1.0f, -0.4f, 0.0f); + public static final Rectangle smiddle090 = new Rectangle(0.2f, 1.0f, 0.0f, 0.0f); + public static final Rectangle sbottom090 = new Rectangle(0.2f, 1.0f, 0.4f, 0.0f); + public static final Rectangle sleft090 = new Rectangle(0.2f, 0.2f, -0.2f, 0.4f); + public static final Rectangle sright090 = new Rectangle(0.2f, 0.2f, 0.2f, -0.4f); + + + + /***********************/ + /* Getters and Setters */ + /***********************/ + + + public float getxdim() { + return xdim; + } + + + public float getzdim() { + return zdim; + } + + + public float getxcoord() { + return xcoord; + } + + + public float getzcoord() { + return zcoord; + } +} diff --git a/src/jaredbgreat/dldungeons/pieces/Shape.java b/src/jaredbgreat/dldungeons/pieces/Shape.java new file mode 100644 index 0000000..48cd44c --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/Shape.java @@ -0,0 +1,225 @@ +package jaredbgreat.dldungeons.pieces; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.rooms.Room; + +import java.util.ArrayList; + +//import net.minecraft.world.World; +import static jaredbgreat.dldungeons.pieces.Rectangle.*; + + +/** + * This class represents shape primitives from which dungeon architecture + * is drawn. Each shape is cut from a unit square centered on 0,0 in the + * xz plane and built from rectangles. This allows for shapes to be easily + * stretched to fit areas they are added. In addition, they can be flipped + * on either axis and come in pre-rotated variations, for easy transformation. + * + * All shapes used by the mod are defined as static final members of the class, + * as are groups varying only by rotation as are larger groups defined by + * symmetry. + * + * @author Jared Blackburn + * + */ +public final class Shape { + + private final Rectangle[] rectangles; + + public Shape(Rectangle[] rectangles) { + this.rectangles = rectangles; + } + + + /** + * Add a pool of "liquid" in this shape to the dungeon. + * + * @param dungeon + * @param room + * @param sx the x coordinate + * @param sz the z coordinate + * @param sdimx the length on x + * @param sdimz the length on z + * @param invertX + * @param invertZ + */ + public void drawLiquid(Dungeon dungeon, Room room, float sx, float sz, float sdimx, float sdimz, + boolean invertX, boolean invertZ) { + for(Rectangle rect: rectangles) { + rect.drawLiquid(dungeon, room, sx, sz, sdimx, sdimz, invertX, invertZ); + } + } + + + /** + * Add a walkway (normal floor at normal height) through a pool of + * previously added liquid. This is mostly for use with whole room + * shapes. + * + * @param dungeon + * @param room + * @param sx the x coordinate + * @param sz the z coordinate + * @param sdimx the length on x + * @param sdimz the length on z + * @param invertX + * @param invertZ + */ + public void drawWalkway(Dungeon dungeon, Room room, float sx, float sz, byte sdimx, byte sdimz, + boolean invertX, boolean invertZ) { + for(Rectangle rect: rectangles) { + rect.drawWalkway(dungeon, room, sx, sz, sdimx, sdimz, invertX, invertZ); + } + } + + + /** + * Effectively remove an area of in the shape from the dungeon by filling it + * with walls. + * + * @param dungeon + * @param room + * @param sx the x coordinate + * @param sz the z coordinate + * @param sdimx the length on x + * @param sdimz the length on z + * @param invertX + * @param invertZ + */ + public void drawCutout(Dungeon dungeon, Room room, float sx, float sz, float sdimx, float sdimz, + boolean invertX, boolean invertZ) { + for(Rectangle rect: rectangles) { + rect.drawCutout(dungeon, room, sx, sz, sdimx, sdimz, invertX, invertZ); + } + } + + + /** + * Removes walls from an area of this shape (cuts into the wall); this is + * mostly for use with whole room shapes. + * + * @param dungeon + * @param room + * @param sx the x coordinate + * @param sz the z coordinate + * @param sdimx the length on x + * @param sdimz the length on z + * @param invertX + * @param invertZ + */ + public void drawCutin(Dungeon dungeon, Room room, + float sx, float sz, byte sdimx, byte sdimz, boolean invertX, boolean invertZ) { + for(Rectangle rect: rectangles) { + rect.drawCutin(dungeon, room, sx, sz, sdimx, sdimz, invertX, invertZ); + } + } + + + /** + * Adds a platform (or depression) of this shape. + * + * @param dungeon + * @param room + * @param floorY the new floor height + * @param sx the x coordinate + * @param sz the z coordinate + * @param sdimx the length on x + * @param sdimz the length on z + * @param invertX + * @param invertZ + */ + public void drawPlatform(Dungeon dungeon, Room room, byte floorY, + float sx, float sz, float sdimx, float sdimz, boolean invertX, boolean invertZ) { + for(Rectangle rect: rectangles) { + rect.drawPlatform(dungeon, room, floorY, sx, sz, sdimx, sdimz, invertX, invertZ); + } + } + + + + /***********************/ + /* Shapes */ + /***********************/ + + // Rectangle (Works) + public static final Shape simpleRect = new Shape(new Rectangle[]{simple}); + public static final Shape X = simpleRect; + public static final Shape[] xgroup = {X, X, X, X}; + + // 'L' (Works) + public static final Shape L000 = new Shape(new Rectangle[]{lback000, lbottom000}); + public static final Shape L090 = new Shape(new Rectangle[]{lback090, lbottom090}); + public static final Shape L180 = new Shape(new Rectangle[]{lback180, lbottom180}); + public static final Shape L270 = new Shape(new Rectangle[]{lback270, lbottom270}); + public static final Shape[] lgroup = {L000, L090, L180, L270}; + + // 'O' (Works) + public static final Shape O = new Shape(new Rectangle[]{obottom, oleft, oright, otop}); + public static final Shape[] ogroup = {O, O, O, O}; + + // 'T' (I think its working -- not sure out its orientation)... + public static final Shape T000 = new Shape(new Rectangle[]{ttop000, tbottom000}); + public static final Shape T090 = new Shape(new Rectangle[]{ttop090, tbottom090}); + public static final Shape T180 = new Shape(new Rectangle[]{ttop180, tbottom180}); + public static final Shape T270 = new Shape(new Rectangle[]{ttop270, tbottom270}); + public static final Shape[] tgroup = {T000, T090, T180, T270}; + + // 'F' (Working) + public static final Shape F000 = new Shape(new Rectangle[]{eback000, etop000, emiddle000}); + public static final Shape F090 = new Shape(new Rectangle[]{eback090, etop090, emiddle090}); + public static final Shape F180 = new Shape(new Rectangle[]{eback180, etop180, emiddle180}); + public static final Shape F270 = new Shape(new Rectangle[]{eback270, etop270, emiddle270}); + public static final Shape[] fgroup = {F000, F090, F180, F270}; + + // 'E' (Works) + public static final Shape E000 = new Shape(new Rectangle[]{eback000, etop000, emiddle000, ebottom000}); + public static final Shape E090 = new Shape(new Rectangle[]{eback090, etop090, emiddle090, ebottom090}); + public static final Shape E180 = new Shape(new Rectangle[]{eback180, etop180, emiddle180, ebottom180}); + public static final Shape E270 = new Shape(new Rectangle[]{eback270, etop270, emiddle270, ebottom270}); + public static final Shape[] egroup = {E000, E090, E180, E270}; + + // 'I' / 'H' (Working) + public static final Shape I000 = new Shape(new Rectangle[]{itop, imiddle, ibottom}); + public static final Shape I090 = new Shape(new Rectangle[]{ileft, imiddle, iright}); + public static final Shape I180 = I000; + public static final Shape I270 = I090; + public static final Shape[] igroup = {I000, I090, I180, I270}; + + // Plus-shape (Works) + public static final Shape CROSS = new Shape(new Rectangle[]{crosstop, crossmiddle, crossbottom}); + public static final Shape[] cgroup = {CROSS, CROSS, CROSS, CROSS}; + + // 'U' (Works) + public static final Shape U000 = new Shape(new Rectangle[]{uleft000, uright000, ubottom000}); + public static final Shape U090 = new Shape(new Rectangle[]{uleft090, uright090, ubottom090}); + public static final Shape U180 = new Shape(new Rectangle[]{uleft180, uright180, ubottom180}); + public static final Shape U270 = new Shape(new Rectangle[]{uleft270, uright270, ubottom270}); + public static final Shape[] ugroup = {U000, U090, U180, U270}; + + // 'S' (Works) + public static final Shape S000 = new Shape(new Rectangle[]{stop000, smiddle000, sbottom000, + sleft000, sright000}); + public static final Shape S090 = new Shape(new Rectangle[]{stop090, smiddle090, sbottom090, + sleft090, sright090}); + public static final Shape S180 = S000; + public static final Shape S270 = S090; + public static final Shape[] sgroup = {S000, S090, S180, S270}; + + + + public static final Shape[][] allshapes = {xgroup, lgroup, ogroup, tgroup, fgroup, + egroup, igroup, cgroup, ugroup, sgroup}; + + public static final Shape[][] allSolids = {xgroup, lgroup, tgroup, fgroup, + egroup, ugroup}; + + +} diff --git a/src/jaredbgreat/dldungeons/pieces/Shapes.java b/src/jaredbgreat/dldungeons/pieces/Shapes.java new file mode 100644 index 0000000..853faf9 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/Shapes.java @@ -0,0 +1,84 @@ +package jaredbgreat.dldungeons.pieces; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.planner.Symmetry; + +import java.util.EnumSet; +import java.util.Random; + +import static jaredbgreat.dldungeons.pieces.Shape.*; + + +/** + * Families of shapes, each representing a single shape in each of its rotations. + * + * Each enumeration constant has an associates Shape area from the shape class + * allows with minimum dimensions to hold the shape without loose details to + * rounding. + * + * This class also helps find a shape for a given symmetry class. + * + * @author Jared Blackburn + * + */ +public enum Shapes { + + X (1, 1, xgroup), + L (2, 2, lgroup), + O (3, 3, ogroup), + T (3, 3, tgroup), + F (4, 5, fgroup), + E (4, 5, egroup), + I (3, 3, igroup), + C (3, 3, cgroup), + U (3, 3, ugroup), + S (5, 5, sgroup); + + + public final int minx; + public final int miny; + public final Shape[] family; + + + Shapes(int minx, int miny, Shape[] family) { + this.minx = minx; + this.miny = miny; + this.family = family; + } + + + /** + * Will return a random shape that fits a given symmetry. + * + * @param sym + * @param random + * @return + */ + public static Shapes wholeShape(Symmetry sym, Random random) { + switch (sym) { + case NONE: + return sym.allPart[random.nextInt(sym.allPart.length)]; + case R: + case SW: + return sym.rotatedPart[random.nextInt(sym.rotatedPart.length)]; + case TR1: + case TR2: + return sym.transPart[random.nextInt(sym.transPart.length)]; + case X: + return sym.xsymmetricPart[random.nextInt(sym.xsymmetricPart.length)]; + case XZ: + return sym.xysymmetricPart[random.nextInt(sym.xysymmetricPart.length)]; + case Z: + return sym.ysymmetricPart[random.nextInt(sym.ysymmetricPart.length)]; + default: + return sym.allPart[random.nextInt(sym.allPart.length)]; + } + } + +} diff --git a/src/jaredbgreat/dldungeons/pieces/Spawner.java b/src/jaredbgreat/dldungeons/pieces/Spawner.java new file mode 100644 index 0000000..d52a98e --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/Spawner.java @@ -0,0 +1,63 @@ +package jaredbgreat.dldungeons.pieces; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +/** + * Represents a spawner that should be placed, including its location + * in xyz coordinates and the name of the mob to be spawned. + * + * @author Jared Blackburn + * + */ +public class Spawner { + + private final int x, y, z, room, level; + private final String mob; + + public Spawner(int x, int y, int z, int room, int level, String mob) { + this.x = x; + this.y = y; + this.z = z; + this.room = room; + this.level = level; + mob = mob.toUpperCase(); + mob = mob.replaceAll("MINECRAFT:", ""); + this.mob = mob; + + } + + + public int getX() { + return x; + } + + + public int getY() { + return y; + } + + + public int getZ() { + return z; + } + + + public int getRoom() { + return room; + } + + + public int getLevel() { + return level; + } + + + public String getMob() { + return mob; + } +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/pieces/chests/BasicChest.java b/src/jaredbgreat/dldungeons/pieces/chests/BasicChest.java new file mode 100644 index 0000000..d11a0b0 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/chests/BasicChest.java @@ -0,0 +1,122 @@ +package jaredbgreat.dldungeons.pieces.chests; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.ConfigHandler; +//import jaredbgreat.dldungeons.api.DLDEvent; +import jaredbgreat.dldungeons.builder.DBlock; +import java.util.Random; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.inventory.BlockInventoryHolder; +import org.bukkit.inventory.ItemStack; + +//import net.minecraft.item.ItemStack; +//import net.minecraft.tileentity.TileEntityChest; +//import net.minecraft.util.math.BlockPos; +//import net.minecraft.world.World; +//import net.minecraftforge.common.MinecraftForge; + +/** + * Represents a typical loot chest, including its coordinates and loot level. + * + * @author Jared Blackburn + * + */ +public class BasicChest { + + public int mx, my, mz; + protected int level; + private static int A1 = 2, B1 = 1, C1 = 2; + protected LootCategory category; + + + public BasicChest(int x, int y, int z, int level, LootCategory category) { + this.mx = x; + this.my = y; + this.mz = z; + this.level = level; + this.category = category; + } + + + /** + * This adds a tile entity to the chest, and then calls fillChest to fill it. + * The chest block is placed in the maps by Dungeon.addChestBlocks using + * DBlock.placeChest. + * + * @param world + * @param x + * @param y + * @param z + * @param random + */ + public void place(World world, int x, int y, int z, Random random) { + level += random.nextInt(2); + if(level >= LootCategory.LEVELS) level = LootCategory.LEVELS - 1; + if(world.getBlockAt(x, y, z).getType() != DBlock.chest) { + System.err.println("[DLDUNGEONS] ERROR! Trying to put loot into non-chest at " + + x + ", " + y + ", " + z + " (basic chest)."); + return; + } + Block contents = world.getBlockAt(x, y, z); + int which = random.nextInt(3); + switch (which) { + case 0: + fillChest(contents, LootType.HEAL, random); + break; + case 1: + fillChest(contents, LootType.GEAR, random); + break; + case 2: + fillChest(contents, LootType.RANDOM, random); + break; + } + + +// MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.AfterChestTileEntity(world, contents, which, x, y, z, random, level)); + + } + + + /** + * Fills the chest with loot of the specified kind (lootType). + * + * @param chest + * @param kind + * @param random + */ + protected void fillChest(Block chest, LootType kind, Random random) { + int num = random.nextInt(Math.max(2, A1 + (level / B1))) + C1; + for(int i = 0; i < num; i++) { + ItemStack treasure = category.getLoot(kind, level, random).getLoot(); + if(treasure != null) { + //chest.setInventorySlotContents(random.nextInt(27), treasure); + Chest bih = (Chest) chest.getState(); + bih.getInventory().setItem(random.nextInt(27), treasure); +// bih.update(true, false); + } + } + if(!ConfigHandler.vanillaLoot) { + ItemStack treasure = category.getLoot(LootType.LOOT, + Math.min(6, level), random).getLoot(); + if(treasure != null) { + //chest.setInventorySlotContents(random.nextInt(27), treasure); + Chest bih = (Chest) chest.getState(); + bih.getInventory().setItem(random.nextInt(27), treasure); +// bih.update(true, false); + } + } + } + + + public static void setBasicLootNumbers(int a, int b, int c) { + A1 = a; + B1 = b; + C1 = c; + } +} diff --git a/src/jaredbgreat/dldungeons/pieces/chests/LootCategory.java b/src/jaredbgreat/dldungeons/pieces/chests/LootCategory.java new file mode 100644 index 0000000..97a7288 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/chests/LootCategory.java @@ -0,0 +1,209 @@ +package jaredbgreat.dldungeons.pieces.chests; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import com.gmail.nossr50.util.ItemUtils; +import static jaredbgreat.dldungeons.pieces.chests.LootType.GEAR; +import static jaredbgreat.dldungeons.pieces.chests.LootType.HEAL; +import static jaredbgreat.dldungeons.pieces.chests.LootType.LOOT; + +import java.util.Random; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; + +//import net.minecraft.enchantment.EnchantmentHelper; +//import net.minecraft.init.Items; +//import net.minecraft.item.Item; +//import net.minecraft.item.ItemArmor; +//import net.minecraft.item.ItemBow; +//import net.minecraft.item.ItemStack; +//import net.minecraft.item.ItemSword; +//import net.minecraft.item.ItemTool; + +/** + * A representation of all available loot by type and level. This class + * is actually primarily responsible for selecting specific items of + * the requested type and level rather than for storage, though it + * does store arrays of LootList for use in the selection process. + * + * @author Jared Blackburn + * + */ +public class LootCategory { + + public static final int LEVELS = 7; + private final LootListSet lists; + public LootList[] gear; + public LootList[] heal; + public LootList[] loot; + + public LootCategory(LootListSet listset) { + lists = listset; + gear = new LootList[]{lists.gear1, lists.gear2, + lists.gear3, lists.gear4, lists.gear5, lists.gear6, lists.gear7}; + heal = new LootList[]{lists.heal1, lists.heal2, + lists.heal3, lists.heal4, lists.heal5, lists.heal6, lists.heal7}; + loot = new LootList[]{lists.loot1, lists.loot2, + lists.loot3, lists.loot4, lists.loot5, lists.loot6, lists.loot7}; + }; + + + + + /** + * Takes the loots type and level and returns an item stack of a random + * item fitting the type and level supplied. + * + * @param type + * @param level + * @param random + * @return + */ + public LootResult getLoot(LootType type, int level, Random random) { + if(level <= 6) { + level = Math.min(6, (level + random.nextInt(2) - random.nextInt(2))); + } + if(level < 0) level = 0; + switch(type) { + case GEAR: + if(random.nextBoolean()) { + return getEnchantedGear(level, random); + } else { + int l = Math.min(6, level); + return enchantedLowerLevel(gear[Math.min(6, l)].getLoot(random), l, random); + } + case HEAL: + int l = Math.min(6, level); + return new LootResult(heal[Math.min(6, l)].getLoot(random).getStack(random), l); + case LOOT: + if(level > 6) { + if(level > random.nextInt(100)) { + return new LootResult(lists.special.getLoot(random).getStack(random), 7); + } else { + level = 6; + } + } + if(random.nextInt(10) == 0) { + return getEnchantedBook(level, random); + } else { + return new LootResult(loot[level].getLoot(random).getStack(random), level); + } + case RANDOM: + default: + switch(random.nextInt(3)) { + case 0: + return getLoot(GEAR, level, random); + case 1: + return getLoot(HEAL, level, random); + case 2: + default: + return getLoot(LOOT, level, random); + } + } + } + + + /** + * Returns an item stack from the gear list with some of the items value + * (in terms of loot level) possibly converted to random enchantments and + * the remained used as the loot level of the item itself. + * + * @param lootLevel + * @param random + * @return + */ + private LootResult getEnchantedGear(int lootLevel, Random random) { + ItemStack out; + float portion = random.nextFloat() / 2f; + int lootPart = Math.min(6, Math.max(0, (int)((((float)lootLevel) * (1f - portion)) + 0.5f))); + LootItem item = gear[lootPart].getLoot(random); + int diff = lootLevel - item.level + 1; + int enchPart =Math.min((5 + (diff * (diff + 1) / 2) * 5), diff * 10); + if(enchPart >= 1 && isEnchantable(item)) { + out = item.getStack(random); + Enchantment randEnchant = Enchantment.values()[(int) (Math.random()*Enchantment.values().length)]; + try { + out.addEnchantment(randEnchant, 1); + } catch(IllegalArgumentException ex) { + + } +// out = EnchantmentHelper.addRandomEnchantment(random, out, enchPart, random.nextBoolean()); + } else { + return enchantedLowerLevel(gear[Math.min(6, lootLevel)].getLoot(random), lootLevel, random); + } + return new LootResult(out, Math.min(lootLevel, 6)); + } + + + /** + * Returns an item stack from the gear list with some of the items value + * (in terms of loot level) possibly converted to random enchantments and + * the remained used as the loot level of the item itself. + * + * @param lootLevel + * @param random + * @return + */ + private LootResult enchantedLowerLevel(LootItem item, int level, Random random) { + ItemStack out; + int diff = level - item.level; + if(isEnchantable(item) && (diff > random.nextInt(2))) { + int enchPart = Math.min((5 + (level * (level + 1) / 2) * 5), level * 10); + out = item.getStack(random); + Enchantment randEnchant = Enchantment.values()[(int) (Math.random()*Enchantment.values().length)]; + try { + out.addEnchantment(randEnchant, 1); + } catch(IllegalArgumentException ex) { + + } +// out = EnchantmentHelper.addRandomEnchantment(random, out, enchPart, random.nextBoolean()); + } else { + out = item.getStack(random); + } + return new LootResult(out, level); + } + + + /** + * True if the item is in a category that should be considered + * for possible enchantment. + * + * @param in + * @return + */ + private boolean isEnchantable(LootItem in) { + return ItemUtils.isEnchantable(new ItemStack(in.item, 1)); + } + + + /** + * Creates a random enchanted book and returns it as an ItemStack + * + * @param level + * @param random + * @return + */ + private LootResult getEnchantedBook(int level, Random random) { + ItemStack out = new ItemStack(Material.ENCHANTED_BOOK, 1); + Enchantment randEnchant = Enchantment.values()[(int) (Math.random()*Enchantment.values().length)]; + try { + out.addEnchantment(randEnchant, 1); + } catch(IllegalArgumentException ex) { + + } +// out = EnchantmentHelper.addRandomEnchantment(random, out, Math.min(30, (int)(level * 7.5)), true); + return new LootResult(out, Math.min(level, 6)); + } + + + public LootListSet getLists() { + return lists; + } +} + diff --git a/src/jaredbgreat/dldungeons/pieces/chests/LootHandler.java b/src/jaredbgreat/dldungeons/pieces/chests/LootHandler.java new file mode 100644 index 0000000..297ebb0 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/chests/LootHandler.java @@ -0,0 +1,51 @@ +package jaredbgreat.dldungeons.pieces.chests; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import java.util.HashMap; +import java.util.Map; + +public class LootHandler { + private static LootHandler handler; + private final Map categories; + + private LootHandler() { + categories = new HashMap<>(); + } + + + public static LootHandler getLootHandler() { + if(handler == null) { + handler = new LootHandler(); + } + return handler; + } + + + /** + * Creates and registers a new LootCategory using name as an identifier. + * + * @param name + * @return + */ + public LootCategory createCategory(String name) { + if(categories.containsKey(name)) { + System.err.println("[DLDUNGEONS] Warning: Trying to create Loot Category" + + name + " more than once!"); + return categories.get(name); + } + LootListSet listset = new LootListSet(); + LootCategory category = new LootCategory(listset); + categories.put(name, category); + return category; + } + + + public LootCategory getCategory(String name) { + return categories.get(name); + } + +} diff --git a/src/jaredbgreat/dldungeons/pieces/chests/LootItem.java b/src/jaredbgreat/dldungeons/pieces/chests/LootItem.java new file mode 100644 index 0000000..3d83080 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/chests/LootItem.java @@ -0,0 +1,403 @@ +package jaredbgreat.dldungeons.pieces.chests; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.ConfigHandler; +import jaredbgreat.dldungeons.parser.Tokenizer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Random; +import me.zhehe.Logging; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +//import net.minecraft.block.Block; +//import net.minecraft.item.Item; +//import net.minecraft.item.ItemStack; +//import net.minecraft.util.ResourceLocation; +//import net.minecraftforge.registries.IForgeRegistry; + + +/** + * A class to represent entries in loot tables. + * + * This stores an item for use as loot in terms of the Minecraft Item instance + * along with minimum and maximum quantities and the items damage value (or + * metadata in block terms). + * + * @author Jared Blackburn + * + */ +public class LootItem { +// private static IForgeRegistry ItemRegistry; + private static Map prototypes; + + Material item; + int min, max, meta, level; +// ArrayList nbtData; + + + private static class ItemPrototype { + public final Material item; + public final int meta; + public ItemPrototype(Material i, int m) { + item = i; + meta = m; + } + @Override + public boolean equals(Object obj) { + if(!(obj instanceof ItemPrototype)) { + return false; + } + ItemPrototype p = (ItemPrototype)obj; + return (p.item == item) && (p.meta == meta); + } + @Override + public int hashCode() { + return item.hashCode() + (meta * 102181); + } + } + + + static { + prototypes = new HashMap<>(); + } + + + /** + * Add the named item, where name is a string including the + * items name and an optional damage value. + * + * @param id + * @param min + * @param max + */ + public LootItem(String id, int min, int max, int level) { + metaParse(id); + if(min > max) min = max; + this.min = min; + this.max = max; + this.level = level; + if(item == null) { + String error = "[DLDUNGEONS] ERROR! Item read as \"" + id + + "\" was was not in registry (returned null)."; + Logging.logError(error); + if(ConfigHandler.failfast) { + throw new NoSuchElementException(error); + } + } else { + fixLevel(); + } + } + + + /** + * Create a LootItem using Item. + * + * @param item + * @param min + * @param max + */ + public LootItem(Material item, int min, int max) { + this.item = item; + if(min > max) min = max; + this.min = min; + this.max = max; + // For these items, don't care about level + this.level = 6; + } + + + /** + * Create a LootItem using a block + * + * @param item + * @param min + * @param max + */ +// public LootItem(Block item, int min, int max) { +// this.item = Item.getItemFromBlock(item); +// if(min > max) min = max; +// this.min = min; +// this.max = max; +// // For these items, don't care about level +// this.level = 6; +// } + + + private void fixLevel() { + // Only set level on non-stacked items like tools / weapons + if(max == 1) { + ItemPrototype p = new ItemPrototype(item, meta); + if(prototypes.containsKey(p)) { + int l = prototypes.get(p); + if(l < level) { + level = l; + } + if(l > level) { + prototypes.put(p, level); + } + } else { + prototypes.put(p, level); + } + } + } + + + + /** + * Parses its input string to set the values for item and meta + * (damage value). + * + * @param in + */ + private void metaParse(String in) { +// Tokenizer tokens = new Tokenizer(in, "({[]})"); +// String name = tokens.nextToken(); + in = in.toUpperCase(); + in = in.replace("MINECRAFT:", ""); + item = Material.valueOf(in); + if(item == null) { + Logging.logError("[DLDUNGEONS] ERROR! Item read as \"" + in + + "\" was was not in registry (returned null)."); + } +// if(tokens.hasMoreTokens()) { +// meta = Integer.parseInt(tokens.nextToken()); +// } + } + + private static Material getItem(String in) { + try { + return Material.valueOf("minecraft:" + in); + } catch (Exception ex) { + return Material.AIR; + } + } + + + /** + * This will parse an NBT tag from the chest.cfg and add it to the LootItem + * as an NbtTag object for later use in adding the tag to actual item stacks + * in chests. + * + * @param in + */ + public void addNbt(String in) { +// if(nbtData == null) { +// nbtData = new ArrayList(); +// } +// nbtData.add(NBTHelper.getTagFromLabel(in)); + } + + + /** + * Make the items NBT data a small as possible. + */ + public void trimNbt() { +// if(nbtData != null) { +// nbtData.trimToSize(); +// } + } + + + /** + * Returns a randomly sized ItemStack of the Item. + * + * @param random + * @return + */ + public ItemStack getStack(Random random) { + ItemStack out; + if(max <= min) { + if(item.isItem()) out = new ItemStack(item, max); + else out = new ItemStack(item, max); + } + else { + if(item.isItem()) + out = new ItemStack(item, random.nextInt(max - min) + min +1); + else + out = new ItemStack(item, random.nextInt(max - min) + min +1); + } +// if(out.getType() == null) { +// return null; +// } +// if(out.getHasSubtypes() && meta >= 0) { +// out.setItemDamage(meta); +// } else { +// out.setItemDamage(0); +// } +// if(nbtData != null && !nbtData.isEmpty()) { +// for(ITag tag: nbtData) { +// NBTHelper.setNbtTag(out, tag); +// } +// } + return out; + } + + + /*----------------------------------*/ + /* Default Loots Below */ + /*----------------------------------*/ + // Is this really necessary anymore? + + public static LootItem stoneSword + = new LootItem(Material.STONE_SWORD, 1, 1); + public static LootItem ironSword + = new LootItem(Material.IRON_SWORD, 1, 1); + public static LootItem diamondSword + = new LootItem(Material.DIAMOND_SWORD, 1, 1); + public static LootItem bow + = new LootItem(Material.BOW, 1, 1); + public static LootItem fewArrows + = new LootItem(Material.ARROW, 4, 12); + public static LootItem someArrows + = new LootItem(Material.ARROW, 8, 16); + public static LootItem manyArrows + = new LootItem(Material.ARROW, 16, 48); + + public static LootItem fewTorches + = new LootItem(Material.TORCH, 4, 12); + public static LootItem someToreches + = new LootItem(Material.TORCH, 12, 16); + public static LootItem manyTorches + = new LootItem(Material.TORCH, 16, 24); + + public static LootItem leatherHat + = new LootItem(getItem("leather_helmet"), 1, 1); + public static LootItem goldHat + = new LootItem(getItem("golden_helmet"), 1, 1); + public static LootItem ironHat + = new LootItem(getItem("iron_helmet"), 1, 1); + public static LootItem diamondHat + = new LootItem(getItem("diamond_helmet"), 1, 1); + public static LootItem leatherBoots + = new LootItem(getItem("leather_boots"), 1, 1); + public static LootItem goldBoots + = new LootItem(getItem("golden_boots"), 1, 1); + public static LootItem ironBoots + = new LootItem(getItem("iron_boots"), 1, 1); + public static LootItem diamondBoots + = new LootItem(getItem("diamond_boots"), 1, 1); + public static LootItem leatherPants + = new LootItem(getItem("leather_leggings"), 1, 1); + public static LootItem goldPants + = new LootItem(getItem("golden_leggings"), 1, 1); + public static LootItem ironPants + = new LootItem(getItem("iron_leggings"), 1, 1); + public static LootItem diamondPants + = new LootItem(getItem("diamond_leggings"), 1, 1); + public static LootItem leatherChest + = new LootItem(getItem("leather_chestplate"), 1, 1); + public static LootItem goldChest + = new LootItem(getItem("golden_chestplate"), 1, 1); + public static LootItem ironChest + = new LootItem(getItem("iron_chestplate"), 1, 1); + public static LootItem diamondChest + = new LootItem(getItem("diamond_chestplate"), 1, 1); + + public static LootItem someBread + = new LootItem(getItem("bread"), 2, 4); + public static LootItem moreBread + = new LootItem(getItem("bread"), 4, 8); + public static LootItem someSteak + = new LootItem(getItem("cooked_beef"), 2, 4); + public static LootItem moreSteak + = new LootItem(getItem("cooked_beef"), 4, 8); + public static LootItem someChicken + = new LootItem(getItem("cooked_chicken"), 2, 4); + public static LootItem moreChicken + = new LootItem(getItem("cooked_chicken"), 4, 8); + public static LootItem someApples + = new LootItem(getItem("apple"), 1, 3); + public static LootItem moreApples + = new LootItem(getItem("apple"), 2, 7); + public static LootItem somePie + = new LootItem(getItem("pumpkin_pie"), 1, 3); + public static LootItem morePie + = new LootItem(getItem("pumpkin_pie"), 2, 7); + public static LootItem goldApple + = new LootItem(getItem("golden_apple"), 1, 1); + public static LootItem goldApples + = new LootItem(getItem("golden_apple"), 1, 3); + + public static LootItem oneGold + = new LootItem(getItem("gold_ingot"), 1, 1); + public static LootItem someGold + = new LootItem(getItem("gold_ingot"), 2, 5); + public static LootItem moreGold + = new LootItem(getItem("gold_ingot"), 3, 8); + public static LootItem someIron + = new LootItem(getItem("iron_ingot"), 1, 8); + public static LootItem moreIron + = new LootItem(getItem("iron_ingot"), 3, 12); + public static LootItem oneDiamond + = new LootItem(getItem("iron_ingot"), 1, 1); + public static LootItem diamonds + = new LootItem(getItem("diamond"), 1, 4); + public static LootItem manyDiamonds + = new LootItem(getItem("diamond"), 3, 9); + public static LootItem oneEmerald + = new LootItem(getItem("emerald"), 1, 1); + public static LootItem emeralds + = new LootItem(getItem("emerald"), 1, 4); + public static LootItem manyEmerald + = new LootItem(getItem("emerald"), 3, 7); + + public static LootItem saddle + = new LootItem(getItem("saddle"), 1, 1); + public static LootItem ironBarding + = new LootItem(getItem("iron_horse_armor"), 1, 1); + public static LootItem goldBarding + = new LootItem(getItem("golden_horse_armor"), 1, 1); + public static LootItem diamondBard + = new LootItem(getItem("diamond_horse_armor"), 1, 1); + + public static LootItem book + = new LootItem(getItem("book"), 1, 1); + public static LootItem someBooks + = new LootItem(Material.BOOK, 2, 5); + public static LootItem moreBooks + = new LootItem(Material.BOOK, 3, 8); + public static LootItem nameTag + = new LootItem(Material.NAME_TAG, 1, 1); + public static LootItem enderpearl + = new LootItem(getItem("ender_pearl"), 1, 2); + public static LootItem enderpearls + = new LootItem(getItem("ender_pearl"), 1, 9); + public static LootItem eyeOfEnder + = new LootItem(getItem("ender_eye"), 1, 2); + public static LootItem blazeRod + = new LootItem(Material.BLAZE_ROD, 1, 2); + public static LootItem netherstar + = new LootItem(Material.NETHER_STAR, 1, 1); + + public static LootItem disc13 + = new LootItem(Material.MUSIC_DISC_13, 1, 1); + public static LootItem discCat + = new LootItem(Material.MUSIC_DISC_CAT, 1, 1); + public static LootItem discBlocks + = new LootItem(Material.MUSIC_DISC_BLOCKS, 1, 1); + public static LootItem discChirp + = new LootItem(Material.MUSIC_DISC_CHIRP, 1, 1); + public static LootItem discFar + = new LootItem(Material.MUSIC_DISC_FAR, 1, 1); + public static LootItem discMall + = new LootItem(Material.MUSIC_DISC_MALL, 1, 1); + public static LootItem discMellohi + = new LootItem(Material.MUSIC_DISC_MELLOHI, 1, 1); + public static LootItem discStrad + = new LootItem(Material.MUSIC_DISC_STRAD, 1, 1); + public static LootItem discWard + = new LootItem(Material.MUSIC_DISC_WARD, 1, 1); + public static LootItem disc11 + = new LootItem(Material.MUSIC_DISC_11, 1, 1); + public static LootItem discWait + = new LootItem(Material.MUSIC_DISC_WAIT, 1, 1); +} diff --git a/src/jaredbgreat/dldungeons/pieces/chests/LootList.java b/src/jaredbgreat/dldungeons/pieces/chests/LootList.java new file mode 100644 index 0000000..4b966c3 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/chests/LootList.java @@ -0,0 +1,69 @@ +package jaredbgreat.dldungeons.pieces.chests; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + + +//import net.minecraft.block.Block; +//import net.minecraft.item.Item; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.*; +import java.util.ArrayList; +import java.util.Random; +import org.bukkit.Material; + + +/** + * A list of loot items for a particular type and level. This class also + * contains static LootList members to statically hold all the loot used by + * the mod. + * + * @author Jared Blackburn + * + */ +public class LootList extends ArrayList{ + ArrayList dummy = new ArrayList(); + + + /** + * Add the item, converting it to a LootItem. + * + * @param item + * @param min + * @param max + * @param prob + */ + public void add(Material item, int min, int max, int prob) { + add(new LootItem(item, min, max)); + } + + + /** + * Returns a random item (as a LootItem) stored in the list. + * + * @param random + * @return + */ + public LootItem getLoot(Random random) { + LootItem out; + if(isEmpty()) return null; + // Done with removal now to somewhat increase randomness + if(dummy.isEmpty() || random.nextInt(size()) > dummy.size()) { + dummy.clear(); + dummy.addAll(this); + } + int which = random.nextInt(dummy.size()); + out = dummy.get(which); + dummy.remove(which); + return out; + } + + + + + + +} diff --git a/src/jaredbgreat/dldungeons/pieces/chests/LootListSet.java b/src/jaredbgreat/dldungeons/pieces/chests/LootListSet.java new file mode 100644 index 0000000..b0fad63 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/chests/LootListSet.java @@ -0,0 +1,421 @@ +package jaredbgreat.dldungeons.pieces.chests; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import static jaredbgreat.dldungeons.pieces.chests.LootItem.blazeRod; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.book; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.bow; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.diamondBoots; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.diamondChest; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.diamondHat; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.diamondPants; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.diamondSword; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.diamonds; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.disc11; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.disc13; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.discBlocks; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.discCat; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.discChirp; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.discFar; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.discMall; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.discMellohi; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.discStrad; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.discWait; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.discWard; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.emeralds; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.enderpearls; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.eyeOfEnder; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.fewArrows; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.fewTorches; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.goldApple; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.goldApples; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.ironBoots; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.ironChest; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.ironHat; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.ironPants; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.ironSword; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.leatherBoots; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.leatherChest; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.leatherHat; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.leatherPants; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.manyArrows; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.manyTorches; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.moreApples; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.moreBooks; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.moreBread; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.moreChicken; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.moreGold; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.moreIron; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.morePie; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.moreSteak; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.netherstar; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.oneDiamond; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.oneEmerald; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.oneGold; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.someApples; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.someArrows; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.someBooks; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.someBread; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.someChicken; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.someGold; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.someIron; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.somePie; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.someSteak; +import static jaredbgreat.dldungeons.pieces.chests.LootItem.stoneSword; + +/** + * Not a set in the mathematical sense, just in the common English + * sense. This represents a grouping of loot types relating to a + * single loot config file (e.g., chest.cfg). That is a certain + * type of loots that might exist in a given dungeon. + * + * @author Jared Blackburn + */ +public class LootListSet { + + LootList gear1 = new LootList(); + LootList gear2 = new LootList(); + LootList gear3 = new LootList(); + LootList gear4 = new LootList(); + LootList gear5 = new LootList(); + LootList gear6 = new LootList(); + LootList gear7 = new LootList(); + + LootList heal1 = new LootList(); + LootList heal2 = new LootList(); + LootList heal3 = new LootList(); + LootList heal4 = new LootList(); + LootList heal5 = new LootList(); + LootList heal6 = new LootList(); + LootList heal7 = new LootList(); + + LootList loot1 = new LootList(); + LootList loot2 = new LootList(); + LootList loot3 = new LootList(); + LootList loot4 = new LootList(); + LootList loot5 = new LootList(); + LootList loot6 = new LootList(); + LootList loot7 = new LootList(); + + LootList discs = new LootList(); + LootList special = new LootList(); + + + /** + * Adds default loot for use if chest config cannot be found or created. + * + * In addition, this also performs some pre-game initialization, specifically + * populating the TreasureChest's slots list with Integers from 0 to 26. + */ + public void addDefaultLoot() { + gear1.add(stoneSword); + gear1.add(leatherHat); + gear1.add(leatherPants); + gear1.add(leatherBoots); + gear1.add(leatherChest); + gear1.add(fewArrows); + gear1.add(fewTorches); + + gear2.add(stoneSword); + gear2.add(ironSword); + gear2.add(bow); + gear2.add(leatherHat); + gear2.add(leatherPants); + gear2.add(leatherBoots); + gear2.add(leatherChest); + gear2.add(ironHat); + gear2.add(ironPants); + gear2.add(ironBoots); + gear2.add(ironChest); + gear2.add(fewArrows); + gear2.add(fewTorches); + + gear3.add(ironSword); + gear3.add(bow); + gear3.add(ironHat); + gear3.add(ironPants); + gear3.add(ironBoots); + gear3.add(ironChest); + gear3.add(fewArrows); + gear3.add(fewTorches); + gear3.add(someArrows); + gear3.add(manyTorches); + + gear4.add(ironSword); + gear4.add(diamondSword); + gear4.add(bow); + gear4.add(ironHat); + gear4.add(ironPants); + gear4.add(ironBoots); + gear4.add(ironChest); + gear4.add(diamondHat); + gear4.add(diamondPants); + gear4.add(diamondBoots); + gear4.add(diamondChest); + gear4.add(fewArrows); + gear4.add(fewTorches); + gear4.add(someArrows); + gear4.add(manyTorches); + + gear5.add(diamondSword); + gear5.add(diamondHat); + gear5.add(diamondPants); + gear5.add(diamondBoots); + gear5.add(diamondChest); + gear5.add(fewArrows); + gear5.add(fewTorches); + gear5.add(someArrows); + gear5.add(manyTorches); + + gear6.add(diamondSword); + gear6.add(diamondHat); + gear6.add(diamondPants); + gear6.add(diamondBoots); + gear6.add(diamondChest); + gear6.add(manyArrows); + gear6.add(someArrows); + gear6.add(manyTorches); + + gear7.add(diamondSword); + gear7.add(diamondHat); + gear7.add(diamondPants); + gear7.add(diamondBoots); + gear7.add(diamondChest); + gear7.add(manyArrows); + gear7.add(manyTorches); + + heal1.add(someBread); + + heal2.add(someBread); + heal2.add(someApples); + heal2.add(someChicken); + + heal3.add(moreBread); + heal3.add(someApples); + heal2.add(someChicken); + heal3.add(someSteak); + heal3.add(goldApple); + + heal4.add(moreBread); + heal4.add(someApples); + heal4.add(moreApples); + heal4.add(someChicken); + heal4.add(moreChicken); + heal4.add(someSteak); + heal4.add(goldApple); + + heal5.add(moreBread); + heal5.add(somePie); + heal5.add(moreApples); + heal5.add(someChicken); + heal5.add(moreChicken); + heal5.add(someSteak); + heal5.add(moreSteak); + heal5.add(goldApple); + heal5.add(goldApples); + + heal6.add(somePie); + heal6.add(moreApples); + heal6.add(morePie); + heal6.add(moreSteak); + heal6.add(goldApple); + heal6.add(goldApples); + + heal7.add(moreApples); + heal7.add(moreSteak); + heal7.add(goldApple); + heal7.add(goldApples); + + loot1.add(someIron); + loot1.add(oneGold); + loot1.add(book); + loot1.add(someApples); + loot1.add(ironSword); + + loot2.add(book); + loot2.add(someBooks); + loot2.add(someIron); + loot2.add(oneGold); + loot2.add(someGold); + + loot3.add(someBooks); + loot3.add(someGold); + loot3.add(oneDiamond); + loot3.add(moreIron); + loot3.add(oneEmerald); + + loot4.add(goldApple); + loot4.add(blazeRod); + loot4.add(moreBooks); + loot4.add(enderpearls); + loot4.add(moreIron); + loot4.add(someGold); + loot4.add(oneDiamond); + loot4.add(diamonds); + loot4.add(oneEmerald); + loot4.add(emeralds); + + loot5.add(moreBooks); + loot5.add(blazeRod); + loot5.add(goldApple); + loot5.add(eyeOfEnder); + loot5.add(enderpearls); + loot5.add(moreIron); + loot5.add(moreGold); + loot5.add(diamonds); + loot5.add(oneEmerald); + loot5.add(emeralds); + + loot6.add(moreBooks); + loot6.add(eyeOfEnder); + loot6.add(enderpearls); + loot6.add(goldApples); + loot6.add(moreIron); + loot6.add(moreGold); + loot6.add(diamonds); + loot6.add(emeralds); + + loot7.add(moreGold); + loot7.add(diamonds); + loot7.add(emeralds); + loot7.add(eyeOfEnder); + loot7.add(goldApple); + + special.add(discBlocks); + special.add(discChirp); + special.add(discFar); + special.add(discMall); + special.add(discMellohi); + special.add(discStrad); + special.add(discWard); + special.add(disc11); + special.add(discWait); + special.add(netherstar); + special.add(goldApples); + + addDiscs(); + TreasureChest.initSlots(); + } + + + /** + * Creates the hard-coded list of discs to give as trophies in some + * treasure chests. + */ + // Should this, perhaps, be replaced with a configurable "trophies" list? + public void addDiscs() { + discs.add(disc13); + discs.add(discCat); + discs.add(discBlocks); + discs.add(discChirp); + discs.add(discFar); + discs.add(discMall); + discs.add(discMellohi); + discs.add(discStrad); + discs.add(discWard); + discs.add(disc11); + discs.add(discWait); + } + + + /** + * Adds the item to the one of the LootLists, assigning it + * the type and level in the process. + * + * The item will be converted to a LootItm in the process of being added. + * + * @param item + * @param type + * @param level + */ + public void addItem(LootItem item, String type, int level) { + if(type.equals("gear")) { + switch(level) { + case 0: + case 1: + gear1.add(item); + break; + case 2: + gear2.add(item); + break; + case 3: + gear3.add(item); + break; + case 4: + gear4.add(item); + break; + case 5: + gear5.add(item); + break; + case 6: + gear6.add(item); + break; + case 7: + gear7.add(item); + break; + default: + special.add(item); + break; + } + } else if(type.equals("heal")) { + switch(level) { + case 0: + case 1: + heal1.add(item); + break; + case 2: + heal2.add(item); + break; + case 3: + heal3.add(item); + break; + case 4: + heal4.add(item); + break; + case 5: + heal5.add(item); + break; + case 6: + heal6.add(item); + break; + case 7: + heal7.add(item); + break; + default: + special.add(item); + break; + } + } else { + switch(level) { + case 0: + case 1: + loot1.add(item); + break; + case 2: + loot2.add(item); + break; + case 3: + loot3.add(item); + break; + case 4: + loot4.add(item); + break; + case 5: + loot5.add(item); + break; + case 6: + loot6.add(item); + break; + case 7: + loot7.add(item); + break; + default: + special.add(item); + break; + } + } + } +} diff --git a/src/jaredbgreat/dldungeons/pieces/chests/LootResult.java b/src/jaredbgreat/dldungeons/pieces/chests/LootResult.java new file mode 100644 index 0000000..797c1ef --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/chests/LootResult.java @@ -0,0 +1,26 @@ +package jaredbgreat.dldungeons.pieces.chests; + +//import net.minecraft.item.ItemStack; + +import org.bukkit.inventory.ItemStack; + + +public class LootResult { + final ItemStack result; + final int level; + + LootResult(ItemStack item, int l) { + result = item; + level = l; + } + + + public ItemStack getLoot() { + return result; + } + + + public int getLevel() { + return level; + } +} diff --git a/src/jaredbgreat/dldungeons/pieces/chests/LootType.java b/src/jaredbgreat/dldungeons/pieces/chests/LootType.java new file mode 100644 index 0000000..5bc56ba --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/chests/LootType.java @@ -0,0 +1,26 @@ +package jaredbgreat.dldungeons.pieces.chests; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +/** + * The three types of loot for chests: + * + *
    + *
  1. GEAR: armor / weapons / tools that are useful combat or dungeoneering
  2. + *
  3. HEAL: health items (usually food)
  4. + *
  5. LOOT: Treasure items (or junk at low levels)
  6. + *
+ * + * This also includes RANDOM, selecting any of the above three randomly. * + * + * @author Jared Blackburn * + */ +public enum LootType { + GEAR, + HEAL, + LOOT, + RANDOM; +} diff --git a/src/jaredbgreat/dldungeons/pieces/chests/TreasureChest.java b/src/jaredbgreat/dldungeons/pieces/chests/TreasureChest.java new file mode 100644 index 0000000..8b85d55 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/chests/TreasureChest.java @@ -0,0 +1,144 @@ +package jaredbgreat.dldungeons.pieces.chests; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.ConfigHandler; +import jaredbgreat.dldungeons.builder.DBlock; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Random; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.inventory.ItemStack; + +//import net.minecraft.item.ItemStack; +//import net.minecraft.tileentity.TileEntityChest; +//import net.minecraft.util.math.BlockPos; +//import net.minecraft.world.World; + +/** + * This represents the treasure chests found in destination nodes + * (a.k.a., "boss rooms"). Each should have some of all three loot + * types, generally of a high level. + * + * @author Jared Blackburn + * + */ +public class TreasureChest extends BasicChest { + + private static int A2 = 3, B2 = 2, C2 = 2; + + private boolean withBoss; + static ArrayList slots = new ArrayList(); + int slot; + + public TreasureChest(int x, int y, int z, int level, LootCategory category) { + super(x, y, z, level, category); + } + + private static void addToInventory(Block chest, int index, ItemStack item) { + Chest bih = (Chest) chest.getState(); + bih.getInventory().setItem(index, item); +// bih.update(true, false); + } + + /** + * This will place some loot of every each type, being sure to use + * a separate random slot for each item so that none are overwritten. + */ + @Override + public void place(World world, int x, int y, int z, Random random) { + Location pos = new Location(world, x, y, z); + Collections.shuffle(slots, random); + slot = 0; + level += random.nextInt(2); + if(level >= LootCategory.LEVELS) level = LootCategory.LEVELS - 1; + ItemStack treasure; + if(world.getBlockAt(pos).getType() != DBlock.chest) { + System.err.println("[DLDUNGEONS] ERROR! Trying to put loot into non-chest at " + + x + ", " + y + ", " + z + " (treasure chest)."); + return; + } + Block contents = world.getBlockAt(pos); +// TileEntityChest contents = (TileEntityChest)world.getTileEntity(pos); + int num; + num = random.nextInt(Math.max(2, A2 + (level / B2))) + C2; + for(int i = 0; i < num; i++) { + treasure = category.getLoot(LootType.HEAL, level, random).getLoot(); + addToInventory(contents, slots.get(slot).intValue(), treasure); +// contents.setInventorySlotContents(slots.get(slot).intValue(), treasure); + slot++; + } + num = random.nextInt(Math.max(2, A2 + (level / B2))) + C2; + for(int i = 0; i < num; i++) { + treasure = category.getLoot(LootType.GEAR, level, random).getLoot(); + addToInventory(contents, slots.get(slot).intValue(), treasure); +// contents.setInventorySlotContents(slots.get(slot).intValue(), treasure); + slot++; + } + num = random.nextInt(Math.max(2, A2 + (level / B2))) + C2; + for(int i = 0; i < num; i++) { + LootResult lootResult = category.getLoot(LootType.LOOT, + level + 1 + random.nextInt(2), random); + treasure = lootResult.getLoot(); + addToInventory(contents, slots.get(slot).intValue(), treasure); +// contents.setInventorySlotContents(slots.get(slot).intValue(), treasure); + if((lootResult.getLevel() > 6) && !withBoss) { + level--; + } + slot++; + } + if(random.nextInt(7) < level) { + if(level >= 6) { + treasure = category.getLists().special.getLoot(random).getStack(random); + addToInventory(contents, slots.get(slot).intValue(), treasure); +// contents.setInventorySlotContents(slots.get(slot).intValue(), treasure); + slot++; + if(random.nextBoolean()) { + treasure = category.getLists().discs.getLoot(random).getStack(random); + addToInventory(contents, slots.get(slot).intValue(), treasure); +// contents.setInventorySlotContents(slots.get(slot).intValue(), treasure); + slot++; + } + } else { + treasure = category.getLists().discs.getLoot(random).getStack(random); + addToInventory(contents, slots.get(slot).intValue(), treasure); +// contents.setInventorySlotContents(slots.get(slot).intValue(), treasure); + slot++; + } + } + } + + + public TreasureChest setWithBoss(boolean bossRoom) { + withBoss = bossRoom; + return this; + } + + + /** + * Returns true if a the slot is a valid part of a chests inventory. + * + * @param slot + * @return + */ + private boolean validSlot(int slot) { + return ((slot >= 0) && (slot < 27)); + } + + + /** + * Initializes the slots list, which is shuffled to randomize item location in + * the chest without the risk of over writing one item with the another. Called + * nut LootList.addDefaultLoot to populate the list. + */ + public static void initSlots() { + for(int i = 0; i < 27; i++) slots.add(new Integer(i)); + } +} diff --git a/src/jaredbgreat/dldungeons/pieces/chests/WeakChest.java b/src/jaredbgreat/dldungeons/pieces/chests/WeakChest.java new file mode 100644 index 0000000..db8a7d4 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/chests/WeakChest.java @@ -0,0 +1,53 @@ +package jaredbgreat.dldungeons.pieces.chests; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +//import jaredbgreat.dldungeons.ConfigHandler; +import jaredbgreat.dldungeons.builder.DBlock; + +import java.util.Random; +import org.bukkit.Location; + +//import net.minecraft.tileentity.TileEntityChest; +//import net.minecraft.util.math.BlockPos; +//import net.minecraft.world.World; +import org.bukkit.World; +import org.bukkit.block.Block; + +/** + * Represents a weak / junk chest found in rooms without spawners and containing + * small amounts of starter materials. + * + * @author Jared Blackburn + * + */ +public class WeakChest extends BasicChest { + + + public WeakChest(int x, int y, int z, LootCategory category) { + super(x, y, z, 0, category); + } + + @Override + public void place(World world, int x, int y, int z, Random random) { + Location pos = new Location(world, x, y, z); + Block contents = world.getBlockAt(pos); + Block block = world.getBlockAt(pos); + if(block.getType() != DBlock.chest) { + System.err.println("[DLDUNGEONS] ERROR! Trying to put loot into non-chest at " + + x + ", " + y + ", " + z + " (basic chest)."); + return; + } + if(random.nextBoolean()) { + if(random.nextBoolean()) fillChest(contents, LootType.GEAR, random); + else fillChest(contents, LootType.HEAL, random); + } else { + fillChest(contents, LootType.GEAR, random); + fillChest(contents, LootType.HEAL, random); + } + } + +} diff --git a/src/jaredbgreat/dldungeons/pieces/entrances/AbstractEntrance.java b/src/jaredbgreat/dldungeons/pieces/entrances/AbstractEntrance.java new file mode 100644 index 0000000..afbfe5c --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/entrances/AbstractEntrance.java @@ -0,0 +1,46 @@ +package jaredbgreat.dldungeons.pieces.entrances; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +/** + * The base class for all that build entrances. + */ +import jaredbgreat.dldungeons.planner.Dungeon; +import org.bukkit.Material; +import org.bukkit.World; +//import net.minecraft.block.Block; +//import net.minecraft.world.World; + +public abstract class AbstractEntrance { + + protected static final Material ladder + = Material.LADDER; + protected static final Material stairSlab + = Material.STONE_SLAB; + + int x, z; + + /** + * Set an entrance to be built at the given coordinates. + * + * @param x + * @param z + */ + public AbstractEntrance(int x, int z) { + this.x = x; + this.z = z; + } + + + /** + * Build the entrance to the given dungeon in the given world. + * + * @param dungeon + * @param world + */ + public abstract void build(Dungeon dungeon, World world); +} diff --git a/src/jaredbgreat/dldungeons/pieces/entrances/SimpleEntrance.java b/src/jaredbgreat/dldungeons/pieces/entrances/SimpleEntrance.java new file mode 100644 index 0000000..3fe2efb --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/entrances/SimpleEntrance.java @@ -0,0 +1,60 @@ +package jaredbgreat.dldungeons.pieces.entrances; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.builder.DBlock; +import jaredbgreat.dldungeons.planner.Dungeon; +import static me.zhehe.Constant.*; +import org.bukkit.World; +//import net.minecraft.world.World; + +public class SimpleEntrance extends AbstractEntrance { + + public SimpleEntrance(int x, int z) { + super(x, z); + } + + @Override + public void build(Dungeon dungeon, World world) { + int wx = x + (dungeon.map.chunkX * 16) - (dungeon.map.room.length / 2) + 8; + int wz = z + (dungeon.map.chunkZ * 16) - (dungeon.map.room.length / 2) + 8; + int bottom = dungeon.map.floorY[x][z]; + int top = world.getMaxHeight(); + while(!DBlock.isGroundBlock(world, wx, top, wz)) top--; + top++; + int side = dungeon.random.nextInt(4); + switch (side) { + case 0: + for(int i = bottom; i <= top; i++) { + DBlock.place(world, wx, i, wz, dungeon.wallBlock1); + DBlock.placeBlock(world, wx + 1, i, wz, ladder5); + } + break; + case 1: + for(int i = bottom; i <= top; i++) { + DBlock.place(world, wx, i, wz, dungeon.wallBlock1); + DBlock.placeBlock(world, wx, i, wz + 1, ladder3); + } + break; + case 2: + for(int i = bottom; i <= top; i++) { + DBlock.place(world, wx, i, wz, dungeon.wallBlock1); + DBlock.placeBlock(world, wx - 1, i, wz, ladder4); + } + break; + case 3: + for(int i = bottom; i <= top; i++) { + DBlock.place(world, wx, i, wz, dungeon.wallBlock1); + DBlock.placeBlock(world, wx, i, wz - 1, ladder2); + } + break; + } + + } + +} diff --git a/src/jaredbgreat/dldungeons/pieces/entrances/SpiralStair.java b/src/jaredbgreat/dldungeons/pieces/entrances/SpiralStair.java new file mode 100644 index 0000000..1a8408f --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/entrances/SpiralStair.java @@ -0,0 +1,88 @@ +package jaredbgreat.dldungeons.pieces.entrances; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.builder.DBlock; +import jaredbgreat.dldungeons.planner.Dungeon; +import static me.zhehe.Constant.*; +import org.bukkit.World; +//import net.minecraft.block.Block; +//import net.minecraft.world.World; + + +public class SpiralStair extends AbstractEntrance { + + + public SpiralStair(int x, int z) { + super(x, z); + } + + + @Override + public void build(Dungeon dungeon, World world) { + int wx = x + (dungeon.map.chunkX * 16) - (dungeon.map.room.length / 2) + 8; + int wz = z + (dungeon.map.chunkZ * 16) - (dungeon.map.room.length / 2) + 8; + int bottom = dungeon.map.floorY[x][z]; + int top = world.getMaxHeight(); + //int top = world.getChunkFromChunkCoords(wx / 16, wz / 16).getHeight(wx, wz); + while(!DBlock.isGroundBlock(world, wx, top, wz)) top--; + top++; + int side = dungeon.random.nextInt(4); + for(int i = bottom; i < top; i++) { + int sx, sz; + DBlock.place(world, wx, i, wz, dungeon.wallBlock1); + switch (side) { + case 0: + DBlock.placeBlock(world, wx+1, i, wz, slab0); + DBlock.placeBlock(world, wx+1, i, wz+1, slab8); + // Empty space + DBlock.deleteBlock(world, wx, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz); + DBlock.deleteBlock(world, wx-1, i, wz-1); + DBlock.deleteBlock(world, wx, i, wz-1); + DBlock.deleteBlock(world, wx+1, i, wz-1); + break; + case 1: + DBlock.placeBlock(world, wx, i, wz+1, slab0); + DBlock.placeBlock(world, wx-1, i, wz+1, slab8); + // Empty space + DBlock.deleteBlock(world, wx+1, i, wz); + DBlock.deleteBlock(world, wx+1, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz); + DBlock.deleteBlock(world, wx-1, i, wz-1); + DBlock.deleteBlock(world, wx, i, wz-1); + DBlock.deleteBlock(world, wx+1, i, wz-1); + break; + case 2: + DBlock.placeBlock(world, wx-1, i, wz, slab0); + DBlock.placeBlock(world, wx-1, i, wz-1, slab8); + // Empty space + DBlock.deleteBlock(world, wx+1, i, wz); + DBlock.deleteBlock(world, wx+1, i, wz+1); + DBlock.deleteBlock(world, wx, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz+1); + DBlock.deleteBlock(world, wx, i, wz-1); + DBlock.deleteBlock(world, wx+1, i, wz-1); + break; + case 3: + DBlock.placeBlock(world, wx, i, wz-1, slab0); + DBlock.placeBlock(world, wx+1, i, wz-1, slab8); + // Empty space + DBlock.deleteBlock(world, wx+1, i, wz); + DBlock.deleteBlock(world, wx+1, i, wz+1); + DBlock.deleteBlock(world, wx, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz); + DBlock.deleteBlock(world, wx-1, i, wz-1); + break; + } + side = (side + 1) % 4; + } + } + +} diff --git a/src/jaredbgreat/dldungeons/pieces/entrances/TopRoom.java b/src/jaredbgreat/dldungeons/pieces/entrances/TopRoom.java new file mode 100644 index 0000000..ac95789 --- /dev/null +++ b/src/jaredbgreat/dldungeons/pieces/entrances/TopRoom.java @@ -0,0 +1,332 @@ +package jaredbgreat.dldungeons.pieces.entrances; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.builder.DBlock; +import jaredbgreat.dldungeons.planner.Dungeon; +import static me.zhehe.Constant.*; +import org.bukkit.World; +//import net.minecraft.block.Block; +//import net.minecraft.world.World; + + +/** + * An entrance with a small, one-room building, either complete or as a ruin, + * at the top. + * + * @author Jared Blackburn + * + */ +public class TopRoom extends AbstractEntrance { + int wx, wz, bottom, top, xdim, ydim, zdim, ymod, xmin, xmax, zmin, zmax, below; + + public TopRoom(int x, int z) { + super(x, z); + + } + + + @Override + public void build(Dungeon dungeon, World world) { + //DoomlikeDungeons.profiler.startTask("Generating Top Room Numbers (TopRoom)"); + wx = x + (dungeon.map.chunkX * 16) - (dungeon.map.room.length / 2) + 8; + wz = z + (dungeon.map.chunkZ * 16) - (dungeon.map.room.length / 2) + 8; + bottom = dungeon.map.floorY[x][z]; + top = world.getMaxHeight(); + while(!DBlock.isGroundBlock(world, wx, top, wz)) top--; + xdim = dungeon.random.nextInt(7) + 6; + zdim = dungeon.random.nextInt(7) + 6; + ymod = (xdim <= zdim) ? (int) Math.sqrt(xdim) : (int) Math.sqrt(zdim); + ydim = dungeon.random.nextInt((dungeon.verticle.value / 2) + (ymod / 2) + 2) + 2; + + xmin = wx - (xdim / 2); + xmax = wx + (xdim / 2); + zmin = wz - (zdim / 2); + zmax = wz + (zdim / 2); + //DoomlikeDungeons.profiler.endTask("Generating Top Room Numbers (TopRoom)"); + + // Build a small building over the entrance + if(dungeon.random.nextBoolean() || dungeon.degeneracy.use(dungeon.random)) + buildRuin(dungeon, world); + else buidBuilding(dungeon, world); + + // Build the actual way in + if(dungeon.random.nextBoolean()) buildLatter(world, dungeon); + else buildStair(world, dungeon); + } + + + + + ////////////////////////////////////////////////////////////////////////// + // Building The Upper Ruin // + ////////////////////////////////////////////////////////////////////////// + + + /** + * Build a complete / intact building, consisting of one room in the + * shape of a rectangular solid. This will also fill in a any areas + * between the room and ground so that it doesn't float. + * + * @param dungeon + * @param world + */ + private void buidBuilding(Dungeon dungeon, World world) { + //DoomlikeDungeons.profiler.startTask("Generating Building (TopRoom)"); + //DoomlikeDungeons.profiler.startTask("Generating Floor (TopRoom)"); + for(int i = xmin + 1; i < xmax; i++) + for(int j = zmin + 1; j < zmax; j++) { + DBlock.place(world, i, top, j, dungeon.floorBlock); + for(int k = top + (ydim * 2); k >= top + 1; k--) + DBlock.deleteBlock(world, i, k, j); + below = top - 1; + while(!DBlock.isGroundBlock(world, i, below, j)) { + DBlock.place(world, i, below, j, dungeon.floorBlock); + below--; + } + } + //DoomlikeDungeons.profiler.endTask("Generating Floor (TopRoom)"); + //DoomlikeDungeons.profiler.startTask("Generating X-Walls (TopRoom)"); + for(int i = xmin; i <= xmax; i++) { + for(int j = top + ydim; j >= top; j--) { + DBlock.place(world, i, j, zmax, dungeon.wallBlock1); + DBlock.place(world, i, j, zmin, dungeon.wallBlock1); + } + if(dungeon.random.nextInt(8) == 0) + for(int j = top + 2; j > top; j--) { + DBlock.deleteBlock(world, i, j, zmax); + DBlock.deleteBlock(world, i, j, zmin); + } + below = top - 1; + while(!DBlock.isGroundBlock(world, i, below, zmax)) { + DBlock.place(world, i, below, zmax, dungeon.wallBlock1); + below--; + } + below = top - 1; + while(!DBlock.isGroundBlock(world, i, below, zmin)) { + DBlock.place(world, i, below, zmin, dungeon.floorBlock); + below--; + } + } + //DoomlikeDungeons.profiler.endTask("Generating X-Walls (TopRoom)"); + //DoomlikeDungeons.profiler.startTask("Generating Z-Walls (TopRoom)"); + for(int i = zmin; i <= zmax; i++) { + for(int j = top + ydim; j >= top; j--) { + DBlock.place(world, xmin, j, i, dungeon.wallBlock1); + DBlock.place(world, xmax, j, i, dungeon.wallBlock1); + } + if(dungeon.random.nextInt(8) == 0) + for(int j = top + 2; j > top; j--) { + DBlock.deleteBlock(world, xmax, j, i); + DBlock.deleteBlock(world, xmin, j, i); + } + below = top - 1; + while(!DBlock.isGroundBlock(world, xmax, below, i)) { + DBlock.place(world, xmax, below, i, dungeon.wallBlock1); + below--; + } + below = top - 1; + while(!DBlock.isGroundBlock(world, xmin, below, i)) { + DBlock.place(world, xmin, below, i, dungeon.floorBlock); + below--; + } + } + //DoomlikeDungeons.profiler.endTask("Generating Z-Walls (TopRoom)"); + //DoomlikeDungeons.profiler.startTask("Generating Ceilding (TopRoom)"); + for(int i = xmin; i <= xmax; i++) + for(int j = zmin; j <= zmax; j++) { + DBlock.place(world, i, top + ydim + 1, j, dungeon.cielingBlock); + } + //DoomlikeDungeons.profiler.endTask("Generating Ceilding (TopRoom)"); + //DoomlikeDungeons.profiler.endTask("Generating Building (TopRoom)"); + } + + + /** + * This will build a small ruin at the dungeon entrance. This will also + * fill in a any areas between the room and ground so that it doesn't float. + * + * @param dungeon + * @param world + */ + private void buildRuin(Dungeon dungeon, World world) { + //DoomlikeDungeons.profiler.startTask("Generating Ruin (TopRoom)"); + //DoomlikeDungeons.profiler.startTask("Generating Floor (TopRoom)"); + for(int i = xmin + 1; i < xmax; i++) + for(int j = zmin + 1; j < zmax; j++) { + DBlock.place(world, i, top, j, dungeon.floorBlock); + below = top - 1; + while(!DBlock.isGroundBlock(world, i, below, j)) { + DBlock.place(world, i, below, j, dungeon.floorBlock); + below--; + } + } + //DoomlikeDungeons.profiler.endTask("Generating Floor (TopRoom)"); + //DoomlikeDungeons.profiler.startTask("Generating X-Walls (TopRoom)"); + for(int i = xmin; i <= xmax; i++) { + for(int j = top + ydim - dungeon.random.nextInt(3); j >= top; j--) { + DBlock.place(world, i, j, zmax, dungeon.wallBlock1); + DBlock.place(world, i, j, zmin, dungeon.wallBlock1); + } + if(dungeon.random.nextInt(8) == 0) + for(int j = top + 2; j > top; j--) { + DBlock.deleteBlock(world, i, j, zmax); + DBlock.deleteBlock(world, i, j, zmin); + } + below = top - 1; + while(!DBlock.isGroundBlock(world, i, below, zmax)) { + DBlock.place(world, i, below, zmax, dungeon.wallBlock1); + below--; + } + below = top - 1; + while(!DBlock.isGroundBlock(world, i, below, zmin)) { + DBlock.place(world, i, below, zmin, dungeon.floorBlock); + below--; + } + } + //DoomlikeDungeons.profiler.endTask("Generating X-Walls (TopRoom)"); + //DoomlikeDungeons.profiler.startTask("Generating Z-Walls (TopRoom)"); + for(int i = zmin; i <= zmax; i++) { + for(int j = top + ydim - dungeon.random.nextInt(3); j >= top; j--) { + DBlock.place(world, xmin, j, i, dungeon.wallBlock1); + DBlock.place(world, xmax, j, i, dungeon.wallBlock1); + } + if(dungeon.random.nextInt(8) == 0) + for(int j = top + 2; j > top; j--) { + DBlock.deleteBlock(world, xmax, j, i); + DBlock.deleteBlock(world, xmin, j, i); + } + below = top - 1; + while(!DBlock.isGroundBlock(world, xmax, below, i)) { + DBlock.place(world, xmax, below, i, dungeon.wallBlock1); + below--; + } + below = top - 1; + while(!DBlock.isGroundBlock(world, xmin, below, i)) { + DBlock.place(world, xmin, below, i, dungeon.floorBlock); + below--; + } + } + //DoomlikeDungeons.profiler.endTask("Generating Z-Walls (TopRoom)"); + //DoomlikeDungeons.profiler.startTask("Generating Ruin (TopRoom)"); + } + + + + + ////////////////////////////////////////////////////////////////////////// + // Building Way In Below // + ////////////////////////////////////////////////////////////////////////// + + + /** + * Will build a column holding a ladder; this is the same as what's build + * by SimplEntrance, except that the column and ladder will reach to the + * top room's ceiling height. + * + * @param world + * @param dungeon + */ + private void buildLatter(World world, Dungeon dungeon) { + //DoomlikeDungeons.profiler.startTask("Generating Latter (TopRoom)"); + top += ydim; + int side = dungeon.random.nextInt(4); + switch (side) { + case 0: + for(int i = bottom; i <= top; i++) { + DBlock.place(world, wx, i, wz, dungeon.wallBlock1); + DBlock.placeBlock(world, wx + 1, i, wz, ladder5); + } + break; + case 1: + for(int i = bottom; i <= top; i++) { + DBlock.place(world, wx, i, wz, dungeon.wallBlock1); + DBlock.placeBlock(world, wx, i, wz + 1, ladder3); + } + break; + case 2: + for(int i = bottom; i <= top; i++) { + DBlock.place(world, wx, i, wz, dungeon.wallBlock1); + DBlock.placeBlock(world, wx - 1, i, wz, ladder4); + } + break; + case 3: + for(int i = bottom; i <= top; i++) { + DBlock.place(world, wx, i, wz, dungeon.wallBlock1); + DBlock.placeBlock(world, wx, i, wz - 1, ladder2); + } + break; + } + //DoomlikeDungeons.profiler.endTask("Generating Latter (TopRoom)"); + } + + + /** + * This will build a spiral stair into the dungeon, the same as would have + * been built by the SpiralStair class. + * + * @param world + * @param dungeon + */ + private void buildStair(World world, Dungeon dungeon) { + //DoomlikeDungeons.profiler.startTask("Generating Stair (TopRoom)"); + top++; + int side = dungeon.random.nextInt(4); + for(int i = bottom; i < top; i++) { + int sx, sz; + DBlock.place(world, wx, i, wz, dungeon.wallBlock1); + switch (side) { + case 0: + DBlock.placeBlock(world, wx+1, i, wz, slab0); + DBlock.placeBlock(world, wx+1, i, wz+1, slab8); + // Empty space + DBlock.deleteBlock(world, wx, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz); + DBlock.deleteBlock(world, wx-1, i, wz-1); + DBlock.deleteBlock(world, wx, i, wz-1); + DBlock.deleteBlock(world, wx+1, i, wz-1); + break; + case 1: + DBlock.placeBlock(world, wx, i, wz+1, slab0); + DBlock.placeBlock(world, wx-1, i, wz+1, slab8); + // Empty space + DBlock.deleteBlock(world, wx+1, i, wz); + DBlock.deleteBlock(world, wx+1, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz); + DBlock.deleteBlock(world, wx-1, i, wz-1); + DBlock.deleteBlock(world, wx, i, wz-1); + DBlock.deleteBlock(world, wx+1, i, wz-1); + break; + case 2: + DBlock.placeBlock(world, wx-1, i, wz, slab0); + DBlock.placeBlock(world, wx-1, i, wz-1, slab8); + // Empty space + DBlock.deleteBlock(world, wx+1, i, wz); + DBlock.deleteBlock(world, wx+1, i, wz+1); + DBlock.deleteBlock(world, wx, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz+1); + DBlock.deleteBlock(world, wx, i, wz-1); + DBlock.deleteBlock(world, wx+1, i, wz-1); + break; + case 3: + DBlock.placeBlock(world, wx, i, wz-1, slab0); + DBlock.placeBlock(world, wx+1, i, wz-1, slab8); + // Empty space + DBlock.deleteBlock(world, wx+1, i, wz); + DBlock.deleteBlock(world, wx+1, i, wz+1); + DBlock.deleteBlock(world, wx, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz+1); + DBlock.deleteBlock(world, wx-1, i, wz); + DBlock.deleteBlock(world, wx-1, i, wz-1); + break; + } + side = (side + 1) % 4; + } + //DoomlikeDungeons.profiler.endTask("Generating Stair (TopRoom)"); + } + +} diff --git a/src/jaredbgreat/dldungeons/planner/Dungeon.java b/src/jaredbgreat/dldungeons/planner/Dungeon.java new file mode 100644 index 0000000..93c126b --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/Dungeon.java @@ -0,0 +1,500 @@ +package jaredbgreat.dldungeons.planner; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.ConfigHandler; +import jaredbgreat.dldungeons.Difficulty; +//import jaredbgreat.dldungeons.DoomlikeDungeons; +import jaredbgreat.dldungeons.builder.DBlock; +import jaredbgreat.dldungeons.pieces.Spawner; +import jaredbgreat.dldungeons.pieces.chests.BasicChest; +import jaredbgreat.dldungeons.pieces.chests.LootCategory; +import jaredbgreat.dldungeons.pieces.chests.LootHandler; +import jaredbgreat.dldungeons.pieces.entrances.SimpleEntrance; +import jaredbgreat.dldungeons.pieces.entrances.SpiralStair; +import jaredbgreat.dldungeons.pieces.entrances.TopRoom; +import jaredbgreat.dldungeons.planner.astar.DoorChecker; +import jaredbgreat.dldungeons.planner.mapping.MapMatrix; +import jaredbgreat.dldungeons.rooms.Cave; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.rooms.RoomList; +import jaredbgreat.dldungeons.themes.BiomeSets; +import jaredbgreat.dldungeons.themes.Degree; +import jaredbgreat.dldungeons.themes.Sizes; +import jaredbgreat.dldungeons.themes.Theme; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Random; +import java.util.logging.Level; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.entity.EntityType; + +//import net.minecraft.world.World; +//import net.minecraft.world.biome.Biome; +//import net.minecraftforge.common.MinecraftForge; + + +/** + * A representation of a dungeon level; as multi-level dungeons are not generated this is, + * by extension, a dungeon. This class holds all the dungeon wide information as well + * as the 2D map (MapMatrix) of the dungeon and its list of rooms. + * + * Methods of this class are responsible for determining the dungeon wide info it holds and + * and for layout the rooms and other features. + * + * @author Jared Blackburn + * + */ +public class Dungeon { + + public Theme theme; + public Random random; + public Biome biome; + + public MapMatrix map; // 2D layout of the dungeon + public Node[] nodes; // Main rooms (entrances and destination) which other rooms connect + public int numNodes; + public int roomCount; + public int entrancePref; + + public int baseHeight; // Default floor height for the dungeon + public int numEntrances = 0; + + public RoomList rooms; + public SpawnerCounter spawners; + public ArrayList planter; + public ArrayList grower; + + // Planning parameters + public Sizes size; + + // Not sure if I'll use all of them... + public Degree outside; // Roofless rooms (also wall-less, but may have fences) + public Degree liquids; // Quantity of water / lava pools + public Degree subrooms; // Rooms budding of from the main one + public Degree islands; // Rooms inside rooms + public Degree pillars; // Uh, pillars / columns, duh! + public Degree fences; // Uh, fences, duh! + public Degree symmetry; // How symmetrical rooms are (technically, chance of axis mirroring) + public Degree variability; // Inconsistency, that chance of using a different style in some place + public Degree degeneracy; // Chance of walls / ceilings not spawning over airblocks (idea taken from Greymerk) + public Degree complexity; // Basically how many shape primitives to add; depth of added place seeds + public Degree verticle; // How many height change and how much height change + public Degree entrances; // Ways in and outS + public Degree bigRooms; // Not currently used, but for oversided rooms between 1 and 2 time the normal max + public Degree naturals; // Cave like areas created with celluar automata + + // Default blocks + public int wallBlock1; + public int floorBlock; + public int cielingBlock; + public int stairBlock; + public int stairSlab; + public int fenceBlock; + public int cornerBlock; + public int liquidBlock; + public int caveBlock; + + public LootCategory lootCat; + + int shiftX; + int shiftZ; + + + /** + * De-links all referenced objects as a safety measure against memory leaks, + * which the complexity creates a risk for. This might not be needed, as + * circular have been checked for. + */ + public void preFinalize() { + if(theme != null) { + for(int i = 0; i < nodes.length; i++) nodes[i] = null; + for(Room room: rooms) { + room.preFinalize(); + room = null; + } + rooms.clear(); + } + rooms = null; + planter = grower = null; + nodes = null; + theme = null; + random = null; + biome = null; + map = null; + size = null; + outside = null; + liquids = null; + subrooms = null; + islands = null; + pillars = null; + symmetry = null; + variability = null; + degeneracy = null; + complexity = null; + verticle = null; + entrances = null; + bigRooms = null; + naturals = null; + } + + + public Dungeon(Random rnd, Biome biome, World world, int chunkX, int chunkZ) throws Throwable { +// DoomlikeDungeons.profiler.startTask("Planning Dungeon"); +// DoomlikeDungeons.profiler.startTask("Layout dungeon (rough draft)"); + random = rnd; + this.biome = biome; + theme = BiomeSets.getTheme(biome, random); + if(theme == null) { +// Bukkit.getLogger().log(Level.SEVERE, "ERROR2"); + return; + } + + applyTheme(); + entrancePref = random.nextInt(3); + + wallBlock1 = theme.walls[random.nextInt(theme.walls.length)]; + floorBlock = theme.floors[random.nextInt(theme.floors.length)]; + cielingBlock = theme.ceilings[random.nextInt(theme.ceilings.length)]; + fenceBlock = theme.fencing[random.nextInt(theme.fencing.length)]; + cornerBlock = theme.pillarBlock[random.nextInt(theme.pillarBlock.length)]; + liquidBlock = theme.liquid[random.nextInt(theme.liquid.length)]; + caveBlock = theme.caveWalls[random.nextInt(theme.caveWalls.length)]; + + rooms = new RoomList(size.maxRooms + 1); + planter = new ArrayList(); + map = new MapMatrix(size.width, world, chunkX, chunkZ); + numNodes = random.nextInt(size.maxNodes - size.minNodes + 1) + size.minNodes + 1; + nodes = new Node[numNodes]; + spawners = new SpawnerCounter(); + + shiftX = (map.chunkX * 16) - (map.room.length / 2) + 8; + shiftZ = (map.chunkZ * 16) - (map.room.length / 2) + 8; + + makeNodes(); + if((numEntrances < 1) + && (ConfigHandler.easyFind || ConfigHandler.singleEntrance)) addAnEntrance(); + connectNodes(); + growthCycle(); + if(ConfigHandler.thinSpawners && (ConfigHandler.difficulty != Difficulty.NONE)) { + spawners.fixSpawners(this, rnd); + for(Room room : rooms) { + room.addChests(this); + } + } +// DoomlikeDungeons.profiler.endTask("Layout dungeon (rough draft)"); +// DoomlikeDungeons.profiler.startTask("Fixing room contents"); + fixRoomContents(); +// DoomlikeDungeons.profiler.endTask("Fixing room contents"); +// DoomlikeDungeons.profiler.endTask("Planning Dungeon"); + } + + + /** + * Set all the dungeon wide theme derived variables that are + * of type Degree. + */ + private void applyTheme() { + size = theme.sizes.select(random); + outside = theme.outside.select(random); + liquids = theme.liquids.select(random); + subrooms = theme.subrooms.select(random); + islands = theme.islands.select(random); + pillars = theme.pillars.select(random); + symmetry = theme.symmetry.select(random); + variability = theme.variability.select(random); + degeneracy = theme.degeneracy.select(random); + complexity = theme.complexity.select(random); + verticle = theme.verticle.select(random); + entrances = theme.entrances.select(random); + fences = theme.fences.select(random); + naturals = theme.naturals.select(random); + baseHeight = random.nextInt(theme.maxY - theme.minY) + theme.minY; + lootCat = LootHandler.getLootHandler().getCategory(theme.lootCat); + if(lootCat == null) { + lootCat = LootHandler.getLootHandler().getCategory("chest.cfg"); + } + } + + + /** + * Creates all the nodes and store along with a list of node rooms. + */ + private void makeNodes() { + //DoomlikeDungeons.profiler.startTask("Creating Node Rooms"); + int i = 0; + while(i < numNodes) { + nodes[i] = new Node(random.nextInt(size.width), baseHeight, + random.nextInt(size.width), random, this); + if(nodes[i].hubRoom != null) ++i; + } + //DoomlikeDungeons.profiler.endTask("Creating Node Rooms"); + } + + + /** + * This will connect all the nodes with series of intermediate rooms by + * callaing either connectNodesDensely or connectNodesSparcely, with a + * 50% chance of each. + * + * @throws Throwable + */ + private void connectNodes() { + if(random.nextBoolean()) { + connectNodesDensely(); + } else { + connectNodesSparcely(); + } + } + + + /** + * This will attempt to connect all nodes based on the logic that + * if B can be reached from A, and C can be reached from B, then + * C can be reached from A (by going through B if no other route + * exists). + * + * Specifically, it will connect the first node to one random other + * node, and then connect a random node already connected to the + * first with one that has not been connected, until all nodes have + * attempted a connects. Note that this does not guarantee connections + * as the attempt to place a route between any two nodes may fail. + * + * @throws Throwable + */ + private void connectNodesSparcely() { + //DoomlikeDungeons.profiler.startTask("Connecting Nodes"); + Node first, other; + ArrayList connected = new ArrayList(nodes.length), + disconnected = new ArrayList(nodes.length); + connected.add(nodes[0]); + for(int i = 1; i < nodes.length; i++) { + disconnected.add(nodes[i]); + } + while(!disconnected.isEmpty()) { + if(rooms.realSize() >= size.maxRooms) { + //DoomlikeDungeons.profiler.endTask("Connecting Nodes"); + return; + } + first = connected.get(random.nextInt(connected.size())); + other = disconnected.get(random.nextInt(disconnected.size())); + new Route(first, other).drawConnections(this); + connected.add(other); + disconnected.remove(other); + } + //DoomlikeDungeons.profiler.endTask("Connecting Nodes"); + } + + + /** + * This will attempt to make one connects between every two pairs of + * nodes by first connecting the first node to all others directly, + * then each successive node to every node with a higher index. As + * nodes with a lower index will already have attempted a connects + * this is not repeated. Note that this does not guarantee connections + * as the attempt to place a route between any two nodes may fail. + * + * @throws Throwable + */ + private void connectNodesDensely() { + //DoomlikeDungeons.profiler.startTask("Connecting Nodes"); + Node first, other; + for(int i = 0; i < nodes.length; i++) { + first = nodes[i]; + for(int j = i + 1; j < nodes.length; j++) { + other = nodes[j]; + if(rooms.realSize() >= size.maxRooms) { + //DoomlikeDungeons.profiler.endTask("Connecting Nodes"); + return; + } + if(other != first) { + new Route(first, other).drawConnections(this); + } + } + } + //DoomlikeDungeons.profiler.endTask("Connecting Nodes"); + } + + + /** + * This will add side rooms not directly connecting nodes (though new + * connection are often added by luck); these are the extra rooms whose + * only real purpose it to give the player more areas to explore, mobs + * to fights, and chests to loot. + * + * The basic system try to sprout side room from all rooms that are eligible + * to produce side rooms in random order, but trying to grow rooms their + * doors. If a room fails to grow a new room it is no longer considered + * eligible for future attempt, while all new rooms start as eligible by + * default. The cycle will repeat until either the maximum number of rooms + * for the dungeons size have been generated or there are no more eligible + * rooms to spread from. + */ + private void growthCycle() { + //DoomlikeDungeons.profiler.startTask("Adding Rooms (growthCycle)"); + boolean doMore = true; + do { + doMore = false; + grower = planter; + Collections.shuffle(grower, random); + planter = new ArrayList(); + for(Room room : grower) { + if(rooms.realSize() >= size.maxRooms) { + return; + } + if(room.plantChildren(this)) { + doMore = true; + } + } + } while(doMore); + //DoomlikeDungeons.profiler.endTask("Adding Rooms (growthCycle)"); + } + + + /** + * This is the master method for error corrections and improvements + * in the dungeon. While it does none of these things directly, it + * calls methods for removing doors-to-nowhere, determining which + * doors to treat as the main connection between rooms, check room + * passibility, and check dungeon connectivity, ensure all these methods + * are called (and in the correct order). + */ + private void fixRoomContents() { + for(Room room : rooms) { + addChestBlocks(room); + DoorChecker.processDoors1(this, room); + } + for(Room room : rooms) { + DoorChecker.processDoors2(this, room); + } + for(Room room : rooms) { + DoorChecker.processDoors3(this, room); + if(room instanceof Cave) DoorChecker.caveConnector(this, room); + } + DoorChecker.checkConnectivity(this); + } + + + /** + * Places the chest blocks; this is done in advance to decrease the chance of + * absent chests resulting from concurrent optimization in the main game. + * + * @param room + */ + public void addChestBlocks(Room room) { +// if(MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.AddChestBlocksToRoom(this, room))) return; + for(BasicChest chest : room.chests) { + DBlock.placeChest(map.world, shiftX + chest.mx, chest.my, shiftZ + chest.mz); + } + } + + + /** + * This cycles through all the rooms and add chests and spawners + * by calling addTileEntitiesToRoom on each. + */ + public void addTileEntities() { + for(Room room : rooms) { + addTileEntitesToRoom(room); + } + } + + + /** + * This add all the chest and spawners to the room. + * + * @param room + */ + private void addTileEntitesToRoom(Room room) { +// if(MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.AddTileEntitiesToRoom(this, room))) return; + for(Spawner spawner : room.spawners) { + DBlock.placeSpawner(map.world, + shiftX + spawner.getX(), + spawner.getY(), + shiftZ + spawner.getZ(), + EntityType.valueOf(spawner.getMob())); + } + for(BasicChest chest : room.chests) { + chest.place(map.world, shiftX + chest.mx, chest.my, shiftZ + chest.mz, random); + } + } + + + /** + * This cycles through all nodes and calls addEntrance on each; + * entrances will only be added to entrance nodes, but that is + * checked by addEntrance, not here. + */ + public void addEntrances() { + for(int i = 0; i < nodes.length; i++) { + if(nodes[i].hubRoom != null) addEntrance(nodes[i].hubRoom); + } + } + + + /** + * This will added a physical entrance to all entrance nodes. + * + * @param room + */ + private void addEntrance(Room room) { + if(!room.hasEntrance) return; + //DoomlikeDungeons.profiler.startTask("Adding Entrances"); + int entrance; + if(variability.use(random)) entrance = random.nextInt(3); + else entrance = entrancePref; + if(ConfigHandler.easyFind) entrance = 1; +// if(MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.AddEntrance(this, room))) return; + + switch (entrance) { + case 0: + //DoomlikeDungeons.profiler.startTask("Adding Sriral Stair"); + new SpiralStair((int)room.realX, (int)room.realZ).build(this, map.world); + //DoomlikeDungeons.profiler.endTask("Adding Sriral Stair"); + break; + case 1: + //DoomlikeDungeons.profiler.startTask("Adding Top Room"); + new TopRoom((int)room.realX, (int)room.realZ).build(this, map.world); + //DoomlikeDungeons.profiler.endTask("Adding Top Room"); + break; + case 2: + default: + //DoomlikeDungeons.profiler.startTask("Adding Simple Entrance"); + new SimpleEntrance((int)room.realX, (int)room.realZ).build(this, map.world); + //DoomlikeDungeons.profiler.endTask("Adding Simple Entrance"); + break; + } + //DoomlikeDungeons.profiler.endTask("Adding Entrances"); + } + + + /** + * This will convert one non-entrance node into an entrance node + * if and only if the number of entrances has not been set to + * a degree of NONE by the dungeons theme. + */ + private void addAnEntrance() { + if(theme.entrances.never()) return; + int which = random.nextInt(nodes.length); + Room it = nodes[which].hubRoom; + it.chests.clear(); + it.spawners.clear(); + it.hasEntrance = true; + it.hasSpawners = false; + numEntrances = 1; + for(int i = (int)it.realX -2; i < ((int)it.realX + 2); i++) + for(int j = (int)it.realZ - 2; j < ((int)it.realZ + 2); j++) { + map.floorY[i][j] = (byte)it.floorY; + map.hasLiquid[i][j] = false; + map.isWall[i][j] = false; + } + } + +} + diff --git a/src/jaredbgreat/dldungeons/planner/Node.java b/src/jaredbgreat/dldungeons/planner/Node.java new file mode 100644 index 0000000..f86de1e --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/Node.java @@ -0,0 +1,41 @@ +package jaredbgreat.dldungeons.planner; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.rooms.Room; + +import java.util.Random; + + +/** + * A class representing node rooms (aka, hub-rooms) from and between + * which other rooms will be added. These are the rooms which will + * become entrances or destinations ("boss" / treasure rooms). + * + * @author Jared Blackburn + * + */ +public class Node { + Room hubRoom; + + + public Node(int x, int y, int z, Random random, Dungeon dungeon) { + // Nodes should be on the larger end of the size scale for rooms... + int xdim = random.nextInt((dungeon.size.maxRoomSize / 2) - 3) + + (dungeon.size.maxRoomSize / 2) + 4; + int zdim = random.nextInt((dungeon.size.maxRoomSize / 2) - 3) + + (dungeon.size.maxRoomSize / 2) + 4; + int ymod = (xdim <= zdim) ? (int) Math.sqrt(xdim) : (int) Math.sqrt(zdim); + int height = random.nextInt((dungeon.verticle.value / 2) + ymod + 1) + 2; + + // Then plant a seed and try to grow the room + hubRoom = new RoomSeed(x, y, z).growRoom(xdim, zdim, height, dungeon, null, null); +// if(hubRoom != null) { +// dungeon.nodeRooms.add(hubRoom); +// } + } +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/planner/RoomSeed.java b/src/jaredbgreat/dldungeons/planner/RoomSeed.java new file mode 100644 index 0000000..cbc00fe --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/RoomSeed.java @@ -0,0 +1,235 @@ +package jaredbgreat.dldungeons.planner; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.pieces.Shape; +import jaredbgreat.dldungeons.rooms.AbstractRoom; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.rooms.RoomType; + + +/** + * These "seeds" represent a potential Room. + * + * Target room sizes are passed into the constructor, after which the seed will + * attempt to grow (spread) to the fill that area. If there is not enough space on one + * dimension growth will stop. After a final size has been reach it is then checked + * to be sure it meets minimum the room size, that is at least five blocks on each + * dimension (x and z). + */ +public class RoomSeed { + + private int w = 0; + private int lowEdge, highEdge; + + private boolean canAddX = true, canAddZ = true, canSubX = true, canSubZ = true; + int x, y, z, height, grownX = 1, grownZ = 1, endX, beginX, endZ, beginZ; + + + public RoomSeed(int startX, int startY, int startZ) { + // These may change once the the seeds has grown + x = endX = beginX = startX; + y = startY; + z = endZ = beginZ = startZ; + } + + + /** + * Attempts to "grow" a new room from the RoomSeed. Two avoid a bias + * for creating long narrow rooms only along one dimension, the + * dimension to expand first is randomly determined and one of two + * methods are called to do the expansion. + * + * @param xdim + * @param zdim + * @param height + * @param dungeon + * @param parent + * @param previous + * @return A new room, or null if a room is not created + */ + public Room growRoom(int xdim, int zdim, int height, + Dungeon dungeon, Room parent, Room previous) { + if(dungeon.rooms.size() >= dungeon.size.maxRooms) return null; + if(dungeon.random.nextBoolean()) + return growRoomX(xdim, zdim, height, dungeon, parent, previous); + else return growRoomZ(xdim, zdim, height, dungeon, parent, previous); + } + + + /** + * This will attempt to grow a new room by expanding first along the x-axis, + * then the z-axis. + * + * The x-axis will first try to expand in each direction, until the both ends + * are blocked by existing rooms or the edge of the dungeon, or the target size + * is reached. Afterward the seed will try to expand along the y-axis by adding + * entire rows to each side, until it is either blocked on each side or the + * target size is reached. + * + * If either dimension is less the five blocks in length null will be returned, + * otherwise AbstractRoom.makeRoom is called to create a Room to return. + * + * The code for this and growRoomZ with some variables reversed, since this was + * the only simple solution to present itself when this class was designed and + * written. + * + * @param xdim + * @param zdim + * @param height + * @param dungeon + * @param parent + * @param previous + * @return A new room if successfully create, or null if not + */ + public Room growRoomX(int xdim, int zdim, int height, + Dungeon dungeon, Room parent, Room previous) { + int container; + // Parent should always be null unless growing an island sub-room. + if(parent == null) { + container = 0; + w = 0; + } + else { + container = parent.id; + w = 1; + } + if((x >= dungeon.size.width) || (x < 0) || (z >= dungeon.size.width) || (z < 0)) return null; + if(dungeon.map.room[x][z] != container) return null; + while((canAddX || canSubX) && grownX < xdim) { + if((endX+1) >= dungeon.size.width) canAddX = false; + if((beginX-1) < 0) canSubX = false; + if(canAddX) { + if(dungeon.map.room[endX+w][z] == container) { + grownX += 1; + endX += 1; + } else canAddX = false; + } if(canSubX) { + if(dungeon.map.room[beginX-w][z] == container) { + grownX += 1; + beginX -= 1; + } else canSubX = false; + } + } + while((canAddZ || canSubZ) && grownZ < zdim) { + lowEdge = beginX + 1 - w; + highEdge = endX - 1 + w; + for(int i = lowEdge; i <= highEdge; i++) { + if((endZ+1) >= dungeon.size.width) canAddZ = false; + else { + if(dungeon.map.room[i][endZ+w] != container) canAddZ = false; + } + if((beginZ-1) < 0) canSubZ = false; + else { + if(dungeon.map.room[i][beginZ-w] != container) canSubZ = false; + } + } + if(canAddZ) { + grownZ += 1; + endZ += 1; + } + if(canSubZ) { + grownZ += 1; + beginZ -= 1; + } + } + if((grownX < 5) || (grownZ < 5)) { + return null; // Not big enough for a room! + } + else { + dungeon.roomCount++; + return AbstractRoom.makeRoom(beginX, endX, beginZ, endZ, y, y + height, dungeon, parent, previous); + } + } + + + /** + * This will attempt to grow a new room by expanding first along the z-axis, + * then the x-axis. + * + * The z-axis will first try to expand in each direction, until the both ends + * are blocked by existing rooms or the edge of the dungeon, or the target size + * is reached. Afterward the seed will try to expand along the x-axis by adding + * entire rows to each side, until it is either blocked on each side or the + * target size is reached. + * + * If either dimension is less the five blocks in length null will be returned, + * otherwise AbstractRoom.makeRoom is called to create a Room to return. + * + * The code for this and growRoomX with some variables reversed, since this was + * the only simple solution to present itself when this class was designed and + * written. + * + * @param xdim + * @param zdim + * @param height + * @param dungeon + * @param parent + * @param previous + * @return A new room if successfully create, or null if not + */ + public Room growRoomZ(int xdim, int zdim, int height, + Dungeon dungeon, Room parent, Room previous) { + int container; + // Parent should always be null unless growing an island sub-room. + if(parent == null) { + container = 0; + w = 0; + } + else { + container = parent.id; + w = 1; + } + if((x >= dungeon.size.width) || (x < 0) || (z >= dungeon.size.width) || (z < 0)) return null; + if(dungeon.map.room[x][z] != container) return null; + while((canAddZ || canSubZ) && grownZ < zdim) { + if((endZ+1) >= dungeon.size.width) canAddZ = false; + if((beginZ-1) < 0) canSubZ = false; + if(canAddZ) { + if(dungeon.map.room[x][endZ+w] == container) { + grownZ += 1; + endZ += 1; + } else canAddZ = false; + } if(canSubZ) { + if(dungeon.map.room[x][beginZ-w] == container) { + grownZ += 1; + beginZ -= 1; + } else canSubZ = false; + } + } + while((canAddX || canSubX) && grownX < xdim) { + lowEdge = beginZ + 1 - w; + highEdge = endZ - 1 + w; + for(int i = lowEdge; i <= highEdge; i++) { + if((endX+1) >= dungeon.size.width) canAddX = false; + else { + if(dungeon.map.room[endX+w][i] != container) canAddX = false; + } + if((beginX-1) < 0) canSubX = false; + else { + if(dungeon.map.room[beginX-w][i] != container) canSubX = false; + } + } + if(canAddX) { + grownX += 1; + endX += 1; + } + if(canSubX) { + grownX += 1; + beginX -= 1; + } + } + if((grownX < 5) || (grownZ < 5)) { + return null; // Not big enough for a room! + } + else { + dungeon.roomCount++; + return AbstractRoom.makeRoom(beginX, endX, beginZ, endZ, y, y + height, dungeon, parent, previous); + } + } +} diff --git a/src/jaredbgreat/dldungeons/planner/Route.java b/src/jaredbgreat/dldungeons/planner/Route.java new file mode 100644 index 0000000..70cda80 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/Route.java @@ -0,0 +1,292 @@ +package jaredbgreat.dldungeons.planner; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.rooms.Room; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Random; + +/** + * This class represents a potential route between two rooms; its purpose + * is to find an actual concrete route and add it to the dungeon. To do + * that it will produce a sequence of rooms from each end (start and + * finish), alternately adding a room to each in the general direction + * of the other until the squences connect at some point. + * + * @author Jared Blackburn + * + */ +public class Route { + + + private final Node start, finish; + private Room current1, current2, temp; + private float realXDist, realZDist; + private int bXDist, bZDist, dir1, dir2; + private boolean xMatch, zMatch, finishTurn, complete, comp1, comp2; + private ArrayList side1, side2; + + + protected Route(Node start, Node finish) { + this.start = start; + this.finish = finish; + current1 = start.hubRoom; + current2 = finish.hubRoom; + side1 = new ArrayList(); + side1.add(current1); + side2 = new ArrayList(); + side2.add(current2); + finishTurn = false; + complete = false; + + if(realXDist > 3.0f) { + bXDist = current2.endX - current1.beginX; + xMatch = false; + } else if(realXDist < -3.0f) { + bXDist = current2.beginX - current1.endX; + xMatch = false; + } else { + bXDist = (int)realXDist; + xMatch = true; + } + + if(realZDist > 3.0f) { + bZDist = current2.endZ - current1.beginZ; + zMatch = false; + } else if(realZDist < -3.0f) { + bZDist = current2.beginZ - current1.endZ; + zMatch = false; + } else { + bZDist = (int)realZDist; + zMatch = true; + } + } + + + /** + * This will attempt to draw the connecting serious of rooms by + * calling drawConnection until either the connection is flagged as + * complete or the dungeon has reach the maximum number of rooms. + * + * Note that the connection may be flagged complete either because + * an actual connection has been found or because both sequences + * (that from the start and that from the + * + * @param dungeon + */ + protected void drawConnections(Dungeon dungeon) { + int limit = dungeon.size.maxRooms; + while(!complete && (limit > 0)) { + limit--; + if(dungeon.rooms.size() >= dungeon.size.maxRooms) return; + drawConnection(dungeon); + if(complete || (limit < 0)) return; + } + } + + + /** + * This will try to add a room to one of the sequences. Which sequence gets + * this turn is determined by the internal finishTurn variable, which alternates + * with each call. The location of the new rooms will always be closer on either + * the x or z axis, though which is determined randomly, though weighted to favor + * the axis on which the distance is greatest. + * + * The connection is considered complete when either the sequence of rooms from + * either end meet or when each fails to add a room on consecutive turns (a + * give-up condition). + * + * @param dungeon + */ + public void drawConnection(Dungeon dungeon) { + //System.out.println("Running drawConnections(Dungeon dungeon)"); + getGrowthDir(dungeon.random); + int height = dungeon.baseHeight; + int x = dungeon.random.nextInt(dungeon.size.width); + int z = dungeon.random.nextInt(dungeon.size.width); + int xdim = dungeon.random.nextInt(dungeon.size.maxRoomSize - 5) + 6; + int zdim = dungeon.random.nextInt(dungeon.size.maxRoomSize - 5) + 6; + if(close(dungeon.size.maxRoomSize - 1)) xdim = zdim = dungeon.size.maxRoomSize; + int ymod = (xdim <= zdim) ? (int) Math.sqrt(xdim) : (int) Math.sqrt(zdim); + int roomHeight = dungeon.random.nextInt((dungeon.verticle.value / 2) + ymod + 1) + 2; + if(finishTurn) { + dir1 = (dir1 + 2) % 4; + dir2 = (dir2 + 2) % 4; + temp = current2.connector(dungeon, dir1, xdim, zdim, roomHeight, this); + if((temp == null) || side2.contains(temp)) temp = current2.connector(dungeon, dir2, xdim, zdim, roomHeight, this); + if((temp == null) || side2.contains(temp)) { + comp2 = true; // for now, give up + } else if(side1.contains(temp)) { + complete = true; // Success! + } else { + side2.add(temp); + current2 = temp; + } + } else { + temp = current1.connector(dungeon, dir1, xdim, zdim, roomHeight, this); + if(temp == null|| side1.contains(temp)) temp = current1.connector(dungeon, dir2, xdim, zdim, roomHeight, this); + if(temp == null|| side1.contains(temp)) { + comp1 = true; // for now, give up + } else if(side2.contains(temp)) { + complete = true; // Success! + } else { + side1.add(temp); + current1 = temp; + } + } + if(!complete) complete = comp1 && comp2; + if(comp1) finishTurn = true; + else if(comp2) finishTurn = false; + else finishTurn = !finishTurn; + } + + + + + + // Helper methods + + /** + * @return ture if the terminal rooms in both sequences overlap on the x axis. + */ + private boolean xOverlap() { + return ((current1.endX > current2.beginX) && (current2.endX > current1.beginX)); + } + + + /** + * @return true if the terminal rooms in both sequences overlap on the z axis. + */ + private boolean zOverlap() { + return ((current1.endZ > current2.beginZ) && (current2.endZ > current1.beginZ)); + } + + + /** + * @return true if the room edges align on x and the rooms overlap on z + */ + private boolean touchesOnX() { + if(!zOverlap()) return false; + return ((current1.beginX == current2.endX) || (current1.endX == current2.beginX)); + } + + + /** + * @return true if the room edges align on z and overlap on x. + */ + private boolean touchesOnZ() { + if(!xOverlap()) return false; + return ((current1.beginZ == current2.endZ) || (current1.endZ == current2.beginZ)); + } + + + /** + * @return true if the the terminal rooms in each sequence are directly adjacent + */ + private boolean touching() { + return (touchesOnX() || touchesOnZ()); + } + + + /** + * This will determine which wall is touching between the terminal rooms on each + * sequence. Specifically this finds which direction to move from the terminal room in + * the sequence to that in the finish sequence. + * + * @return the direction from the start sequence to the finish sequence. + */ + private int touchDir() { + if(zOverlap()) { + if(current1.endX == current2.beginX) return 0; + if(current1.beginX == current2.endX) return 2; + } else if(xOverlap()) { + if(current1.endZ == current2.beginZ) return 1; + if(current1.beginZ == current2.endZ) return 3; + } + return -1; // Not touching + } + + + /** + * This determines if the terminal rooms in the each sequence are close, that is + * if they are close enough to fill the gap with a single room. This is used to + * prevent potential connections are not ruined by placing an room whose target + * size is too short to connect but leave too small a gap for another room. + * + * @param range + * @return + */ + private boolean close(int range) { + if(Math.abs(current1.beginX - current2.endX) > range) return false; + if(Math.abs(current2.beginX - current1.endX) > range) return false; + if(Math.abs(current1.beginZ - current2.endZ) > range) return false; + if(Math.abs(current2.beginZ - current1.endZ) > range) return false; + return true; + } + + + /** + * This uses randomness and the coordinate of the terminal rooms in each + * sequence to determine in which direction a new rooms should be added. + * + * The direction is picked in such a way that sequences attempt to "grow" + * toward each other while also maintaining a degree of randomness. + * + * @param random + */ + private void getGrowthDir(Random random) { + boolean posX = (current1.realX < current2.realX); + boolean posZ = (current1.realZ < current2.realZ); + if(xOverlap()) { + if(posZ) { + dir1 = 1; + dir2 = random.nextInt(2) * 2; + } + else { + dir1 = 3; + dir2 = random.nextInt(2) * 2; + } + } else if (zOverlap()) { + if(posX) { + dir1 = 0; + dir2 = 1 + random.nextInt(2) * 2; + } + else { + dir1 = 2; + dir2 = 1 + random.nextInt(2) * 2; + } + } else if (random.nextInt((int)(Math.abs(realXDist) + Math.abs(realZDist) + 1)) + > (int)(Math.abs(realXDist))) { + if(posX) { + dir1 = 0; + if(posZ) dir2 = 1; + else dir2 = 3; + } + else { + dir1 = 2; + if(posZ) dir2 = 1; + else dir2 = 3; + } + } else { + if(posZ) { + dir1 = 1; + if(posX) dir2 = 0; + else dir2 = 2; + } + else { + dir1 = 3; + if(posX) dir2 = 0; + else dir2 = 2; + } + } + } + + +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/planner/SpawnerCounter.java b/src/jaredbgreat/dldungeons/planner/SpawnerCounter.java new file mode 100644 index 0000000..07564e1 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/SpawnerCounter.java @@ -0,0 +1,49 @@ +package jaredbgreat.dldungeons.planner; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.pieces.Spawner; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Random; +import jaredbgreat.dldungeons.ConfigHandler; + + +public class SpawnerCounter { + final ArrayList list; + int dungeonSize; + + public SpawnerCounter() { + list = new ArrayList<>(); + dungeonSize = 0; + } + + + public void addRoom(int size) { + dungeonSize += size; + } + + + public void addSpawner(Spawner s) { + list.add(s); + } + + + public void fixSpawners(Dungeon dungeon, Random random) { + int targetNum = dungeonSize / ConfigHandler.difficulty.blocksPerSpawner; + targetNum += (targetNum * + Math.max(5, Math.min(0, (random.nextGaussian() + 2)))) / 10; + int existing = list.size(); + if(existing <= targetNum) { + return; + } + Collections.shuffle(list, random); + for(int i = targetNum; i < existing; i++) { + Spawner s = list.get(i); + dungeon.rooms.get(s.getRoom()).spawners.remove(s); + } + } +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/planner/Symmetry.java b/src/jaredbgreat/dldungeons/planner/Symmetry.java new file mode 100644 index 0000000..7c479d0 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/Symmetry.java @@ -0,0 +1,120 @@ +package jaredbgreat.dldungeons.planner; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.pieces.Shape; +import jaredbgreat.dldungeons.pieces.Shapes; + +import java.util.EnumSet; + + +/** + * And enumeration of possible symmetries for rooms, including: + * + *
    + *
  1. NONE: asymmetric
  2. + *
  3. X: single line parallel with the x-axis
  4. + *
  5. Z: single line parallel with the z-axis
  6. + *
  7. XZ: two lines, parallel with the x-axis and z-axis
  8. + *
  9. TR1: a diagonal line (transpose symmetry)
  10. + *
  11. TR2: a diagonal line (transpose symmetry)
  12. + *
  13. R: Rotational symmetry, based on a 180 degree rotation the center of the room
  14. + *
  15. SW: Swirled symmetry, rotating 90 degrees around the center of the room
  16. + *
+ * + * @author Jared Blackburn + * + */ +public enum Symmetry { + + NONE (0, 0, false, false, false), + X (1, 1, true, false, false), + Z (2, 1, false, true, false), + XZ (3, 2, true, true, false), + TR1 (4, 1, false, false, true), + TR2 (5, 1, false, false, true), + R (6, 1, false, false, true), + SW (7, 2, true, true, false); + + + public final int ID; + public final int level; + public final boolean halfX; + public final boolean halfZ; + public final boolean doubler; + + + public static final Shapes[] allshapes = {Shapes.X, Shapes.L, Shapes.O, Shapes.T, + Shapes.F, Shapes.E, Shapes.I, Shapes.C, Shapes.U, Shapes.S}; + public static final Shapes[] xsymmetics = {Shapes.X, Shapes.O, Shapes.E, Shapes.I, Shapes.C}; + public static final Shapes[] ysymmetics = {Shapes.X, Shapes.O, Shapes.T, Shapes.I, Shapes.C, + Shapes.U}; + public static final Shapes[] xysymmetrics = {Shapes.X, Shapes.O, Shapes.I, Shapes.C}; + public static final Shapes[] transshapes = {Shapes.X, Shapes.L, Shapes.O, Shapes.C, Shapes.U}; + public static final Shapes[] rotateds = {Shapes.X, Shapes.O, Shapes.C, Shapes.S}; + + + public static final Shapes[] allPart = {Shapes.L, Shapes.O, Shapes.T, + Shapes.F, Shapes.E, Shapes.I, Shapes.C, Shapes.U, Shapes.S}; + public static final Shapes[] xsymmetricPart = {Shapes.O, Shapes.E, Shapes.I, Shapes.C}; + public static final Shapes[] ysymmetricPart = {Shapes.O, Shapes.T, Shapes.I, Shapes.C, Shapes.U};; + public static final Shapes[] xysymmetricPart = {Shapes.O, Shapes.I, Shapes.C}; + public static final Shapes[] transPart = {Shapes.L, Shapes.O, Shapes.C, Shapes.U}; + public static final Shapes[] rotatedPart = {Shapes.X, Shapes.O, Shapes.C, Shapes.S}; + + + public static final Shapes[] allSolids = {Shapes.X, Shapes.L, Shapes.T, + Shapes.F, Shapes.E, Shapes.I, Shapes.C, Shapes.U, Shapes.S}; + public static final Shapes[] xsymmetricSolid = {Shapes.X, Shapes.E, Shapes.I, Shapes.C}; + public static final Shapes[] ysymmetricSolid = {Shapes.X, Shapes.T, Shapes.I, Shapes.C, Shapes.U}; + public static final Shapes[] xysymmetricSolid = {Shapes.X, Shapes.I, Shapes.C}; + public static final Shapes[] transSolid = {Shapes.X, Shapes.L, Shapes.C, Shapes.U}; + public static final Shapes[] rotatedSolid = {Shapes.X, Shapes.C, Shapes.S}; + + + Symmetry(int ID, int level, boolean halfX, boolean halfZ, boolean doubler) { + this.ID = ID; + this.level = level; + this.halfX = halfX; + this.halfZ = halfZ; + this.doubler = doubler; + } + + + /** + * Returns a Symmetry constant based on the dungeons degree of + * symmetry; used to get the symmetry type for individual rooms. + * + * @param dungeon + * @return a Symmetry constant repressenting a type of semmetry + */ + public static Symmetry getSymmetry(Dungeon dungeon) { + int num = 0; + if(dungeon.symmetry.use(dungeon.random)) num += 1; + if(dungeon.symmetry.use(dungeon.random)) num += 1; + if(num == 0) return NONE; + int which = dungeon.random.nextInt(4 / num); + if(num == 1) switch (which) { + case 0: return X; + case 1: return Z; + case 2: + if(dungeon.random.nextBoolean()) { + return TR1; + } else { + return TR2; + } + case 3: return R; + default: return NONE; + } else switch (which) { + case 0: return XZ; + case 1: return SW; + default: return NONE; + } + } + +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/planner/astar/AStar.java b/src/jaredbgreat/dldungeons/planner/astar/AStar.java new file mode 100644 index 0000000..94ca1ef --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/astar/AStar.java @@ -0,0 +1,192 @@ +package jaredbgreat.dldungeons.planner.astar; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.pieces.Doorway; +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.planner.mapping.MapMatrix; +import jaredbgreat.dldungeons.planner.mapping.Tile; +import jaredbgreat.dldungeons.rooms.Room; + +import java.util.PriorityQueue; + +public class AStar { + + int room, x1, x2, z1, z2; // Room id and bounds + PriorityQueue edges; // Steps to consider + Step[][] spt; // Not a true tree but will hold the data + Dungeon dungeon; + Step root; + Tile end; + + protected AStar() {/*Do not use!*/} + + public AStar(Room room, Dungeon dungeon, Doorway start, Doorway finish) { + this.room = room.id; + this.dungeon = dungeon; + x1 = room.beginX; + x2 = room.endX; + z1 = room.beginZ; + z2 = room.endZ; + + end = finish; + if(end.x < x1) { + x1 = end.x; + } + if (end.x > x2) { + x2 = end.x; + } + if(end.z < z1) { + z1 = end.z; + } + if (end.z > z2) { + z2 = end.z; + } + + root = Step.firstFromDoorway(start, finish); + if(root.x < x1) { + x1 = root.x; + } + if (root.x > x2) { + x2 = root.x; + } + if(root.z < z1) { + z1 = root.z; + } + if (root.z > z2) { + z2 = root.z; + } + + spt = dungeon.map.nodedge; + for(int i = x1; i <= x2; i++) + for(int j = z1; j <= z2; j++) + spt[i][j] = null; + + spt[root.x][root.z] = root; + edges = new PriorityQueue(); + edges.add(root); + } + + /** + * This is what actually runs A* (and also calls other methods + * to make practical use of the results). + */ + public void seek() { + Step current; + do { + current = edges.poll(); + getEdgeStep(current); + } while(!current.equals(end)); + makeRoute(current); + } + + + /** + * This uses the data from AStar to make useful changes to the + * dungeon. + * + * @param end + */ + public void makeRoute(Step end) { + Step child = end, parent = end.parent; + if(parent == null) return; + + dungeon.map.astared[end.x][end.z] = true; + if(dungeon.map.isWall[end.x][end.z] || + dungeon.map.isFence[end.x][end.z]) + dungeon.map.isDoor[end.x][end.z] = true; + if(dungeon.map.hasLiquid[end.x][end.z]) { + dungeon.map.hasLiquid[end.x][end.z] = false; + dungeon.map.floorY[end.x][end.z] = + (byte) dungeon.rooms.get(room).floorY; + } + + do { + dungeon.map.astared[child.x][child.z] = true; + if(dungeon.map.isWall[child.x][child.z] || + dungeon.map.isFence[child.x][child.z]) + addDoor(parent, child); + if(dungeon.map.hasLiquid[child.x][child.z]) + fixLiquid(parent, child, + (byte) dungeon.rooms.get(room).floorY); + fixHeights(parent, child); + child = parent; + parent = child.parent; + } while (parent != null); + + dungeon.map.astared[child.x][child.z] = true; + if(dungeon.map.isWall[child.x][child.z] || + dungeon.map.isFence[child.x][child.z]) + dungeon.map.isDoor[child.x][child.z] = true; + if(dungeon.map.hasLiquid[child.x][child.z]) { + dungeon.map.hasLiquid[child.x][child.z] = false; + dungeon.map.floorY[child.x][child.z] = + (byte) dungeon.rooms.get(room).floorY; + } + } + + + protected void addDoor(Step from, Step to) { + dungeon.map.isDoor[to.x][to.z] = true; + dungeon.map.isDoor[from.x][from.z] = true; + } + + + protected void fixLiquid(Step from, Step to, byte floorY) { + dungeon.map.hasLiquid[to.x][to.z] = false; + dungeon.map.floorY[to.x][to.z] = + dungeon.map.floorY[from.x][from.z]; + if(dungeon.map.floorY[to.x][to.z] < floorY) + dungeon.map.floorY[to.x][to.z] = floorY; + } + + + protected void fixHeights(Step from, Step to) { + int diff = dungeon.map.floorY[to.x][to.z] - dungeon.map.floorY[from.x][from.z]; + if(diff > 2) dungeon.map.floorY[to.x][to.z] + = (byte) (dungeon.map.floorY[from.x][from.z] - 1); + if(diff < -2) dungeon.map.floorY[to.x][to.z] + = (byte) (dungeon.map.floorY[from.x][from.z] + 1); + } + + + protected void getEdgeStep(Step src) { + Step nextEdge; + int x, z; + x = src.x - 1; z = src.z; + if(x >= x1) { + nextEdge = new Step(x, z, src, end, dungeon); + if((spt[x][z] == null)) { + spt[x][z] = nextEdge; + edges.add(nextEdge); + } + } + x = src.x + 1; z = src.z; + if(x >= x1 && x <= x2) { + nextEdge = new Step(x, z, src, end, dungeon); + if((spt[x][z] == null)) { + spt[x][z] = nextEdge; + edges.add(nextEdge); + } + } + x = src.x; z = src.z - 1; + if(z >= z1 && z <= z2) { + nextEdge = new Step(x, z, src, end, dungeon); + if((spt[x][z] == null)) { + spt[x][z] = nextEdge; + edges.add(nextEdge); + } + } + x = src.x; z = src.z + 1; + if(z >= z1 && z <= z2) { + nextEdge = new Step(x, z, src, end, dungeon); + if((spt[x][z] == null)) { + spt[x][z] = nextEdge; + edges.add(nextEdge); + } + } + } +} diff --git a/src/jaredbgreat/dldungeons/planner/astar/AStar2.java b/src/jaredbgreat/dldungeons/planner/astar/AStar2.java new file mode 100644 index 0000000..89a6339 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/astar/AStar2.java @@ -0,0 +1,181 @@ +package jaredbgreat.dldungeons.planner.astar; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import java.util.PriorityQueue; + +import jaredbgreat.dldungeons.pieces.Doorway; +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.planner.mapping.Tile; +import jaredbgreat.dldungeons.rooms.Room; + +public class AStar2 extends AStar { + PriorityQueue edges; // Steps to consider + Step2 root; + + public AStar2(Dungeon dungeon, Room start, Room finish) { + this.dungeon = dungeon; + room = 0; + x1 = 2; + x2 = dungeon.size.width - 3; + z1 = 1; + z2 = dungeon.size.width - 2; + + end = new Tile((int)finish.realX, (int)finish.realZ); + if(end.x < x1) { + x1 = end.x; + } + if (end.x > x2) { + x2 = end.x; + } + if(end.z < z1) { + z1 = end.z; + } + if (end.z > z2) { + z2 = end.z; + } + root = Step2.firstFromDoorway(new Tile((int)start.realX, (int)start.realZ), end); + if(root.x < x1) { + x1 = root.x; + } + if (root.x > x2) { + x2 = root.x; + } + if(root.z < z1) { + z1 = root.z; + } + if (root.z > z2) { + z2 = root.z; + } + + spt = dungeon.map.nodedge; + for(int i = x1; i <= x2; i++) + for(int j = z1; j <= z2; j++) + spt[i][j] = null; + + spt[root.x][root.z] = root; + edges = new PriorityQueue(); + edges.add(root); + } + + + /** + * This uses the data from AStar to make useful changes to the + * dungeon. + * + * @param end + */ + @Override + public void makeRoute(Step end) { + int roomid = dungeon.map.room[end.x][end.z]; + byte floory = dungeon.map.floorY[end.x][end.z]; + byte ceily = (byte)(dungeon.baseHeight + 2); + int size = dungeon.random.nextInt(2) + 1; + Step child = end, parent = end.parent; + if(parent == null) return; + do { + if(dungeon.map.room[child.x][child.z] != 0) { + roomid = dungeon.map.room[child.x][child.z]; + floory = dungeon.map.floorY[child.x][child.z]; + ceily = (byte)(floory + 2); + } else { + for(int i = -size; i <= size; i++) + for(int j = -size; j <= size; j++) { + dungeon.map.floorY[child.x+i][child.z+j] = floory; + dungeon.map.ceilY[child.x+i][child.z+j] = ceily; + dungeon.map.hasLiquid[child.x+i][child.z+j] = false; + if(dungeon.map.room[child.x+i][child.z+j] < 1) { + dungeon.map.room[child.x+i][child.z+j] = roomid; + dungeon.map.isWall[child.x+i][child.z+j] = true; + dungeon.map.floor[child.x+i][child.z+j] = dungeon.floorBlock; + dungeon.map.ceiling[child.x+i][child.z+j] = dungeon.cielingBlock; + dungeon.map.wall[child.x+i][child.z+j] = dungeon.wallBlock1; + + } + if(dungeon.map.astared[child.x+i][child.z+j] || + ((Math.abs(i) < size) && (Math.abs(j) < size))) { + dungeon.map.isDoor[child.x+i][child.z+j] = true; + dungeon.map.isWall[child.x+i][child.z+j] = false; + } + } + } + dungeon.map.astared[child.x][child.z] = true; + if(dungeon.map.isWall[child.x][child.z] || + dungeon.map.isFence[child.x][child.z]) + addDoor(parent, child); + if(dungeon.map.hasLiquid[child.x][child.z]) + fixLiquid(parent, child, + (byte) dungeon.rooms.get(room).floorY); + fixHeights(parent, child); + child = parent; + parent = child.parent; + } while (parent != null); + dungeon.map.astared[child.x][child.z] = true; + if(dungeon.map.isWall[child.x][child.z] || + dungeon.map.isFence[child.x][child.z]) + dungeon.map.isDoor[child.x][child.z] = true; + if(dungeon.map.hasLiquid[child.x][child.z]) { + dungeon.map.hasLiquid[child.x][child.z] = false; + dungeon.map.floorY[child.x][child.z] = + (byte) dungeon.rooms.get(room).floorY; + } + } + + /** + * This is what actually runs A* (and also calls other methods + * to make practical use of the results). + */ + @Override + public void seek() { + Step2 current; + do { + current = edges.poll(); + getEdgeStep(current); + } while(!current.equals(end)); + makeRoute(current); + } + + + @Override + protected void getEdgeStep(Step src) { + Step2 nextEdge; + int x, z; + // Below should probably be a method call, but stingy with overhead + x = src.x - 1; z = src.z; + if(x >= x1 && x <= x2) { + nextEdge = new Step2(x, z, src, end, dungeon); + if(spt[x][z] == null) { + spt[x][z] = nextEdge; + edges.add(nextEdge); + } + } + x = src.x + 1; z = src.z; + if(x >= x1 && x <= x2) { + nextEdge = new Step2(x, z, src, end, dungeon); + if(spt[x][z] == null) { + spt[x][z] = nextEdge; + edges.add(nextEdge); + } + } + x = src.x; z = src.z - 1; + if(z >= z1 && z <= z2) { + nextEdge = new Step2(x, z, src, end, dungeon); + if(spt[x][z] == null) { + spt[x][z] = nextEdge; + edges.add(nextEdge); + } + } + x = src.x; z = src.z + 1; + if(z >= z1 && z <= z2) { + nextEdge = new Step2(x, z, src, end, dungeon); + if(spt[x][z] == null) { + spt[x][z] = nextEdge; + edges.add(nextEdge); + } + } + } + +} diff --git a/src/jaredbgreat/dldungeons/planner/astar/DoorChecker.java b/src/jaredbgreat/dldungeons/planner/astar/DoorChecker.java new file mode 100644 index 0000000..f651858 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/astar/DoorChecker.java @@ -0,0 +1,228 @@ +package jaredbgreat.dldungeons.planner.astar; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.pieces.Doorway; +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.planner.mapping.Tile; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.themes.ThemeFlags; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Random; + +/** + * This class contains utility methods for testing the validity and viability + * of doors. Among other things it will remove the infamous doors to nowhere, + * sort doors by destination room, pick a good door for each room to run the + * A* connectively text-fix on, eliminate doors the transition between liquid + * and non-liquid tiles, and place liquids in doors that have liquid on both + * sides. + * + * @author JaredBGreat (Jared Blackburn) + * + */ +public class DoorChecker { + + + public static class CompareLists implements Comparator { + @Override + public int compare(List o1, List o2) { + return o1.size() - o2.size(); + } + } + static CompareLists c = new CompareLists(); + + + /** + * This will check to see if a tile is a valid location in the + * Dungeon. That is, it will check to see if its both inside + * the dungeons and has a room value other than zero. + * + * @param tile + * @return boolean for if tile is inside a room in the dungeon + */ + public static boolean validateTile(Dungeon dungeon, int x, int z) { + if(x < 0 || x >= dungeon.size.width) return false; + if(z < 0 || z >= dungeon.size.width) return false; + return (dungeon.map.room[x][z] > 0); + } + + + /** + * Will check if a tile representing a door location actually + * connects two rooms, and remove doors that do not. Put differently + * this will remove a door to nowhere and inform the calling method + * if such an action was needed. + * + * @param door + * @return boolean for if the door connects two room in the dungeon + */ + public static boolean validateDoor(Dungeon dungeon, Doorway door) { + return (validateTile(dungeon, door.x - 1, door.z) + && validateTile(dungeon, door.x + 1, door.z) + && validateTile(dungeon, door.x, door.z - 1) + && validateTile(dungeon, door.x, door.z + 1) + && validateTile(dungeon, door.x - 1, door.z - 1) + && validateTile(dungeon, door.x + 1, door.z + 1) + && validateTile(dungeon, door.x + 1, door.z - 1) + && validateTile(dungeon, door.x - 1, door.z + 1)); + } + + + /** + * This will get a list of doors to run A* on for the purpose of + * ensuring room passibility. + * + * @param room + * @return ArrayList of one Doorway per connected room + */ + public static ArrayList makeConnectionList(Room room, Random random) { + ArrayList out = new ArrayList(room.connections.size()); + for(DoorQueue exits : room.connections) { + out.add(exits.peek()); + } + Collections.shuffle(out, random); + return out; + } + + + /** + * This will return the id of the room on the other side of the door. + * + * @param exit + * @param room + * @param dungeon + * @return the id of the connect room + */ + public static int getOtherRoom(Doorway exit, Room room, Dungeon dungeon) { + if(exit.xOriented) { + if(dungeon.map.room[exit.x+1][exit.z] == room.id) + return dungeon.map.room[exit.x-1][exit.z]; + if(dungeon.map.room[exit.x-1][exit.z] == room.id) + return dungeon.map.room[exit.x+1][exit.z]; + } else { + if(dungeon.map.room[exit.x][exit.z+1] == room.id) + return dungeon.map.room[exit.x][exit.z-1]; + if(dungeon.map.room[exit.x][exit.z-1] == room.id) + return dungeon.map.room[exit.x][exit.z+1]; + } + return 0; // This will result in a error (fail-fast -- should not be the nullRoom) + } + + + /** + * This will run A* on exits to ensure all can be reached. It will also + * ensure the same door is used in connected rooms by giving a negative + * value and passing it to the connected rooms DoorQueue. * + * + * @param exits + */ + public static void checkConnections(ArrayList exits, + Room room, Dungeon dungeon) { + if(exits.isEmpty()) return; + Doorway next, current; + ArrayList connected = new ArrayList(exits.size()); + connected.add(exits.remove(exits.size() - 1)); + for(int i = exits.size() -1; i >= 0; --i) { + current = connected.get(dungeon.random.nextInt(connected.size())); + connected.add((next = exits.get(i))); + new AStar(room, dungeon, current, next).seek(); + } + } + + + public static void retestDoors(Dungeon dungeon, Room room) { + if(room.doors.isEmpty()) { + return; + } + for(Doorway door : room.doors) { + if(dungeon.map.astared[door.x][door.z]) continue; + if(door.xOriented) { + if(dungeon.map.isWall[door.x+1][door.z] || + dungeon.map.isWall[door.x-1][door.z]) + dungeon.map.isDoor[door.x][door.z] = false; + if(dungeon.map.hasLiquid[door.x+1][door.z] != + dungeon.map.hasLiquid[door.x-1][door.z]) + dungeon.map.isDoor[door.x][door.z] = false; + if(dungeon.map.hasLiquid[door.x+1][door.z]) { + dungeon.map.hasLiquid[door.x][door.z] = true; + if(dungeon.theme.flags.contains(ThemeFlags.SWAMPY)) + dungeon.map.floorY[door.x][door.z] = (byte) (room.floorY - 1); + else dungeon.map.floorY[door.x][door.z] = (byte) (room.floorY - 2); + } + } else { + if(dungeon.map.isWall[door.x][door.z+1] || + dungeon.map.isWall[door.x][door.z-1]) + dungeon.map.isDoor[door.x][door.z] = false; + if(dungeon.map.hasLiquid[door.x][door.z+1] != + dungeon.map.hasLiquid[door.x][door.z-1]) + dungeon.map.isDoor[door.x][door.z] = false; + if(dungeon.map.hasLiquid[door.x][door.z+1]) { + dungeon.map.hasLiquid[door.x][door.z] = true; + if(dungeon.theme.flags.contains(ThemeFlags.SWAMPY)) + dungeon.map.floorY[door.x][door.z] = (byte) (room.floorY - 1); + else dungeon.map.floorY[door.x][door.z] = (byte) (room.floorY - 2); + } + } + } + } + + + public static void processDoors1(Dungeon dungeon, Room room) { + ArrayList invalid = new ArrayList(); + boolean valid; + for(Doorway door : room.doors) { + valid = validateDoor(dungeon, door); + if(!valid) { + invalid.add(door); + dungeon.map.isDoor[door.x][door.z] = false; + } else { + door.prioritize(dungeon, room.id); // Will only be run on valid doors + room.addToConnections(door); + } + } + room.doors.removeAll(invalid); + } + + + public static void checkConnectivity(Dungeon dungeon) { + ArrayList> sections = new RoomBFS(dungeon).check(); + while(sections.size() > 1) { + Collections.sort(sections, c); + new AStar2(dungeon, sections.get(0).get(0), + sections.get(1).get(0)).seek(); + sections.get(1).addAll(sections.get(0)); + sections.remove(0); + } + } + + + public static void processDoors2(Dungeon dungeon, Room room) { + room.topDoors = makeConnectionList(room, dungeon.random); + for(Doorway exit : room.topDoors) { + exit.priority -= 16; + dungeon.rooms.get(getOtherRoom(exit, room, dungeon)) + .addToConnections(new Doorway(exit, room.id)); + } + } + + + public static void processDoors3(Dungeon dungeon, Room room) { + checkConnections(room.topDoors, room, dungeon); + retestDoors(dungeon, room); + } + + + public static void caveConnector(Dungeon dungeon, Room cave) { + for(Doorway door : cave.doors) { + new AStar(cave, dungeon, cave.midpoint, dungeon.rooms.get(door.otherside).midpoint).seek(); + } + } +} diff --git a/src/jaredbgreat/dldungeons/planner/astar/DoorQueue.java b/src/jaredbgreat/dldungeons/planner/astar/DoorQueue.java new file mode 100644 index 0000000..aaf83e8 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/astar/DoorQueue.java @@ -0,0 +1,38 @@ +package jaredbgreat.dldungeons.planner.astar; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.pieces.Doorway; +import java.util.PriorityQueue; + +/** + * A priority queue for storing doors which should sort + * them in order of fitness as connections between rooms. + * + * @author Jared Blackburn + * + */ +public class DoorQueue extends PriorityQueue { + private int roomid; + + + public DoorQueue(int id) { + super(); + roomid = id; + } + + + /** + * True if the other id passed is the same as that of the room + * that owns these doors. + * + * @param id + * @return id == roomid + */ + public boolean isRoom(int id) { + return id == roomid; + } +} diff --git a/src/jaredbgreat/dldungeons/planner/astar/RoomBFS.java b/src/jaredbgreat/dldungeons/planner/astar/RoomBFS.java new file mode 100644 index 0000000..4654083 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/astar/RoomBFS.java @@ -0,0 +1,64 @@ +package jaredbgreat.dldungeons.planner.astar; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.rooms.Room; +import java.util.ArrayDeque; +import java.util.ArrayList; + + +public class RoomBFS { + private ArrayDeque roomQueue = new ArrayDeque(); + private Dungeon dungeon; + private ArrayList nodes; + private boolean[] checked; + + + public RoomBFS(Dungeon dungeon) { + this.dungeon = dungeon; + nodes = new ArrayList(dungeon.numNodes); + checked = new boolean[dungeon.roomCount + 1]; + for(int i = dungeon.numNodes + 1; i > 0; i--) { + Room room = dungeon.rooms.get(i); + if(room.isNode) nodes.add(room); + } + } + + + public ArrayList> check() { + ArrayList> sections = new ArrayList>(); + while(!nodes.isEmpty()) { + sections.add(search(nodes.get(0))); + } +// System.out.println("[DLDUNGEONS] Dungeon has " + sections.size() +// + " sections."); +// if(sections.size() > 1) System.out.println("[DLDUNGEONS] Dungeon " +// + "is not connected!"); + return sections; + } + + + public ArrayList search(Room room) { + Room next; + roomQueue.add(room); + ArrayList found = new ArrayList(); + while(!nodes.isEmpty() && !roomQueue.isEmpty()) { + next = roomQueue.poll(); + checked[next.id] = true; + if(next.isNode) { + nodes.remove(next); + found.add(next); + } + for(DoorQueue exit : next.connections) { + if(!checked[exit.peek().otherside]) + roomQueue.add(dungeon.rooms.get(exit.peek().otherside)); + } + } + return found; + } +} diff --git a/src/jaredbgreat/dldungeons/planner/astar/Step.java b/src/jaredbgreat/dldungeons/planner/astar/Step.java new file mode 100644 index 0000000..bd3ab02 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/astar/Step.java @@ -0,0 +1,98 @@ +package jaredbgreat.dldungeons.planner.astar; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import java.util.EnumMap; + +import jaredbgreat.dldungeons.pieces.Doorway; +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.planner.mapping.Tile; +import jaredbgreat.dldungeons.themes.ThemeFlags; + +/**This meant to represent a Tile (block column / xz coordinate) that acts + * as a both a node and an implied edge (from the previous node) in an + * implied nav-graph consisting of the rooms floor surface. + * + * The purpose of this is for storing steps on the route from door to + * door, both in an abstract PriorityQueue and in a tree representing + * valid routes. + * + * @author JaredBGreat (Jared Blackburn) + * + */ +public class Step extends Tile implements Comparable { +// FIXME: This class has a lot data that turn out to be extraneous + + int changes; // Changes made to create a player-passable route + int distance; // Tiles traversed from start to get here + int heuristic; // Manhattan distance to destination + int value; // (distance + 16*changes) + heuristic + + Step parent; + + + Step(int x, int z, int traversed, int changes, Tile destination) { + super(x, z); + distance = traversed; + this.changes = changes; + heuristic = Math.abs(x - destination.x) + Math.abs(z - destination.z); + value = (changes * 16) + distance + heuristic; + parent = null; + } + + + /** + * The preferred way to constructor for creating a Step. + * + * @param x + * @param z + * @param previous + * @param destination + * @param dungeon + */ + public Step(int x, int z, Step previous, Tile destination, Dungeon dungeon) { + super(x, z); + distance = previous.distance + 1; + heuristic = Math.abs(x - destination.x) + Math.abs(z - destination.z); + changes = previous.changes; + if(dungeon.map.isWall[x][z]) changes++; + if(dungeon.map.isFence[x][z]) changes++; + if(dungeon.map.hasLiquid[x][z]) changes++; + if(Math.abs(dungeon.map.floorY[x][z] + - dungeon.map.floorY[previous.x][previous.z]) > 1) changes++; + value = (changes * 16) + distance + heuristic; + parent = previous; + } + + + /** + * Returns the first step from a Tile ("door") toward a destination Tile. + * + * @param door + * @param destination + * @return first step from door to destination + */ + public static Step firstFromDoorway(Tile door, Tile destination) { + return new Step(door.x, door.z, 0, 0, destination); + } + + + /** + * Returns a Tile with the same coordinates as the Step + * + * @return The base Tile representation of this Step + */ + public Tile getTile() { + return new Tile(x, z); + } + + + @Override + public int compareTo(Step o) { + return value - o.value; + } + +} diff --git a/src/jaredbgreat/dldungeons/planner/astar/Step2.java b/src/jaredbgreat/dldungeons/planner/astar/Step2.java new file mode 100644 index 0000000..b08159c --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/astar/Step2.java @@ -0,0 +1,30 @@ +package jaredbgreat.dldungeons.planner.astar; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.planner.mapping.Tile; + +public class Step2 extends Step { + + public Step2(int x, int z, Step previous, Tile destination, Dungeon dungeon) { + super(x, z, previous, destination, dungeon); + if(!dungeon.map.astared[x][z]) value += 7; + if(dungeon.map.room[x][z] == 0) value += 512; + } + + + public Step2(int x, int z, int i, int j, Tile destination) { + super(x, z, i, j, destination); + } + + + public static Step2 firstFromDoorway(Tile door, Tile destination) { + return new Step2(door.x, door.z, 0, 0, destination); + } + + +} diff --git a/src/jaredbgreat/dldungeons/planner/features/Cutout.java b/src/jaredbgreat/dldungeons/planner/features/Cutout.java new file mode 100644 index 0000000..a6dd57e --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/features/Cutout.java @@ -0,0 +1,130 @@ +package jaredbgreat.dldungeons.planner.features; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.pieces.Shape; +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.themes.Degree; + +/** + * A chance for to add a wall segment to the room. + * + * @author Jared Blackburn + * + */ +public class Cutout extends FeatureAdder { + + public Cutout(Degree chance) { + super(chance); + } + + @Override + public boolean addFeature(Dungeon dungeon, Room room) { + boolean built = chance.use(dungeon.random); + if(built) buildFeature(dungeon, room); + return built; + } + + @Override + public void buildFeature(Dungeon dungeon, Room room) { + float centerX, centerZ, oppX, oppZ; + float dimX, dimZ; + int rotation = dungeon.random.nextInt(4); + Shape[] which; + dimX = ((room.endX - room.beginX) * ((dungeon.random.nextFloat() * 0.20f) + 0.10f)); + dimZ = ((room.endX - room.beginX) * ((dungeon.random.nextFloat() * 0.20f) + 0.10f)); + centerX = dungeon.random.nextInt(room.endX - room.beginX -1) + room.beginX + 1; + centerZ = dungeon.random.nextInt(room.endZ - room.beginZ -1) + room.beginZ + 1; + oppX = room.endX - (centerX - room.beginX); + oppZ = room.endZ - (centerZ - room.beginZ); + if(room.sym.halfX) { + dimX *= 2; + dimX /= 3; + oppX = room.endX - ((centerX - room.beginX) / 2); + centerX = ((centerX - room.beginX) / 2) + room.beginX; + } + if(room.sym.halfZ) { + dimZ *= 2; + dimZ /= 3; + oppZ = room.endZ -((centerZ - room.beginZ) / 2); + centerZ = ((centerZ - room.beginZ) / 2) + room.beginZ; + } + if(room.sym.doubler) { + dimX *= 0.7; + dimZ *= 0.7; + } + centerX++; + centerZ++; + oppX++; + oppZ++; + if(!dungeon.complexity.use(dungeon.random)) { + which = Shape.xgroup; + } else { + which = Shape.allSolids[dungeon.random.nextInt(Shape.allSolids.length)]; + } + which[rotation].drawCutout(dungeon, room, centerX, centerZ, dimX, dimZ, false, false); + // Apply Symmetries + switch (room.sym) { + case NONE: break; + case TR1: { + oppX = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + oppZ = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + which[(rotation + 1) % 4].drawCutout(dungeon, room, oppX, + oppZ, dimX, dimZ, false, false); + } break; + case TR2: { + oppX = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + oppZ = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + oppZ = room.endZ - (oppZ - room.beginZ); + which[(rotation + 1) % 4].drawCutout(dungeon, room, oppX, + oppZ, dimX, dimZ, false, true); + } break; + case X: { + which[rotation].drawCutout(dungeon, room, oppX, + centerZ, dimX, dimZ, true, false); + } break; + case Z: { + which[rotation].drawCutout(dungeon, room, centerX, + oppZ, dimX, dimZ, false, true); + } break; + case XZ: { + which[rotation].drawCutout(dungeon, room, oppX, + centerZ, dimX, dimZ, true, false); + which[rotation].drawCutout(dungeon, room, centerX, + oppZ, dimX, dimZ, false, true); + which[rotation].drawCutout(dungeon, room, oppX, + oppZ, dimX, dimZ, true, true); + } break; + case R: { + which[(rotation + 2) % 4].drawCutout(dungeon, room, oppX, + oppZ, dimX, dimZ, false, false); + } break; + case SW: { + float swX1 = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + float swZ1 = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + float swX2 = room.realX + ((oppZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + float swZ2 = room.realZ + ((oppX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + which[(rotation + 1) % 4].drawCutout(dungeon, room, swX2, + swZ1, dimX, dimZ, false, false); + which[(rotation + 3) % 4].drawCutout(dungeon, room, swX1, + swZ2, dimX, dimZ, false, false); + which[(rotation + 2) % 4].drawCutout(dungeon, room, oppX, + oppZ, dimX, dimZ, false, false); + } + } + } +} diff --git a/src/jaredbgreat/dldungeons/planner/features/Depression.java b/src/jaredbgreat/dldungeons/planner/features/Depression.java new file mode 100644 index 0000000..a8db0c2 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/features/Depression.java @@ -0,0 +1,26 @@ +package jaredbgreat.dldungeons.planner.features; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.themes.Degree; + +/** + * A chance to add an area of lower floor height (i.e., a pit + * or depression). + * + * @author Jared Blackburn + * + */ +public class Depression extends IslandPlatform { + + public Depression(Degree chance){ + super(chance); + } +} diff --git a/src/jaredbgreat/dldungeons/planner/features/FeatureAdder.java b/src/jaredbgreat/dldungeons/planner/features/FeatureAdder.java new file mode 100644 index 0000000..4183df0 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/features/FeatureAdder.java @@ -0,0 +1,61 @@ +package jaredbgreat.dldungeons.planner.features; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.themes.Degree; + + +/** + * A base class for all room features. This allows a chance for + * a type of feature occurring to be store in a collection and sorted + * to randomize the order of evaluation. + * + * @author Jared Blackburn + * + */ +public abstract class FeatureAdder { + + /** + * The chance of placing the feature on a given use. + */ + Degree chance; + + public FeatureAdder(Degree chance) { + this.chance = chance; + } + + + /** + * This will try to add the feature to the room, based on the features + * pre-defined degree of chance. The actual feature is built by calling + * a method back on the room. It will return true if the room was + * instructed to add the feature, and false otherwise; whether or not the + * feature was actually added successfully is another matter. + * + * @param dungeon + * @param room + * @return the result of chance.use() + */ + public boolean addFeature(Dungeon dungeon, Room room) { + boolean built = chance.use(dungeon.random); + if(built) buildFeature(dungeon, room); + return built; + } + + + /** + * This will actually build the feature into the room. + * + * @param dungeon + * @param room + */ + public abstract void buildFeature(Dungeon dungeon, Room room); + +} diff --git a/src/jaredbgreat/dldungeons/planner/features/IslandPlatform.java b/src/jaredbgreat/dldungeons/planner/features/IslandPlatform.java new file mode 100644 index 0000000..2d78995 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/features/IslandPlatform.java @@ -0,0 +1,140 @@ +package jaredbgreat.dldungeons.planner.features; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.pieces.Shape; +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.themes.Degree; + +/** + * A chance to add a platform. + * + * @author Jared Blackurn + * + */ +public class IslandPlatform extends FeatureAdder { + protected boolean isDepression; + + public IslandPlatform(Degree chance) { + super(chance); + isDepression = this instanceof Depression; + } + + + @Override + public void buildFeature(Dungeon dungeon, Room room) { + int available = room.ceilY - room.floorY; + if(available < 4) return; + float dimX, dimZ, centerX, centerZ, oppX, oppZ; + byte platY; + int rotation = dungeon.random.nextInt(4); + Shape[] which; + dimX = ((room.endX - room.beginX) * ((dungeon.random.nextFloat() * 0.25f) + 0.15f)); + dimZ = ((room.endX - room.beginX) * ((dungeon.random.nextFloat() * 0.25f) + 0.15f)); + centerX = dungeon.random.nextInt(room.endX - room.beginX - 1) + room.beginX + 1; + centerZ = dungeon.random.nextInt(room.endZ - room.beginZ - 1) + room.beginZ + 1; + oppX = room.endX - (centerX - room.beginX); + oppZ = room.endZ - (centerZ - room.beginZ); + if(room.sym.halfX) { + dimX *= 2; + dimX /= 3; + oppX = room.endX - ((centerX - room.beginX) / 2); + centerX = ((centerX - room.beginX) / 2) + room.beginX; + } + if(room.sym.halfZ) { + dimZ *= 2; + dimZ /= 3; + oppZ = room.endZ -((centerZ - room.beginZ) / 2); + centerZ = ((centerZ - room.beginZ) / 2) + room.beginZ; + } + if(room.sym.doubler) { + dimX *= 0.75; + dimZ *= 0.75; + } + centerX++; + centerZ++; + oppX++; + oppZ++; + if(isDepression) { + available -= 2; + if(available > ((dungeon.verticle.value / 2) + 1)) available = ((dungeon.verticle.value / 2) + 1); + platY = (byte) (room.floorY - dungeon.random.nextInt((dungeon.verticle.value / 2) + 1) -1); + } + else { + platY = (byte) (room.floorY + 1 + (dungeon.random.nextInt(2))); + if(available > 4) platY += (byte)(dungeon.random.nextInt(available - 3)); + } + if(dungeon.random.nextBoolean() || !dungeon.complexity.use(dungeon.random)) { + which = Shape.xgroup; + } else { + which = Shape.allSolids[dungeon.random.nextInt(Shape.allSolids.length)]; + } + if(platY > room.nFloorY) room.nFloorY = platY; + which[rotation].drawPlatform(dungeon, room, platY, centerX, + centerZ, dimX, dimZ, false, false); + // Apply Symmetries + switch (room.sym) { + case NONE: break; + case TR1: { + oppX = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + oppZ = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + which[(rotation + 3) % 4].drawPlatform(dungeon, room, platY, oppX, + oppZ, dimX, dimZ, false, false); + } break; + case TR2: { + oppX = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + oppZ = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + oppZ = room.endZ - (oppZ - room.beginZ); + which[(rotation + 3) % 4].drawPlatform(dungeon, room, platY, oppX, + oppZ, dimX, dimZ, false, true); + } break; + case X: { + which[rotation].drawPlatform(dungeon, room, platY, oppX, + centerZ, dimX, dimZ, true, false); + } break; + case Z: { + which[rotation].drawPlatform(dungeon, room, platY, centerX, + oppZ, dimX, dimZ, false, true); + } break; + case XZ: { + which[rotation].drawPlatform(dungeon, room, platY, oppX, + centerZ, dimX, dimZ, true, false); + which[rotation].drawPlatform(dungeon, room, platY, centerX, + oppZ, dimX, dimZ, false, true); + which[rotation].drawPlatform(dungeon, room, platY, oppX, + oppZ, dimX, dimZ, true, true); + } break; + case R: { + which[(rotation + 2) % 4].drawPlatform(dungeon, room, platY, oppX, + oppZ, dimX, dimZ, false, false); + } break; + case SW: { + float swX1 = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + float swZ1 = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + float swX2 = room.realX + ((oppZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + float swZ2 = room.realZ + ((oppX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + which[(rotation + 1) % 4].drawPlatform(dungeon, room, platY, swX2, swZ1, + dimX, dimZ, false, false); + which[(rotation + 3) % 4].drawPlatform(dungeon, room, platY, swX1, swZ2, + dimX, dimZ, false, false); + which[(rotation + 2) % 4].drawPlatform(dungeon, room, platY, oppX, oppZ, + dimX, dimZ, false, false); + } + } + } + +} diff --git a/src/jaredbgreat/dldungeons/planner/features/IslandRoom.java b/src/jaredbgreat/dldungeons/planner/features/IslandRoom.java new file mode 100644 index 0000000..4a6f3c1 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/features/IslandRoom.java @@ -0,0 +1,146 @@ +package jaredbgreat.dldungeons.planner.features; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.planner.RoomSeed; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.themes.Degree; + +/** + * A chance to add a sub-room inside the main room. + * + * @author Jared Blackburn + * + */ +public class IslandRoom extends FeatureAdder { + private boolean built; + + public IslandRoom(Degree chance) { + super(chance); + } + + + + public boolean addFeature(Dungeon dungeon, Room room) { + built = chance.use(dungeon.random); + if(built) buildFeature(dungeon, room); + return built; + } + + + @Override + public void buildFeature(Dungeon dungeon, Room room) { + built = buildSubroom(dungeon, room); + } + + + private boolean buildSubroom(Dungeon dungeon, Room room) { + int dimX = (int)((room.endX - room.beginX) + * (0.2f + (0.3f * dungeon.random.nextFloat()))); + int dimZ = (int)((room.endZ - room.beginZ) + * (0.2f + (0.3f * dungeon.random.nextFloat()))); + float centerX, centerZ, oppX, oppZ; + centerX = dungeon.random.nextInt(room.endX - room.beginX) + room.beginX; + centerZ = dungeon.random.nextInt(room.endZ - room.beginZ) + room.beginZ; + oppX = room.endX - (centerX - room.beginX); + oppZ = room.endZ - (centerZ - room.beginZ); + if(room.sym.halfX) { + dimX *= 2; + dimX /= 3; + oppX = room.endX - ((centerX - room.beginX) / 2); + centerX = ((centerX - room.beginX) / 2) + room.beginX; + } + if(room.sym.halfZ) { + dimZ *= 2; + dimZ /= 3; + oppZ = room.endZ -((centerZ - room.beginZ) / 2); + centerZ = ((centerZ - room.beginZ) / 2) + room.beginZ; + } + if(room.sym.doubler) { + dimX *= 0.75; + dimZ *= 0.75; + } + if((dimX < 5) || (dimZ < 5)) return false; + int ymod = (dimX <= dimZ) ? (int) Math.sqrt(dimX) : (int) Math.sqrt(dimZ); + int height = dungeon.random.nextInt((dungeon.verticle.value / 2) + ymod + 1) + 2; + Room created = + new RoomSeed((int)centerX, room.floorY, + (int)centerZ).growRoom(dimX, dimZ, height, dungeon, room, room); + if(created == null) return false; + // Apply Symmetries + switch (room.sym) { + case NONE: break; + case TR1: { + oppX = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + oppZ = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + created = + new RoomSeed((int)oppX, room.floorY, + (int)oppZ).growRoom(dimZ, dimX, height, dungeon, room, room); + } break; + case TR2: { + oppX = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + oppZ = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + oppZ = room.endZ - (oppZ - room.beginZ); + created = + new RoomSeed((int)oppX, room.floorY, + (int)oppZ).growRoom(dimZ, dimX, height, dungeon, room, room); + } break; + case X: { + created = + new RoomSeed((int)oppX, room.floorY, + (int)centerZ).growRoom(dimX, dimZ, height, dungeon, room, room); + } break; + case Z: { + created = + new RoomSeed((int)centerX, room.floorY, + (int)oppZ).growRoom(dimX, dimZ, height, dungeon, room, room); + } break; + case XZ: { + created = + new RoomSeed((int)oppX, room.floorY, + (int)centerZ).growRoom(dimX, dimZ, height, dungeon, room, room); + created = + new RoomSeed((int)centerX, room.floorY, + (int)oppZ).growRoom(dimX, dimZ, height, dungeon, room, room); + created = + new RoomSeed((int)oppX, room.floorY, + (int)oppZ).growRoom(dimX, dimZ, height, dungeon, room, room); + } break; + case R: { + created = + new RoomSeed((int)oppX, room.floorY, + (int)oppZ).growRoom(dimX, dimZ, height, dungeon, room, room); + } break; + case SW: { + float swX1 = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + float swZ1 = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + float swX2 = room.realX + ((oppZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + float swZ2 = room.realZ + ((oppX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + created = + new RoomSeed((int)swX2, room.floorY, + (int)swZ1).growRoom(dimZ, dimX, height, dungeon, room, room); + created = + new RoomSeed((int)swX1, room.floorY, + (int)swZ2).growRoom(dimZ, dimX, height, dungeon, room, room); + created = + new RoomSeed((int)oppX, room.floorY, + (int)oppZ).growRoom(dimX, dimZ, height, dungeon, room, room); + } + } + return true; + } +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/planner/features/Pillar.java b/src/jaredbgreat/dldungeons/planner/features/Pillar.java new file mode 100644 index 0000000..1e73308 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/features/Pillar.java @@ -0,0 +1,91 @@ +package jaredbgreat.dldungeons.planner.features; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.themes.Degree; + +/** + * A chance to add a pillar / column (1x1 wall with a different block) + * into a room. + * + * @author Jared Blackburn + * + */ +public class Pillar extends FeatureAdder { + + public Pillar(Degree chance) { + super(chance); + } + + + @Override + public void buildFeature(Dungeon dungeon, Room room) { + int pillarx1 = dungeon.random.nextInt(room.endX - room.beginX - 2) + 1; + int pillarz1 = dungeon.random.nextInt(room.endZ - room.beginZ - 2) + 1; + if(room.sym.halfX) pillarx1 = ((pillarx1 - 1) / 2) + 1; + if(room.sym.halfZ) pillarz1 = ((pillarz1 - 1) / 2) + 1; + int pillarx2 = room.endX - pillarx1; + int pillarz2 = room.endZ - pillarz1; + pillarx1 += room.beginX; + pillarz1 += room.beginZ; + switch (room.sym) { + case NONE: break; + case TR1: + dungeon.map.isWall[pillarx1][pillarz1] = true; + dungeon.map.isWall[pillarz1][pillarx1] = true; + dungeon.map.wall[pillarx1][pillarz1] = room.pillarBlock; + dungeon.map.wall[pillarz1][pillarx1] = room.pillarBlock; + break; + case TR2: + dungeon.map.isWall[pillarx1][pillarz1] = true; + dungeon.map.isWall[pillarz1][pillarx1] = true; + dungeon.map.wall[pillarx2][pillarz1] = room.pillarBlock; + dungeon.map.wall[pillarz2][pillarx1] = room.pillarBlock; + break; + case X: + dungeon.map.isWall[pillarx1][pillarz1] = true; + dungeon.map.isWall[pillarx2][pillarz1] = true; + dungeon.map.wall[pillarx1][pillarz1] = room.pillarBlock; + dungeon.map.wall[pillarx2][pillarz1] = room.pillarBlock; + break; + case Z: + dungeon.map.isWall[pillarx1][pillarz1] = true; + dungeon.map.isWall[pillarx1][pillarz2] = true; + dungeon.map.wall[pillarx1][pillarz1] = room.pillarBlock; + dungeon.map.wall[pillarx1][pillarz2] = room.pillarBlock; + break; + case XZ: + dungeon.map.isWall[pillarx1][pillarz1] = true; + dungeon.map.isWall[pillarx1][pillarz2] = true; + dungeon.map.isWall[pillarx2][pillarz1] = true; + dungeon.map.isWall[pillarx2][pillarz2] = true; + dungeon.map.wall[pillarx1][pillarz1] = room.pillarBlock; + dungeon.map.wall[pillarx1][pillarz2] = room.pillarBlock; + dungeon.map.wall[pillarx2][pillarz1] = room.pillarBlock; + dungeon.map.wall[pillarx2][pillarz2] = room.pillarBlock; + break; + case R: + dungeon.map.isWall[pillarx1][pillarz1] = true; + dungeon.map.isWall[pillarx2][pillarz2] = true; + dungeon.map.wall[pillarx1][pillarz1] = room.pillarBlock; + dungeon.map.wall[pillarx2][pillarz2] = room.pillarBlock; + break; + case SW: + dungeon.map.isWall[pillarx1][pillarz1] = true; + dungeon.map.isWall[pillarx1][pillarz2] = true; + dungeon.map.isWall[pillarx2][pillarz1] = true; + dungeon.map.isWall[pillarx2][pillarz2] = true; + dungeon.map.wall[pillarx1][pillarz1] = room.pillarBlock; + dungeon.map.wall[pillarx1][pillarz2] = room.pillarBlock; + dungeon.map.wall[pillarx2][pillarz1] = room.pillarBlock; + dungeon.map.wall[pillarx2][pillarz2] = room.pillarBlock; + } + } +} diff --git a/src/jaredbgreat/dldungeons/planner/features/Pool.java b/src/jaredbgreat/dldungeons/planner/features/Pool.java new file mode 100644 index 0000000..854ecd0 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/features/Pool.java @@ -0,0 +1,131 @@ +package jaredbgreat.dldungeons.planner.features; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.pieces.Shape; +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.themes.Degree; + +/** + * A chance to add a pool of liquid (or a liquid stand-in). + * + * @author Jared Blackburn + * + */ +public class Pool extends FeatureAdder { + + public Pool(Degree chance) { + super(chance); + } + + + @Override + public void buildFeature(Dungeon dungeon, Room room) { + float centerX, centerZ, oppX, oppZ; + float dimX, dimZ; + int rotation = dungeon.random.nextInt(4); + Shape[] which; + dimX = ((room.endX - room.beginX) + * ((dungeon.random.nextFloat() * 0.25f) + 0.15f)); + dimZ = ((room.endX - room.beginX) + * ((dungeon.random.nextFloat() * 0.25f) + 0.15f)); + centerX = dungeon.random.nextInt(room.endX - room.beginX -1) + room.beginX + 1; + centerZ = dungeon.random.nextInt(room.endZ - room.beginZ -1) + room.beginZ + 1; + oppX = room.endX - (centerX - room.beginX); + oppZ = room.endZ - (centerZ - room.beginZ); + if(room.sym.halfX) { + dimX *= 2; + dimX /= 3; + oppX = room.endX - ((centerX - room.beginX) / 2); + centerX = ((centerX - room.beginX) / 2) + room.beginX; + } + if(room.sym.halfZ) { + dimZ *= 2; + dimZ /= 3; + oppZ = room.endZ -((centerZ - room.beginZ) / 2); + centerZ = ((centerZ - room.beginZ) / 2) + room.beginZ; + } + if(room.sym.doubler) { + dimX *= 0.75; + dimZ *= 0.75; + } + centerX++; + centerZ++; + oppX++; + oppZ++; + if(dungeon.random.nextBoolean() || !dungeon.complexity.use(dungeon.random)) { + which = Shape.xgroup; + } else { + which = Shape.allshapes[dungeon.random.nextInt(Shape.allshapes.length)]; + } + which[rotation].drawLiquid(dungeon, room, centerX, centerZ, dimX, dimZ, false, false); + // Apply Symmetries + switch (room.sym) { + case NONE: break; + case TR1: { + oppX = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + oppZ = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + which[(rotation + 1) % 4].drawLiquid(dungeon, room, oppX, + oppZ, dimX, dimZ, false, false); + } break; + case TR2: { + oppX = room.realX + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + oppZ = room.realZ + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + oppZ = room.endZ - (oppZ - room.beginZ); + which[(rotation + 1) % 4].drawLiquid(dungeon, room, oppX, + oppZ, dimX, dimZ, false, true); + } break; + case X: { + which[rotation].drawLiquid(dungeon, room, oppX, + centerZ, dimX, dimZ, true, false); + } break; + case Z: { + which[rotation].drawLiquid(dungeon, room, centerX, + oppZ, dimX, dimZ, false, true); + } break; + case XZ: { + which[rotation].drawLiquid(dungeon, room, oppX, + centerZ, dimX, dimZ, true, false); + which[rotation].drawLiquid(dungeon, room, centerX, + oppZ, dimX, dimZ, false, true); + which[rotation].drawLiquid(dungeon, room, oppX, + oppZ, dimX, dimZ, true, true); + } break; + case R: { + which[(rotation + 2) % 4].drawLiquid(dungeon, room, oppX, + oppZ, dimX, dimZ, false, false); + } break; + case SW: { + float swX1 = room.realX + + ((centerZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + float swZ1 = room.realZ + + ((centerX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + float swX2 = room.realX + + ((oppZ - room.realZ) + / (room.endZ - room.beginZ)) * (room.endX - room.beginX); + float swZ2 = room.realZ + + ((oppX - room.realX) + / (room.endX - room.beginX)) * (room.endZ - room.beginZ); + which[(rotation + 1) % 4].drawLiquid(dungeon, room, swX2, + swZ1, dimX, dimZ, false, false); + which[(rotation + 3) % 4].drawLiquid(dungeon, room, swX1, + swZ2, dimX, dimZ, false, false); + which[(rotation + 2) % 4].drawLiquid(dungeon, room, oppX, + oppZ, dimX, dimZ, false, false); + } + } + } + +} diff --git a/src/jaredbgreat/dldungeons/planner/mapping/MapMatrix.java b/src/jaredbgreat/dldungeons/planner/mapping/MapMatrix.java new file mode 100644 index 0000000..e361e72 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/mapping/MapMatrix.java @@ -0,0 +1,245 @@ +package jaredbgreat.dldungeons.planner.mapping; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +//import jaredbgreat.dldungeons.api.DLDEvent; +import jaredbgreat.dldungeons.builder.DBlock; +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.planner.astar.Step; +import jaredbgreat.dldungeons.rooms.Room; +import jaredbgreat.dldungeons.themes.ThemeFlags; +import org.bukkit.Material; +import org.bukkit.World; +//import net.minecraft.block.Block; +//import net.minecraft.util.math.BlockPos; +//import net.minecraft.world.World; +//import net.minecraftforge.common.MinecraftForge; + +/** + * A two dimensional map of the dungeon, including heights, blocks, and + * certain features such as fall and doorways, and pathfinding data. + * + * This map also includes the method for building itself into the actual + * world, converting the 2 1/2 d mapping into blocks. + * + * @author Jared Blackburn + * + */ +public class MapMatrix { + private static final Material lapis = Material.LAPIS_BLOCK; + private static final Material slab = Material.STONE_SLAB;//Block.getBlockFromName("double_stone_slab"); + private static final Material gold = Material.GOLD_BLOCK; + private static final Material glass = Material.GLASS; + + private static boolean drawFlyingMap = false; + + public final World world; + public final int chunkX, chunkZ, origenX, origenZ; + + // map of heights to build at + public byte[][] ceilY; // Ceiling height + public byte[][] floorY; // Floor Height + public byte[][] nCeilY; // Height of Neighboring Ceiling + public byte[][] nFloorY; // Height of Neighboring Floor + + // Blocks referenced against the DBlock.registry + public int[][] ceiling; + public int[][] wall; + public int[][] floor; + + // The room id (index of the room in the dungeons main RoomList) + public int[][] room; + + // Is it a wall? + public boolean[][] isWall; // Is this coordinate occupied by a wall? + public boolean[][] isFence; // Is this coordinate occupied by a wall? + public boolean[][] hasLiquid; // Is floor covered by a liquid block? + public boolean[][] isDoor; // Is there a door here? + + //The A* scratch pad + public Step nodedge[][]; + public boolean astared[][]; + + + public MapMatrix(int width, World world, int chunkX, int chunkZ) { + this.world = world; + this.chunkX = chunkX; + this.chunkZ = chunkZ; + origenX = (chunkX * 16) - (width / 2) + 8; + origenZ = (chunkZ * 16) - (width / 2) + 8; + ceilY = new byte[width][width]; + floorY = new byte[width][width]; + nCeilY = new byte[width][width]; + nFloorY = new byte[width][width]; + room = new int[width][width]; + ceiling = new int[width][width]; + wall = new int[width][width]; + floor = new int[width][width]; + isWall = new boolean[width][width]; + isFence = new boolean[width][width]; + hasLiquid = new boolean[width][width]; + isDoor = new boolean[width][width]; + nodedge = new Step[width][width]; + astared = new boolean[width][width]; + } + + + /** + * This will build the dungeon into the world, transforming the information + * mapped here in 2D arrays into the finished 3D structure in the Minecraft + * world. + * + * @param dungeon + */ + public void build(Dungeon dungeon) { +// DoomlikeDungeons.profiler.startTask("Building Dungeon in World"); +// DoomlikeDungeons.profiler.startTask("Building Dungeon architecture"); + int shiftX = (chunkX * 16) - (room.length / 2) + 8; + int shiftZ = (chunkZ * 16) - (room.length / 2) + 8; + int below; + boolean flooded = dungeon.theme.flags.contains(ThemeFlags.WATER); +// MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.BeforeBuild(this, shiftX, shiftZ, flooded)); + + for(int i = 0; i < room.length; i++) + for(int j = 0; j < room.length; j++) { + if(room[i][j] != 0) { + Room theRoom = dungeon.rooms.get(room[i][j]); + + // Debugging code; should not normally run + if(drawFlyingMap) { + if(astared[i][j]) { + DBlock.placeBlock(world, shiftX + i, 96, shiftZ +j, lapis); + } else if(isDoor[i][j]) { + DBlock.placeBlock(world, shiftX + i, 96, shiftZ +j, slab); + } else if(isWall[i][j]) { + DBlock.placeBlock(world, shiftX + i, 96, shiftZ +j, gold); + } else { + DBlock.placeBlock(world, shiftX + i, 96, shiftZ +j, glass); + } + } + + // Lower parts of the room + if(nFloorY[i][j] < floorY[i][j]) + for(int k = nFloorY[i][j]; k < floorY[i][j]; k++) + if(noLowDegenerate(theRoom, shiftX + i, k, shiftZ + j, i, j)) + DBlock.place(world, shiftX + i, k, shiftZ + j, wall[i][j]); + if(nFloorY[i][j] > floorY[i][j]) + for(int k = floorY[i][j]; k < nFloorY[i][j]; k++) + if(noLowDegenerate(theRoom, shiftX + i, k, shiftZ + j, i, j)) + DBlock.place(world, shiftX + i, k, shiftZ + j, wall[i][j]); + + if(noLowDegenerate(theRoom, shiftX + i, floorY[i][j] - 1, shiftZ + j, i, j)) { + DBlock.place(world, shiftX + i, floorY[i][j] - 1, shiftZ + j, floor[i][j]); + if(dungeon.theme.buildFoundation) { + below = nFloorY[i][j] < floorY[i][j] ? nFloorY[i][j] - 1 : floorY[i][j] - 2; + while(!DBlock.isGroundBlock(world, shiftX + i, below, shiftZ + j)) { + DBlock.place(world, shiftX + i, below, shiftZ + j, dungeon.floorBlock); + below--; + if(below < 0) break; + } + } + } + + // Upper parts of the room + if(!theRoom.sky + && noHighDegenerate(theRoom, shiftX + i, ceilY[i][j] + 1, shiftZ + j)) + DBlock.place(world, shiftX + i, ceilY[i][j] + 1, shiftZ + j, ceiling[i][j]); + + for(int k = roomBottom(i, j); k <= ceilY[i][j]; k++) + if(!isWall[i][j])DBlock.deleteBlock(world, shiftX +i, k, shiftZ + j, flooded); + else if(noHighDegenerate(theRoom, shiftX + i, k, shiftZ + j)) + DBlock.place(world, shiftX + i, k, shiftZ + j, wall[i][j]); + for(int k = nCeilY[i][j]; k < ceilY[i][j]; k++) + if(noHighDegenerate(theRoom, shiftX + i, k, shiftZ + j)) + DBlock.place(world, shiftX + i, k, shiftZ + j, wall[i][j]); + if(isFence[i][j]) + DBlock.place(world, shiftX + i, floorY[i][j], shiftZ + j, dungeon.fenceBlock); + + if(isDoor[i][j]) { + DBlock.deleteBlock(world, shiftX + i, floorY[i][j], shiftZ + j, flooded); + DBlock.deleteBlock(world, shiftX + i, floorY[i][j] + 1, shiftZ + j, flooded); + DBlock.deleteBlock(world, shiftX + i, floorY[i][j] + 2, shiftZ + j, flooded); + } + + // Liquids + if(hasLiquid[i][j] && (!isWall[i][j] && !isDoor[i][j]) + && world.getBlockAt(shiftX + i, floorY[i][j] - 1, shiftZ + j).getType() != Material.AIR) + DBlock.place(world, shiftX + i, floorY[i][j], shiftZ + j, theRoom.liquidBlock); + } + } + +// MinecraftForge.TERRAIN_GEN_BUS.post(new DLDEvent.AfterBuild(this, shiftX, shiftZ, flooded)); +// DoomlikeDungeons.profiler.endTask("Building Dungeon architecture"); + dungeon.addTileEntities(); + dungeon.addEntrances(); +// DoomlikeDungeons.profiler.endTask("Building Dungeon in World"); + } + + + /** + * Returns true if a block should be placed in those coordinates; that is + * the block is not air or the room is not degenerate. + * + * This is for use with wall and ceiling blocks; for floor blocks use + * noLowDegenerate. + * + * @param theRoom + * @param x world x coordinate + * @param y world y coordinate + * @param z world z coordinate + * @return if the block should be placed here. + */ + private boolean noHighDegenerate(Room theRoom, int x, int y, int z) { + return !(theRoom.degenerate && world.getBlockAt(x, y, z).getType() == Material.AIR); + } + + + /** + * Returns true if a floor block should be placed here. This will be true + * if the block is not air, if the room does not have degenerate floors, or + * is part of a main path through the room. + * + * @param theRoom + * @param x world x coordinate + * @param y world y coordinate + * @param z world z coordinate + * @param i dungeon x coordinate + * @param j dungeon z coordinate + * @return + * @return if the block should be placed here. + */ + private boolean noLowDegenerate(Room theRoom, int x, int y, int z, int i, int j) { + return !(theRoom.degenerateFloors + && world.getBlockAt(x, y, z).getType() == Material.AIR + && !astared[i][j]); + } + + + /** + * The lowest height to place air or wall; walls may + * go one block lower. + * + * @param i dungeon x coordinate + * @param j dungeon z coordinate + * @return lowest height to place a wall or air/water block. + */ + private int roomBottom(int i, int j) { + int b = floorY[i][j]; + if(isWall[i][j] && !isDoor[i][j]) b--; + return b; + } + + + /** + * Sets whether the flying debug map should be drawn. + * + * @param value + */ + public static void setDrawFlyingMap(boolean value) { + drawFlyingMap = value; + } +} diff --git a/src/jaredbgreat/dldungeons/planner/mapping/Tile.java b/src/jaredbgreat/dldungeons/planner/mapping/Tile.java new file mode 100644 index 0000000..dbc3696 --- /dev/null +++ b/src/jaredbgreat/dldungeons/planner/mapping/Tile.java @@ -0,0 +1,45 @@ +package jaredbgreat.dldungeons.planner.mapping; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +/** + * This is a 1x1 column of block, or put differently, a block + * in 2D. This is used to repressent a location in the 2D map, + * especially for use with pathfinding / graph algorithms, for + * which tiles are the vertices and adjency between tiles is an + * edge. + * + * This being used mostly as a C-struct, so everything is left + * public. + * + * @author Jared Blackburn + * + */ +public class Tile { + public int x, z; + public Tile(int x, int z) { + this.x = x; + this.z = z; + } + + + public boolean equals(Tile other) { + return ((x == other.x) && (z == other.z)); + } + + + @Override + public boolean equals(Object other) { + if(other instanceof Tile) return equals((Tile) other); + return false; + } + + + @Override + public int hashCode() { + return x + (z << 8) + (z << 16) + (x << 24); + } +} diff --git a/src/jaredbgreat/dldungeons/rooms/AbstractRoom.java b/src/jaredbgreat/dldungeons/rooms/AbstractRoom.java new file mode 100644 index 0000000..964b7ed --- /dev/null +++ b/src/jaredbgreat/dldungeons/rooms/AbstractRoom.java @@ -0,0 +1,199 @@ +package jaredbgreat.dldungeons.rooms; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.planner.Dungeon; + +import java.util.Random; + +//import net.minecraft.block.Block; + + + +/** + * The base type for all rooms, this determines some general + * room characteristics and provides factory methods for creating + * rooms the types of which are randomly chosen based on dungeon + * wide theme-derived variables. + */ +public abstract class AbstractRoom /*extends Shape*/ { + + + public int wallBlock1; + public int floorBlock; + public int cielingBlock; + public int fenceBlock; + public int pillarBlock; + public int liquidBlock; + public int caveBlock; + + public boolean degenerate; // Leave air blocks in walls / ceiling/ + public boolean degenerateFloors; // Even leave air blocks in floor?!? + public boolean sky; // Does the room have a ceiling? / Is it outdoorsy? + public boolean fenced; + + + /** + * The constructor for the null room (room 0, representing areas + * that are not part of the dungeon). It should never be used to + * generate a "normal" room of any type. It is only protected + * (rather than private) because the null room needs to be instantiated + * to as a place holder in the room lists. + */ + protected AbstractRoom() { + wallBlock1 = 0; + floorBlock = 0; + cielingBlock = 0; + fenceBlock = 0; + pillarBlock = 0; + liquidBlock = 0; + } + + + /** + * The super constructor for creating real rooms. It is still protected + * as no public constructor should exist for rooms as the are provided + * by the makeRoom methods. + * + * @param dungeon + * @param previous + */ + protected AbstractRoom(Dungeon dungeon, AbstractRoom previous) { + if((previous != null) && !dungeon.variability.use(dungeon.random)) { + wallBlock1 = previous.wallBlock1; + floorBlock = previous.floorBlock; + cielingBlock = previous.cielingBlock; + fenceBlock = previous.fenceBlock; + pillarBlock = previous.pillarBlock; + liquidBlock = previous.liquidBlock; + caveBlock = previous.caveBlock; + } else if(dungeon.variability.use(dungeon.random)) { + if(dungeon.variability.use(dungeon.random)) { + wallBlock1 = dungeon.theme.walls[dungeon.random.nextInt(dungeon.theme.walls.length)]; + floorBlock = dungeon.theme.floors[dungeon.random.nextInt(dungeon.theme.floors.length)]; + cielingBlock = dungeon.theme.ceilings[dungeon.random.nextInt(dungeon.theme.ceilings.length)]; + fenceBlock = dungeon.theme.fencing[dungeon.random.nextInt(dungeon.theme.fencing.length)]; + pillarBlock = dungeon.theme.pillarBlock[dungeon.random.nextInt(dungeon.theme.pillarBlock.length)]; + liquidBlock = dungeon.theme.liquid[dungeon.random.nextInt(dungeon.theme.liquid.length)]; + caveBlock = dungeon.theme.caveWalls[dungeon.random.nextInt(dungeon.theme.caveWalls.length)]; + } else { + if(!dungeon.variability.use(dungeon.random)) + wallBlock1 = dungeon.wallBlock1; + else wallBlock1 = dungeon.theme.walls[dungeon.random.nextInt(dungeon.theme.walls.length)]; + if(!dungeon.variability.use(dungeon.random)) + floorBlock = dungeon.floorBlock; + else floorBlock = dungeon.theme.floors[dungeon.random.nextInt(dungeon.theme.floors.length)]; + if(!dungeon.variability.use(dungeon.random)) + cielingBlock = dungeon.cielingBlock; + else cielingBlock = dungeon.theme.ceilings[dungeon.random.nextInt(dungeon.theme.ceilings.length)]; + if(!dungeon.variability.use(dungeon.random)) + fenceBlock = dungeon.fenceBlock; + else fenceBlock = dungeon.theme.fencing[dungeon.random.nextInt(dungeon.theme.fencing.length)]; + if(!dungeon.variability.use(dungeon.random)) + pillarBlock = dungeon.cornerBlock; + else pillarBlock = dungeon.theme.pillarBlock[dungeon.random.nextInt(dungeon.theme.pillarBlock.length)]; + if(!dungeon.variability.use(dungeon.random)) + liquidBlock = dungeon.liquidBlock; + else liquidBlock = dungeon.theme.liquid[dungeon.random.nextInt(dungeon.theme.liquid.length)]; + if(!dungeon.variability.use(dungeon.random)) + caveBlock = dungeon.caveBlock; + else caveBlock = dungeon.theme.caveWalls[dungeon.random.nextInt(dungeon.theme.caveWalls.length)]; + } + } else { + wallBlock1 = dungeon.wallBlock1; + floorBlock = dungeon.floorBlock; + cielingBlock = dungeon.cielingBlock; + fenceBlock = dungeon.fenceBlock; + pillarBlock = dungeon.cornerBlock; + liquidBlock = dungeon.liquidBlock; + caveBlock = dungeon.caveBlock; + } + if(dungeon.outside.value > 0) + sky = dungeon.outside.use(dungeon.random); + if(dungeon.degeneracy.value > 0) { + degenerate = dungeon.degeneracy.use(dungeon.random); + degenerateFloors = + (degenerate && dungeon.degeneracy.use(dungeon.random) && dungeon.random.nextBoolean()); + } + if(sky) fenced = dungeon.fences.use(dungeon.random); + else fenced = false; + } + + + /** + * A factory method for creating rooms of a random type. The + * actual type will be based on dungeon-wide theme-derived + * variables. + * + * @param beginX + * @param endX + * @param beginZ + * @param endZ + * @param floorY + * @param ceilY + * @param dungeon + * @param parent + * @param previous + * @return + */ + public static Room makeRoom(int beginX, int endX, int beginZ, int endZ, int floorY, int ceilY, + Dungeon dungeon, Room parent, Room previous) { + RoomType type = RoomType.ROOM; + if(dungeon.naturals.use(dungeon.random)) { + type = RoomType.CAVE; + } + switch(type) { + case CAVE: { + Cave base = new Cave(beginX, endX, beginZ, endZ, floorY, ceilY, + dungeon, parent, previous); + return base.plan(dungeon, parent); + } + case ROOM: + default: { + Room base = new Room(beginX, endX, beginZ, endZ, floorY, ceilY, + dungeon, parent, previous); + return base.plan(dungeon, parent); + } + } + } + + + /** + * A factory method for creating rooms of a specified type. Specifying + * and unimplemented type will result in a default room of type ROOM / + * class Room -- that is, a basic room built from shape primitives. + * + * This is not currently used, but is kept for possible expansion. + * + * @param beginX + * @param endX + * @param beginZ + * @param endZ + * @param floorY + * @param ceilY + * @param dungeon + * @param parent + * @param previous + * @param type + * @return + */ + public static Room makeRoom(int beginX, int endX, int beginZ, int endZ, int floorY, int ceilY, + Dungeon dungeon, Room parent, Room previous, RoomType type) { + switch(type) { + case CAVE: { + Cave base = new Cave(beginX, endX, beginZ, endZ, floorY, ceilY, + dungeon, parent, previous); + return base.plan(dungeon, parent); + } + case ROOM: + default: { + Room base = new Room(beginX, endX, beginZ, endZ, floorY, ceilY, + dungeon, parent, previous); + return base.plan(dungeon, parent); + } + } + } +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/rooms/Cave.java b/src/jaredbgreat/dldungeons/rooms/Cave.java new file mode 100644 index 0000000..0909966 --- /dev/null +++ b/src/jaredbgreat/dldungeons/rooms/Cave.java @@ -0,0 +1,203 @@ +package jaredbgreat.dldungeons.rooms; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.pieces.Doorway; +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.planner.astar.AStar; + + +/** + * This class represents alternative caves created by cellular automata + * with a "2 1/2 D" architecture. + * + * The algorithm uses is based on one originally created for Rogue-like games + * and a variation is also use by the Oblige level generator for creating + * "natural" areas in Doom levels. + * + * Googling "cellular automata caves" will produce many relevant results. + * + * @author Jared Blackburn (JaredBGreat) + */ +public class Cave extends Room { + private int xSize, zSize, layers; + private int[][][] cells; + private int[][] scratchpad; + + private int sum; + + + public Cave(int beginX, int endX, int beginZ, int endZ, int floorY, + int ceilY, Dungeon dungeon, Room parent, Room previous) { + super(beginX, endX, beginZ, endZ, floorY, ceilY, dungeon, previous, previous); + this.degenerate = true; + } + + + /** + * Plans the room. Chests and spawner are added in the same way + * as for basic rooms, but walls and variation in floor / ceiling + * height are determined by cellular automata to produce a more + * cave-like layout. + */ + @Override + public Room plan(Dungeon dungeon, Room parent) { + xSize = endX - beginX; + zSize = endZ - beginZ; + layers = dungeon.verticle.ordinal();{ + if(layers < 1) layers = 1; + } + + cells = new int[layers][xSize][zSize]; + + for(int i = 0; i < xSize; i++) { + for(int j = 0; j < zSize; j++) { + for(int k = 0; k < layers; k++) { + cells[k][i][j] = dungeon.random.nextInt(2); + } + } + } + cells[0] = layerConvert1(cells[0], 5 + dungeon.random.nextInt(2)); + for(int i = 0; i < xSize; i++) { + for(int j = 0; j < zSize; j++) { + if(cells[0][i][j] == 1) { + dungeon.map.isWall[i + beginX][j + beginZ] = true; + } + } + } + int tmpFY = floorY; + int tmpCY = ceilY; + for(int k = 1; k < layers; k++) { + cells[k] = layerConvert2(cells[k], k-1, 4 + dungeon.random.nextInt(3)); + tmpFY += (dungeon.random.nextInt(3) - 1); + tmpCY += (dungeon.random.nextInt(3) - 1); + if((tmpCY - tmpFY) < 3) { + tmpCY = tmpFY + 3; + } + for(int i = 0; i < xSize; i++) { + for(int j = 0; j < zSize; j++) { + if(cells[k][i][j] == 0) { + dungeon.map.floorY[i + beginX][j + beginZ] = (byte)tmpFY; + dungeon.map.nFloorY[i + beginX][j + beginZ] = (byte)tmpFY; + dungeon.map.ceilY[i + beginX][j + beginZ] = (byte)tmpCY; + dungeon.map.nCeilY[i + beginX][j + beginZ] = (byte)tmpCY; + } + } + } + } + if(hasEntrance) { + for(int i = (int)realX -2; i < ((int)realX + 2); i++) + for(int j = (int)realZ - 2; j < ((int)realZ + 2); j++) { + dungeon.map.floorY[i][j] = (byte)floorY; + dungeon.map.hasLiquid[i][j] = false; + dungeon.map.isWall[i][j] = false; + } + } + if(parent == null) { + addSpawners(dungeon); + } + if(dungeon.naturals.use(dungeon.random) || !dungeon.variability.use(dungeon.random)) { + for(int i = beginX; i < endX; i++) { + for(int j = beginZ; j < endZ; j++) { + dungeon.map.wall[i][j] = caveBlock; + dungeon.map.floor[i][j] = caveBlock; + dungeon.map.ceiling[i][j] = caveBlock; + } + } + } + return this; + } + + + /** + * Use cellular automata to find area that should be walls. + * + * @param layer + * @param thresshold + * @return + */ + private int[][] layerConvert1(int[][] layer, int thresshold) { + makeScratchpad(); + for(int i = xSize - 2; i > 0; i--) { + for(int j = zSize - 2; j > 0; j--) { + processCell(layer, i, j, thresshold); + } + } + return scratchpad; + } + + + /** + * Use cellular automata to determine areas of height variation (floor + * and ceiling) between the walls. + * + * @param layer + * @param down + * @param thresshold + * @return + */ + private int[][] layerConvert2(int[][] layer, int down, int thresshold) { + makeScratchpad(); + for(int i = xSize - 2; i > 0; i--) { + for(int j = zSize - 2; j > 0; j--) { + if(cells[down][i][j] == 1) { + layer[i][j] = 1; + } + } + } + for(int i = xSize - 2; i > 0; i--) { + for(int j = zSize - 2; j > 0; j--) { + processCell(layer, i, j, thresshold); + } + } + return scratchpad; + } + + + /** + * This process the cells for a tile, convert it to one or zero based on + * the sum of it and its neighbors. Note that most implementation do not + * consider the initial value of the cell itself, but I get good results + * doing so and it simplifies the code, so I do here. + * + * @param layer + * @param x + * @param z + * @param thresshold + */ + private void processCell(int[][] layer, int x, int z, int thresshold) { + sum = 0; + for(int i = x-1; i <= x+1; i++) { + for(int j = z-1; j <= z+1; j++ ) { + sum += layer[i][j]; + } + } + if(sum >= thresshold) { + scratchpad[x][z] = 1; + } else { + scratchpad[x][z] = 0; + } + } + + + /** + * Initialize the classes internal (read, private) scratchpad for a + * new round of cellular automata processing. + */ + private void makeScratchpad() { + scratchpad = new int[xSize][zSize]; + for(int i = 0; i < xSize; i++) { + scratchpad[i][0] = 1; + scratchpad[i][zSize - 1] = 1; + } + for(int i = 0; i < zSize; i++) { + scratchpad[0][1] = 1; + scratchpad[xSize - 1][i] = 1; + } + } + +} diff --git a/src/jaredbgreat/dldungeons/rooms/Room.java b/src/jaredbgreat/dldungeons/rooms/Room.java new file mode 100644 index 0000000..1967471 --- /dev/null +++ b/src/jaredbgreat/dldungeons/rooms/Room.java @@ -0,0 +1,757 @@ +package jaredbgreat.dldungeons.rooms; + +/* +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import jaredbgreat.dldungeons.ConfigHandler; +import jaredbgreat.dldungeons.Difficulty; +import jaredbgreat.dldungeons.pieces.Doorway; +import jaredbgreat.dldungeons.pieces.Shape; +import jaredbgreat.dldungeons.pieces.Shapes; +import jaredbgreat.dldungeons.pieces.Spawner; +import jaredbgreat.dldungeons.pieces.chests.BasicChest; +import jaredbgreat.dldungeons.pieces.chests.LootCategory; +import jaredbgreat.dldungeons.pieces.chests.TreasureChest; +import jaredbgreat.dldungeons.pieces.chests.WeakChest; +import jaredbgreat.dldungeons.planner.Dungeon; +import jaredbgreat.dldungeons.planner.RoomSeed; +import jaredbgreat.dldungeons.planner.Route; +import jaredbgreat.dldungeons.planner.Symmetry; +import jaredbgreat.dldungeons.planner.astar.AStar; +import jaredbgreat.dldungeons.planner.astar.DoorQueue; +import jaredbgreat.dldungeons.planner.features.Cutout; +import jaredbgreat.dldungeons.planner.features.Depression; +import jaredbgreat.dldungeons.planner.features.FeatureAdder; +import jaredbgreat.dldungeons.planner.features.IslandPlatform; +import jaredbgreat.dldungeons.planner.features.IslandRoom; +import jaredbgreat.dldungeons.planner.features.Pillar; +import jaredbgreat.dldungeons.planner.features.Pool; +import jaredbgreat.dldungeons.themes.ThemeFlags; +import jaredbgreat.dldungeons.themes.ThemeType; +import java.util.ArrayList; +import java.util.Collections; + + +/** + * This is the basic room type, built from shape primitive and most + * common in most dungeon themes. Most of the methods are used for + * adding features to the room so that it builds itself, though most + * of these features are actually store in the dungeon map (a MapMatrix) + * rather than the Room instance. Exception are chests, spawners, + * and doors, which are kept in lists to be further processes and/or + * added in ways that accommodate their special features (TileEntities). + * + * Note that the poor encapsulation of this class is largely due to + * excessive concerns about efficiency and exaggerated assumptions + * about the overhead of method calls (getters). While this could, and + * perhaps should be changed in principle, the number of required + * code changes throughout the mod is now a major reason for leaving + * them as public. + * + * @author Jared Blackburn + * + */ +public class Room extends AbstractRoom { + private static int lootBonus = 0; + + public int id; // Should be equal to the index in Dungeon.rooms ArrayList. + public static final Room roomNull = new Room(); // Areas outside the dungeon (index 0) + public int beginX, midX, endX, beginZ, midZ, endZ, floorY, nFloorY, ceilY, nCeilY, y; + public float realX, realZ; + public boolean hasWholePattern; + public Symmetry sym; + public int orientation; + public boolean XFlip, ZFlip; + public Shapes shape = Shapes.X; + public ArrayList childSeeds; + public boolean isNode; + public boolean isSubroom; + public boolean hasEntrance; + public boolean hasSpawners; + public ArrayList spawners; + public ArrayList chests; + public ArrayList doors; + public ArrayList connections; + public ArrayList topDoors; + public Doorway midpoint; // not really a door but used as one at times + + + private Room() {id = 0;} + + + /** + * A safety method to ensure there are no circular references + * to create a memory leak. Note that none should exist, this + * is included as a safety measure do to the general complexity + * of the relationship between dungeons, rooms, and related rooms. + */ + public void preFinalize() { + childSeeds.clear(); + childSeeds = null; + spawners.clear(); + chests.clear(); + spawners = null; + chests = null; + doors = null; + } + + + public Room(int beginX, int endX, int beginZ, int endZ, int floorY, int ceilY, + Dungeon dungeon, Room parent, Room previous) { + super(dungeon, previous); + //DoomlikeDungeons.profiler.startTask("Creating a Room"); + dungeon.rooms.add(this); + id = dungeon.rooms.realSize(); + childSeeds = new ArrayList(); + spawners = new ArrayList(); + chests = new ArrayList(); + doors = new ArrayList(); + connections = new ArrayList(); + dungeon.planter.add(this); + isNode = (previous == null); + isSubroom = (parent != null); + hasEntrance = (isNode && !ConfigHandler.singleEntrance + && dungeon.entrances.use(dungeon.random)); + if(hasEntrance) dungeon.numEntrances++; + hasSpawners = false; + + sym = Symmetry.getSymmetry(dungeon); + orientation = dungeon.random.nextInt(4); + XFlip = dungeon.random.nextBoolean(); + ZFlip = dungeon.random.nextBoolean(); + + this.beginX = beginX; + this.endX = endX; + this.beginZ = beginZ; + this.endZ = endZ; + this.floorY = floorY; + this.ceilY = ceilY; + + midX = beginX + ((endX - beginX) / 2); + midZ = beginZ + ((endZ - beginZ) / 2); + + realX = (((float)(endX - beginX)) / 2.0f) + (float)beginX + 1.0f; + realZ = (((float)(endZ - beginZ)) / 2.0f) + (float)beginZ + 1.0f; + + dungeon.spawners.addRoom((endX - beginX) * (endZ - beginZ)); + + if(isNode) { + degenerateFloors = false; + doors.add(new Doorway(midX, midZ, dungeon.random.nextBoolean())); + } + + if(isSubroom && parent.sky) { + sky = (sky && !dungeon.outside.use(dungeon.random)); + } + for(int i = beginX + 1; i < endX; i++) + for(int j = beginZ + 1; j < endZ; j++) { + if(dungeon.map.room[i][j] == 0) dungeon.map.room[i][j] = id; + dungeon.map.ceilY[i][j] = dungeon.map.nCeilY[i][j] = (byte)ceilY; + dungeon.map.floorY[i][j] = dungeon.map.nFloorY[i][j] = (byte)floorY; + if(!sky) dungeon.map.ceiling[i][j] = cielingBlock; + dungeon.map.floor[i][j] = floorBlock; + dungeon.map.wall[i][j] = wallBlock1; + dungeon.map.hasLiquid[i][j] = false; + dungeon.map.isWall[i][j] = false; + } + for(int i = beginX; i <= endX; i++) { + assignEdge(dungeon, i, beginZ); + assignEdge(dungeon, i, endZ); + } + for(int i = beginZ; i <= endZ; i++) { + assignEdge(dungeon, beginX, i); + assignEdge(dungeon, endX, i); + } + doorways(dungeon); + midpoint = new Doorway(midX, midZ, dungeon.random.nextBoolean()); + } + + + /** + * Adds the features, including chests and spawners, to the room. + * + * @param dungeon + * @param parent + * @return + */ + public Room plan(Dungeon dungeon, Room parent) { + if(!dungeon.complexity.use(dungeon.random) && !isNode) { + hasWholePattern = true; + if(dungeon.liquids.use(dungeon.random)) { + walkway(dungeon); + } else if(!sky && (dungeon.complexity.use(dungeon.random) + || dungeon.symmetry.use(dungeon.random))) { + cutin(dungeon); + } + } else addFeatures(dungeon); + if(hasEntrance) { + for(int i = (int)realX -2; i < ((int)realX + 2); i++) + for(int j = (int)realZ - 2; j < ((int)realZ + 2); j++) { + dungeon.map.floorY[i][j] = (byte)floorY; + dungeon.map.hasLiquid[i][j] = false; + dungeon.map.isWall[i][j] = false; + } + } + if(parent == null) { + addSpawners(dungeon); + } + return this; + } + + + /** + * Assigns a wall section between this room and another to the room with + * the higher ceiling, so as too avoid overly short walls between rooms + * of differing heights. + * + * @param dungeon + * @param x + * @param z + */ + private void assignEdge(Dungeon dungeon, int x, int z) { + if((dungeon.map.room[x][z] == 0) + || (dungeon.rooms.get(dungeon.map.room[x][z]).sky && !sky) + || (isSubroom)) { + dungeon.map.room[x][z] = id; + if(!sky) dungeon.map.ceiling[x][z] = cielingBlock; + dungeon.map.floor[x][z] = floorBlock; + dungeon.map.wall[x][z] = wallBlock1; + dungeon.map.hasLiquid[x][z] = false; + dungeon.map.isWall[x][z] = !sky; + dungeon.map.isFence[x][z] = fenced; + } + if(dungeon.map.ceilY[x][z] < (byte)ceilY) dungeon.map.ceilY[x][z] = (byte)ceilY; + if(dungeon.map.nCeilY[x][z] < (byte)ceilY) dungeon.map.nCeilY[x][z] = (byte)ceilY; + if(dungeon.map.floorY[x][z] < (byte)floorY) dungeon.map.floorY[x][z] = (byte)floorY; + if((dungeon.map.nFloorY[x][z] > (byte)nFloorY) || (dungeon.map.nFloorY[x][z] == 0)) + dungeon.map.nFloorY[x][z] = (byte)floorY; + } + + + /** + * Adds features other than chests and spawns to the room to rooms that + * lack a whole room pattern. This is called by plan room. + * + * It will try to at a number of features based on dungeon complexity. + * On each attempt it will check each possible feature once; if a feature + * is selected to add it the attempt ends and the next begins. To avoid + * a universal bias based on checking order, all features types are added + * to a list and shuffled once, giving each room its own set of biases + * that can be thought of as the room character or a room equivalent to + * the dungeons wide theme-based probabilities. + * + * @param dungeon + */ + public void addFeatures(Dungeon dungeon) { + ArrayList features = new ArrayList(); + features.add(new IslandPlatform(dungeon.verticle)); + features.add(new Depression(dungeon.verticle)); + features.add(new Pool(dungeon.liquids)); + if(!sky) { + features.add(new Cutout(dungeon.complexity)); + features.add(new Pillar(dungeon.pillars)); + } + features.add(new IslandRoom(dungeon.islands)); + features.trimToSize(); + Collections.shuffle(features, dungeon.random); + if(dungeon.complexity.value <= 0) return; + int tries = ((endX - beginX + endZ - beginZ) / (4 + sym.level)); + for(int i = 0; i <= tries; i++) { + for(FeatureAdder feat: features) { + if(feat.addFeature(dungeon, this)) break; + } + } + } + + + /** + * Adds spawners, taking into consideration the mods difficulty setting + * and whether the room is an entrance, a destination, or an ordinary room. + * + * @param dungeon + */ + protected void addSpawners(Dungeon dungeon) { + if(ConfigHandler.difficulty == Difficulty.NONE || + (!isNode && !ConfigHandler.difficulty.addmob(dungeon.random)) + || (hasEntrance && !ConfigHandler.difficulty.entrancemobs)) return; + boolean multibonus = false; + int x, y, z, tmp, num; + String mob; + if(!hasEntrance && (ConfigHandler.difficulty.multimob(dungeon.random) || isNode)) { + tmp = (endX - beginX) > (endZ - beginZ) ? (endX - beginX) : (endZ - beginZ); + num = dungeon.random.nextInt(2 + (tmp / 8)) + 1; + for(int i = 0; i < num; i++) { + tmp = (endX - beginX - 3); + x = dungeon.random.nextInt(tmp) + beginX + 2; + tmp = (endZ - beginZ - 3); + z = dungeon.random.nextInt(tmp) + beginZ + 2; + if(dungeon.random.nextInt(4) == 0) y = dungeon.map.ceilY[x][z]; + else y = dungeon.map.floorY[x][z]; + int lev = levAdjust(ConfigHandler.difficulty.moblevel(dungeon.random), dungeon); + if(lev >= 0) { + mob = dungeon.theme.allMobs[lev].get(dungeon.random.nextInt(dungeon.theme.allMobs[lev].size())); + Spawner s = new Spawner(x, y, z, id, lev, mob); + spawners.add(s); + dungeon.spawners.addSpawner(s); + } + } + } else { + tmp = (endX - beginX) / 2; + x = dungeon.random.nextInt(tmp) + beginX + (tmp /2); + tmp = (endZ - beginZ) / 2; + z = dungeon.random.nextInt(tmp) + beginZ + (tmp /2); + if(dungeon.random.nextInt(4) == 0) y = dungeon.map.floorY[x][z]; + else y = dungeon.map.ceilY[x][z]; + int lev = levAdjust(ConfigHandler.difficulty.moblevel(dungeon.random), dungeon); + if(lev >= 0) { + mob = dungeon.theme.allMobs[lev].get(dungeon.random.nextInt(dungeon.theme.allMobs[lev].size())); + Spawner s = new Spawner(x, y, z, id, lev, mob); + spawners.add(s); + dungeon.spawners.addSpawner(s); + } + } + if(isNode && !hasEntrance) { + x = (int)realX; + z = (int)realZ; + if(dungeon.map.hasLiquid[x][z]) {y = dungeon.map.ceilY[x][z];} + else {y = dungeon.map.floorY[x][z] - 1;} + int lev = levAdjust(ConfigHandler.difficulty.nodelevel(dungeon.random), dungeon); + if(lev >= 0) { + mob = dungeon.theme.allMobs[lev].get(dungeon.random.nextInt(dungeon.theme.allMobs[lev].size())); + spawners.add(new Spawner(x, y, z, id, lev, mob)); + } + } + } + + + /** + * Checks to see if there are mobs available at the level determined, + * and if not adjusts down. + * + * @param lev + * @param dungeon + * @return + */ + private int levAdjust(int lev, Dungeon dungeon) { + while(dungeon.theme.allMobs[lev].isEmpty()) { + lev--; + if(lev < 0) return -1; + } + return lev; + } + + + /** + * Adds chests, taking into consideration the rooms difficulty and + * whether its a destination or ordinary room. No chests will be + * added to entrance rooms. + * + * @param dungeon + */ + public void addChests(Dungeon dungeon) { + if((ConfigHandler.difficulty == Difficulty.NONE) || + hasEntrance) return; + hasSpawners = spawners.size() > 0; + if((!hasSpawners && (dungeon.random.nextInt(5) > 0))) return; + int lev = 0; + int n = spawners.size(); + for(int i = 0; i < n; i++) { + lev = Math.max(lev, spawners.get(i).getLevel()); + } + boolean trueBoss = lev > 3; + if(n > 1) { + lev++; + } + if(isNode && !hasEntrance) { + lev++; + } + if(dungeon.theme.flags.contains(ThemeFlags.HARD)) { + lev++; + } else if(dungeon.theme.flags.contains(ThemeFlags.EASY)) { + lev--; + } + lev += lootBonus + dungeon.random.nextInt(1); + int x, y, z, tmp, num; + if(!hasSpawners) { + tmp = (endX - beginX - 3); + x = dungeon.random.nextInt(tmp) + beginX + 2; + tmp = (endZ - beginZ - 3); + z = dungeon.random.nextInt(tmp) + beginZ + 2; + y = dungeon.map.floorY[x][z]; + chests.add(new WeakChest(x, y, z, dungeon.lootCat)); + } else if(dungeon.random.nextBoolean() && !isNode) { + tmp = (endX - beginX - 3); + x = dungeon.random.nextInt(tmp) + beginX + 2; + tmp = (endZ - beginZ - 3); + z = dungeon.random.nextInt(tmp) + beginZ + 2; + y = dungeon.map.floorY[x][z]; + chests.add(new BasicChest(x, y, z, lev, dungeon.lootCat)); + } else { + int ms = Math.max(n, 2); + if(isNode)num = Math.min(ms, dungeon.random.nextInt(2 + (ms / 2)) + 2); + else num = dungeon.random.nextInt(1 + (ms / 2)) + 1; + for(int i = 0; i < num; i++) { + tmp = (endX - beginX - 3); + x = dungeon.random.nextInt(tmp) + beginX + 2; + tmp = (endZ - beginZ - 3); + z = dungeon.random.nextInt(tmp) + beginZ + 2; + y = dungeon.map.floorY[x][z]; + chests.add(new BasicChest(x, y, z, lev, dungeon.lootCat)); + } + } if(isNode && !hasEntrance) { + x = (int)realX; + z = (int)realZ; + y = dungeon.map.floorY[x][z]; + chests.add(new TreasureChest(x, y, z, lev, dungeon.lootCat).setWithBoss(trueBoss)); + } + } + + + /** + * Determine the number of doorways and add them. + * + * @param dungeon + */ + protected void doorways(Dungeon dungeon) { + int num = dungeon.random.nextInt(2 + ((endX - beginX + endZ - beginZ) / ((sym.level * 8) + 8)) + + (dungeon.subrooms.value / (2 + sym.level))) + 1; + for(int i = 0; i < num; i++) doorway(dungeon); + } + + + /** + * Adds a doorway. + * + * @param dungeon + * @param x + * @param z + * @param xOriented + */ + protected void addDoor(Dungeon dungeon, int x, int z, boolean xOriented) { + doors.add(new Doorway(x, z, xOriented)); + dungeon.map.isDoor[x][z] = true; + } + + + /** + * Creates a doorway, or more than one based on room symmetry. + * + * @param dungeon + */ + protected void doorway(Dungeon dungeon) { + int xExtend = 0; + int zExtend = 0; + int xSeedDir = 0; + int zSeedDir = 0; + int wall = dungeon.random.nextInt(4); + int x, z, oppX, oppZ; + switch (wall) { + case 0: + x = beginX; + oppX = endX; + z = dungeon.random.nextInt(endZ - beginZ - 3) + 2; + oppZ = endZ - z; + z += beginZ; + xSeedDir = -1; + zSeedDir = 0; + zExtend = dungeon.random.nextInt(3) - 1; + break; + case 1: + z = beginZ; + oppZ = endZ; + x = dungeon.random.nextInt(endX - beginX - 3) + 2; + oppX = endX - x; + x += beginX; + xSeedDir = 0; + zSeedDir = -1; + xExtend = dungeon.random.nextInt(3) - 1; + break; + case 2: + x = endX; + oppX = beginX; + z = dungeon.random.nextInt(endZ - beginZ - 3) + 2; + oppZ = endZ - z; + z += beginZ; + xSeedDir = 1; + zSeedDir = 0; + zExtend = dungeon.random.nextInt(3) - 1; + break; + case 3: + z = endZ; + oppZ = beginZ; + x = dungeon.random.nextInt(endX - beginX - 3) + 2; + oppX = endX - x; + x += beginX; + xSeedDir = 0; + zSeedDir = 1; + xExtend = dungeon.random.nextInt(3) - 1; + break; + default: // Removes the "...may not be initialized" warning. + x = beginX; + oppX = endX; + z = dungeon.random.nextInt(endZ - beginZ - 3) + 2; + oppZ = endZ - z; + z += beginZ; + xSeedDir = -1; + zSeedDir = 0; + zExtend = dungeon.random.nextInt(3) - 1; + break; + } + addDoor(dungeon, x, z, (xSeedDir != 0)); + addDoor(dungeon, x + xExtend, z + zExtend, (xSeedDir != 0)); + childSeeds.add(new RoomSeed(x + xSeedDir, floorY, z + zSeedDir)); + // Apply Symmetries + switch (sym) { + case NONE: break; + case TR1: { + oppX = (int)(realX + ((z - realZ) / (float)(endZ - beginZ)) * (endX - beginX)); + if(oppX < 1) oppX = 1; + if(oppX > (dungeon.size.width - 2)) oppX = (dungeon.size.width - 2); + oppZ = (int)(realZ + ((x - realX) / (float)(endX - beginX)) * (endZ - beginZ)); + if(oppZ < 1) oppZ = 1; + if(oppZ > (dungeon.size.width - 2)) oppZ = (dungeon.size.width - 2); + addDoor(dungeon, oppX, oppZ, (zSeedDir != 0)); + addDoor(dungeon, oppX + xExtend, oppZ + zExtend, (zSeedDir != 0)); + childSeeds.add(new RoomSeed(oppX + zSeedDir, floorY, oppZ + xSeedDir)); + } break; + case TR2: { + oppX = (int)(realX + ((z - realZ) / (float)(endZ - beginZ)) * (endX - beginX)); + if(oppX < 1) oppX = 1; + if(oppX > (dungeon.size.width - 2)) oppX = (dungeon.size.width - 2); + oppZ = (int)(realZ + ((x - realX) / (float)(endX - beginX)) * (endZ - beginZ)); + oppZ = endZ - (oppZ - beginZ); + if(oppZ < 1) oppZ = 1; + if(oppZ > (dungeon.size.width - 2)) oppZ = (dungeon.size.width - 2); + addDoor(dungeon, oppX, oppZ, (zSeedDir != 0)); + addDoor(dungeon, oppX + xExtend, oppZ + zExtend, (zSeedDir != 0)); + childSeeds.add(new RoomSeed(oppX + zSeedDir, floorY, oppZ - xSeedDir)); + } break; + case X: { + addDoor(dungeon, oppX, z, (xSeedDir != 0)); + addDoor(dungeon, oppX - xExtend, z + zExtend, (xSeedDir != 0)); + childSeeds.add(new RoomSeed(oppX - xSeedDir, floorY, z + zSeedDir)); + } break; + case Z: { + addDoor(dungeon, x, oppZ, (xSeedDir != 0)); + addDoor(dungeon, x + xExtend, oppZ - zExtend, (xSeedDir != 0)); + childSeeds.add(new RoomSeed(x + xSeedDir, floorY, oppZ - zSeedDir)); + } break; + case XZ: { + addDoor(dungeon, oppX,z, (xSeedDir != 0)); + addDoor(dungeon, oppX - xExtend, z + zExtend, (xSeedDir != 0)); + childSeeds.add(new RoomSeed(oppX - xSeedDir, floorY, z + zSeedDir)); + addDoor(dungeon, x, oppZ, (xSeedDir != 0)); + addDoor(dungeon, x + xExtend, oppZ - zExtend, (xSeedDir != 0)); + childSeeds.add(new RoomSeed(x + xSeedDir, floorY, oppZ - zSeedDir)); + addDoor(dungeon, oppX, oppZ, (xSeedDir != 0)); + addDoor(dungeon, oppX - xExtend, oppZ - zExtend, (xSeedDir != 0)); + childSeeds.add(new RoomSeed(oppX - xSeedDir, floorY, oppZ - zSeedDir)); + } break; + case R: { + addDoor(dungeon, oppX, oppZ, (xSeedDir != 0)); + addDoor(dungeon, oppX - xExtend, oppZ - zExtend, (xSeedDir != 0)); + childSeeds.add(new RoomSeed(oppX - xSeedDir, floorY, oppZ - zSeedDir)); + } break; + case SW: { + addDoor(dungeon, oppX, z, (xSeedDir != 0)); + addDoor(dungeon, oppX - xExtend, z + zExtend, (xSeedDir != 0)); + childSeeds.add(new RoomSeed(oppX - xSeedDir, floorY, z + zSeedDir)); + addDoor(dungeon, x, oppZ, (xSeedDir != 0)); + addDoor(dungeon, x + xExtend, oppZ - zExtend, (xSeedDir != 0)); + childSeeds.add(new RoomSeed(x + xSeedDir, floorY, oppZ - zSeedDir)); + addDoor(dungeon, oppX, oppZ, (xSeedDir != 0)); + addDoor(dungeon, oppX - xExtend, oppZ - zExtend, (xSeedDir != 0)); + childSeeds.add(new RoomSeed(oppX - xSeedDir, floorY, oppZ - zSeedDir)); + } + } + } + + + /** + * Adds a room new room branching from this one that is part of a sequence of + * rooms between two dungeon nods. + * + * @param dungeon + * @param dir + * @param xdim + * @param zdim + * @param height + * @param source + * @return + */ + public Room connector(Dungeon dungeon, int dir, int xdim, int zdim, int height, Route source) { + int xExtend = 0; + int zExtend = 0; + int xSeedDir = 0; + int zSeedDir = 0; + int x, z, oppX, oppZ; + switch (dir) { + case 2: + x = beginX; + oppX = endX; + z = (int)realZ; + oppZ = z; + xSeedDir = -1; + zSeedDir = 0; + zExtend = dungeon.random.nextInt(3) - 1; + break; + case 3: + z = beginZ; + oppZ = endZ; + x = (int)realX; + oppX = x; + xSeedDir = 0; + zSeedDir = -1; + xExtend = dungeon.random.nextInt(3) - 1; + break; + case 0: + x = endX; + oppX = beginX; + z = (int)realZ; + oppZ = z; + xSeedDir = 1; + zSeedDir = 0; + zExtend = dungeon.random.nextInt(3) - 1; + break; + case 1: + z = endZ; + oppZ = beginZ; + x = (int)realX; + oppX = x; + xSeedDir = 0; + zSeedDir = 1; + xExtend = dungeon.random.nextInt(3) - 1; + break; + default: // Removes the "...may not be initialized" warning. + x = beginX; + oppX = endX; + z = (int)realZ; + oppZ = z; + z += beginZ; + xSeedDir = -1; + zSeedDir = 0; + zExtend = dungeon.random.nextInt(3) - 1; + break; + } + addDoor(dungeon, x, z, (xSeedDir != 0)); + addDoor(dungeon, x + xExtend, z + zExtend, (xSeedDir != 0)); + if(((x + xSeedDir) >= dungeon.size.width) || + ((x + xSeedDir) < 0) || + ((z + zSeedDir) >= dungeon.size.width) || + ((z + zSeedDir) < 0)) return null; + if(dungeon.map.room[x + xSeedDir][z + zSeedDir] != 0) { + return dungeon.rooms.get(dungeon.map.room[x + xSeedDir][z + zSeedDir]); + } + else if((dir % 2) == 0) return new RoomSeed(x + xSeedDir, floorY, z + zSeedDir) + .growRoomZ(xdim, zdim, height, dungeon, null, this); + else return new RoomSeed(x + xSeedDir, floorY, z + zSeedDir) + .growRoomX(xdim, zdim, height, dungeon, null, this); + } + + + /** + * Fills a room with a "liquid" and then adds a walkway through it; + * this is used for rooms with a whole room pattern. + * + * @param dungeon + */ + private void walkway(Dungeon dungeon) { + int drop; + if(dungeon.theme.type.contains(ThemeType.SWAMP)) drop = 1; + else drop = 2; + shape = Shapes.wholeShape(sym, dungeon.random); + for(int i = beginX; i <= endX; i++) + for(int j = beginZ; j <= endZ; j++) { + dungeon.map.floorY[i][j] -= drop; + dungeon.map.hasLiquid[i][j] = true; + } + shape.family[orientation].drawWalkway(dungeon, this, realX, realZ, + (byte)(endX - beginX + 1), (byte)(endZ - beginZ + 1), XFlip, ZFlip); + } + + + /** + * Fills the room with walls, then opens up a passage; used for rooms + * with a whole room pattern. + * + * @param dungeon + */ + private void cutin(Dungeon dungeon) { + shape = Shapes.wholeShape(sym, dungeon.random); + for(int i = beginX; i <= endX; i++) + for(int j = beginZ; j <= endZ; j++) { + dungeon.map.isWall[i][j] = true; + } + shape.family[orientation].drawCutin(dungeon, this, realX, realZ, + (byte)(endX - beginX - 1), (byte)(endZ - beginZ - 1), XFlip, ZFlip); + } + + + /** + * Generate a side room; this is called by Dungeon.growCycle to expand + * the dungeon. + * + * @param dungeon + * @return + */ + public boolean plantChildren(Dungeon dungeon) { + boolean result = false; + for(RoomSeed planted : childSeeds) { + if(dungeon.rooms.realSize() >= dungeon.size.maxRooms) return false; + int height = dungeon.baseHeight; + int x = dungeon.random.nextInt(dungeon.size.width); + int z = dungeon.random.nextInt(dungeon.size.width); + if(height > dungeon.theme.maxY) height = dungeon.baseHeight; + if(height < dungeon.theme.minY) height = dungeon.baseHeight; + int xdim = dungeon.random.nextInt(dungeon.size.maxRoomSize - 5) + 6; + int zdim = dungeon.random.nextInt(dungeon.size.maxRoomSize - 5) + 6; + int ymod = (xdim <= zdim) ? (int) Math.sqrt(xdim) : (int) Math.sqrt(zdim); + int roomHeight = dungeon.random.nextInt((dungeon.verticle.value / 2) + ymod + 1) + 2; + if(planted.growRoom(xdim, zdim, roomHeight, dungeon, null, this) != null) + result = true; + } + return result; + } + + + /** + * Determines the other rooms to which a door leads; this is + * used in processing door corrections and room passibility. + * + * @param door + */ + public void addToConnections(Doorway door) { + if(id < 1) { + return; + } + if(connections.isEmpty()) { + DoorQueue pq = new DoorQueue(door.otherside); + pq.add(door); + connections.add(pq); + } else { + boolean added = false; + for(DoorQueue pq : connections) { + if(pq.isRoom(door.otherside)) { + pq.add(door); + added = true; + break; + } + } + if(!added) { + DoorQueue pq = new DoorQueue(door.otherside); + pq.add(door); + connections.add(pq); + } + } + } + + + public static void setLootBonus(int bonus) { + lootBonus = bonus; + } + + +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/rooms/RoomList.java b/src/jaredbgreat/dldungeons/rooms/RoomList.java new file mode 100644 index 0000000..fdc0cfe --- /dev/null +++ b/src/jaredbgreat/dldungeons/rooms/RoomList.java @@ -0,0 +1,88 @@ +package jaredbgreat.dldungeons.rooms; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.logging.Logger; + +/** + * A list of rooms. This is implemented as a ArrayList, but starting + * with one for the first room, as zero is used to represented rooms + * outside the dungeon (the "null room"). + * + * @author Jared Blackburn + * + */ +public class RoomList extends ArrayList { + + private int numRooms, index; + private Room[] rooms; + + + public RoomList(int slots) { + super(slots); + add(0, Room.roomNull); + numRooms = 0; + } + + + /** + * The number real rooms actually in the list; the null + * room is not counted. + * + * @return the number of rooms in the list + */ + public int realSize() { + return numRooms; + } + + + /** + * Returns true if only the null room is present. + * + * @return true if no "real" rooms are in the list + */ + public boolean isReallyEmpty() { + return (numRooms == 0); + } + + @Override + public ListIterator listIterator() { + return super.listIterator(1); + } + + + @Override + public Iterator iterator() { + return super.listIterator(1); + } + + + @Override + public boolean add(Room room) { + boolean out = super.add(room); + if(out) { + numRooms++; + } + return out; + } + + + + @Override + public Room remove(int index) { + System.err.println("[DLDUNGEONS] WARNING! Trying to remove room from list " + + "(Rooms cannot be removed)!"); + return null; // Rooms cannot be removed + } + +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/rooms/RoomType.java b/src/jaredbgreat/dldungeons/rooms/RoomType.java new file mode 100644 index 0000000..c2b920f --- /dev/null +++ b/src/jaredbgreat/dldungeons/rooms/RoomType.java @@ -0,0 +1,20 @@ +package jaredbgreat.dldungeons.rooms; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +/** + * Room types that can appear in the Dungeon, not all of + * which are implemented (yet?). Each type of room is + * planned differently. + * + * @author Jared Blackburn + * + */ +public enum RoomType { + ROOM, + CAVE, + MAZE; +} diff --git a/src/jaredbgreat/dldungeons/setup/Externalizer.java b/src/jaredbgreat/dldungeons/setup/Externalizer.java new file mode 100644 index 0000000..8ebeeb2 --- /dev/null +++ b/src/jaredbgreat/dldungeons/setup/Externalizer.java @@ -0,0 +1,210 @@ +package jaredbgreat.dldungeons.setup; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; + + +/** + * The purpose of this class is to read internal resource, located inside the jar + * by URI and write them to external files. More to the point, this if for + * auto-installing themes, and thus focuses on text processing methods. + * + * (Note that themes will still be installed as external files so as to allow + * players to easily edit them without needing to edit the jar.) + * + * @author JaredBGreat (Jared Blackburn) + */ +public class Externalizer { + private BufferedReader instream; + private BufferedWriter outstream; + private File outFile; + private static final String baseLocation = "/jaredbgreat/dldungeons/res/themes/"; + private static String outDirectory; + + private static final String[] themes + = new String[]{"common.cfg", + "continentalShelf.cfg", + "dank.cfg", + "desert.cfg", + "frozen.cfg", + "jungle.cfg", + "mesa.cfg", + "nether.cfg", + "oceanic.cfg", + "template.cfg", + "urban.cfg", + "villagelike.cfg", + "volcanic.cfg"}; + + public Externalizer(String outDir) { + outDirectory = outDir; + } + + + /** + * Exports a theme file by reading it from the jar and + * writing it to the hard drive, but only if a file with + * that path does not already exist on the drive. + * + * @param name + */ + public void copyOut(String name) { + copyOut(name, name); + } + + + /** + * Exports a theme file by reading it from the jar and + * writing it to the hard drive, but only if a file with + * that path does not already exist on the drive. + * + * @param name + */ + public void copyOut(String name, String outloc) { + try { + outFile = new File(outDirectory + outloc); + if(outFile.exists()) return; + instream = new BufferedReader(new InputStreamReader(getClass() + .getResourceAsStream(baseLocation + name))); + outstream = new BufferedWriter(new FileWriter(outFile)); + String line; + if((instream != null) && (outstream != null)) + while((line = instream.readLine()) != null) { + outstream.write(line + System.lineSeparator()); + } else { + System.err.println("[DLDUNGEONS] Error! Failed to write theme file " + outFile); + } + if(instream != null) instream.close(); + if(outstream != null) outstream.close(); + } catch (IOException e) { + System.err.println("[DLDUNGEONS] Error! Failed to write theme file " + outFile); + //e.printStackTrace(); + } + } + + + /** + * Exports a theme file by reading it from the jar and + * writing it to the hard drive, over-writing any file + * with the same path. + * + * @param name + */ + public boolean forceOut(String name) { + return forceOut(name, name); + } + + + /** + * Exports a theme file by reading it from the jar and + * writing it to the hard drive, over-writing any file + * with the same path. + * + * @param name + */ + public boolean forceOut(String name, String outloc) { + boolean result = true; + try { + outFile = new File(outDirectory + outloc); + if(outFile.exists()) { + if(outFile.canWrite() && !outFile.isDirectory()) { + outFile.delete(); + } else { + System.err.println("[DLDUNGEONS] Warning, could not delete " + outFile); + result = false; + } + } + instream = new BufferedReader(new InputStreamReader(getClass() + .getResourceAsStream(baseLocation + name))); + outstream = new BufferedWriter(new FileWriter(outFile)); + String line; + if((instream != null) && (outstream != null)) + while((line = instream.readLine()) != null) { + outstream.write(line + System.lineSeparator()); + } else { + System.err.println("[DLDUNGEONS] Error! Failed to write theme file " + outFile); + result = false; + } + if(instream != null) instream.close(); + if(outstream != null) outstream.close(); + } catch (IOException e) { + System.err.println("[DLDUNGEONS] Error! Failed to write theme file " + outFile); + result = false; + e.printStackTrace(); + } + return result; + } + + + /** + * Iterate through the default themes and export them to their own files. + */ + public void makeThemes() { + for(String name : themes) { + System.out.println("[DLDUNGEONS] Installing file " + outDirectory + name); + copyOut(name); + } + } + + + /** + * Iterate through the default themes and export them to their own files, + * over-writing any files with the same path. + */ + public void forceThemes() { + for(String name : themes) { + System.out.println("[DLDUNGEONS] Installing file " + outDirectory + name); + forceOut(name); + } + } + + + /** + * Export the chest.cfg file if it doesn't currently exist. + */ + public void makeChestCfg() { + System.out.println("[DLDUNGEONS] Installing files " + outDirectory + "chests.cfg"); + copyOut("nbt.cfg"); + copyOut("chests.cfg"); + copyOut("oceanic_chests.cfg", "SpecialChests" + File.separator + "oceanic_chests.cfg"); + } + + + /** + * Export the chest.cfg file, over-writing it if it already exists. + */ + public void forceChestCfg() { + System.out.println("[DLDUNGEONS] Installing files " + outDirectory + "chests.cfg"); + forceOut("chests.cfg"); + forceOut("SpecialChests" + File.separator + "oceanic_chests.cfg"); + } + + + /** + * Export the nbt.cfg file if it doesn't currently exist. + */ + public void makeNBTCfg() { + System.out.println("[DLDUNGEONS] Installing files " + outDirectory + "nbt.cfg and " ); + copyOut("nbt.cfg"); + } + + + /** + * Export the nbt.cfg file, over-writing it if it already exists. + */ + public void forceNBTCfg() { + System.out.println("[DLDUNGEONS] Installing files " + outDirectory + "nbt.cfg and " ); + forceOut("nbt.cfg"); + } + + +} diff --git a/src/jaredbgreat/dldungeons/themes/Autoselectable.java b/src/jaredbgreat/dldungeons/themes/Autoselectable.java new file mode 100644 index 0000000..ab603f8 --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/Autoselectable.java @@ -0,0 +1,17 @@ +package jaredbgreat.dldungeons.themes; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +/** + * Tags an enum as one that should be automatically selected by + * and Autoselecting enum. + * + * @author Jared Blackburn + * + */ +public interface Autoselectable {} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/themes/Autoselecting.java b/src/jaredbgreat/dldungeons/themes/Autoselecting.java new file mode 100644 index 0000000..0429b65 --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/Autoselecting.java @@ -0,0 +1,30 @@ +package jaredbgreat.dldungeons.themes; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import java.util.Random; + + +/** + * Classes with this interface can automatically select an + * Autoselectable enum. + * + * @author jared + * + */ +public interface Autoselecting { + + /** + * Returns an enum constant from an enum that implements + * Autoselectable. + * + * @param random + * @return + */ + public Autoselectable select(Random random); + +} diff --git a/src/jaredbgreat/dldungeons/themes/BiomeSets.java b/src/jaredbgreat/dldungeons/themes/BiomeSets.java new file mode 100644 index 0000000..cbbe3b3 --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/BiomeSets.java @@ -0,0 +1,558 @@ +package jaredbgreat.dldungeons.themes; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Random; +import me.zhehe.BiomeDictionary; +import me.zhehe.BiomeDictionary.Type; +import org.bukkit.block.Biome; + +//import net.minecraft.world.biome.Biome; +//import net.minecraftforge.common.BiomeDictionary; +//import net.minecraftforge.common.BiomeDictionary.Type; + +/** + * This handles the determination of which themes to use in + * each biome. + * + * Included a HashSets for various Forge biome dictionary types, + * storing which dungeons should appear in each. Additional sets + * are used to store with themes should never appear in each. + * + * In a given biome the possible dungeon themes equate to the union + * of inclusion defining sets for types that describe it followed + * by the subtraction of the union of the sets of forbidden themes + * for those types. + * + * @author Jared Blackburn + * + */ +public class BiomeSets { + + /* + * FIXME?: Lots of set variables: + * + * This should probably been handled with a collection, + * most likely a HashMap between the sets and the enum + * constants used (or else their string representation. + */ + + // For old types + static HashSet forest = new HashSet(); + static HashSet plains = new HashSet(); + static HashSet mountain = new HashSet(); + static HashSet hills = new HashSet(); + static HashSet swamp = new HashSet(); + static HashSet water = new HashSet(); + static HashSet desert = new HashSet(); + static HashSet frozen = new HashSet(); + static HashSet jungle = new HashSet(); + static HashSet wasteland = new HashSet(); + static HashSet nether = new HashSet(); + static HashSet end = new HashSet(); + static HashSet mushroom = new HashSet(); + static HashSet magical = new HashSet(); + //for new types + static HashSet hot = new HashSet(); + static HashSet cold = new HashSet(); + static HashSet sparse = new HashSet(); + static HashSet dense = new HashSet(); + static HashSet wet = new HashSet(); + static HashSet dry = new HashSet(); + static HashSet savanna = new HashSet(); + static HashSet coniferous = new HashSet(); + static HashSet spooky = new HashSet(); + static HashSet dead = new HashSet(); + static HashSet lush = new HashSet(); + static HashSet mesa = new HashSet(); + static HashSet ocean = new HashSet(); + static HashSet sandy = new HashSet(); + static HashSet snowy = frozen; + static HashSet minigame = new HashSet(); + + // NEGATIONS + // For old types + static HashSet nforest = new HashSet(); + static HashSet nplains = new HashSet(); + static HashSet nmountain = new HashSet(); + static HashSet nhills = new HashSet(); + static HashSet nswamp = new HashSet(); + static HashSet nwater = new HashSet(); + static HashSet ndesert = new HashSet(); + static HashSet nfrozen = new HashSet(); + static HashSet njungle = new HashSet(); + static HashSet nwasteland = new HashSet(); + static HashSet nnether = new HashSet(); + static HashSet nend = new HashSet(); + static HashSet nmushroom = new HashSet(); + static HashSet nmagical = new HashSet(); + //for new types + static HashSet nhot = new HashSet(); + static HashSet ncold = new HashSet(); + static HashSet nsparse = new HashSet(); + static HashSet ndense = new HashSet(); + static HashSet nwet = new HashSet(); + static HashSet ndry = new HashSet(); + static HashSet nsavanna = new HashSet(); + static HashSet nconiferous = new HashSet(); + static HashSet nspooky = new HashSet(); + static HashSet ndead = new HashSet(); + static HashSet nlush = new HashSet(); + static HashSet nmesa = new HashSet(); + static HashSet nocean = new HashSet(); + static HashSet nsandy = new HashSet(); + static HashSet nsnowy = nfrozen; + + + /** + * This will look at a themes biome type data and add it + * to the proper sets for both inclusion in those type. + * + * @param theme + */ + public static void registerTheme(Theme theme) { + if(theme.biomes.contains(Type.END)) { + end.add(theme); + } + if(theme.biomes.contains(Type.FOREST)) { + forest.add(theme); + } + if(theme.biomes.contains(Type.SNOWY)) { + frozen.add(theme); + } + if(theme.biomes.contains(Type.HILLS)) { + hills.add(theme); + } + if(theme.biomes.contains(Type.JUNGLE)) { + jungle.add(theme); + } + if(theme.biomes.contains(Type.MAGICAL)) { + magical.add(theme); + } + if(theme.biomes.contains(Type.MOUNTAIN)) { + mountain.add(theme); + } + if(theme.biomes.contains(Type.MUSHROOM)) { + mushroom.add(theme); + } + if(theme.biomes.contains(Type.NETHER)) { + nether.add(theme); + } + if(theme.biomes.contains(Type.PLAINS)) { + plains.add(theme); + } + if(theme.biomes.contains(Type.SWAMP)) { + swamp.add(theme); + } + if(theme.biomes.contains(Type.WASTELAND)) { + wasteland.add(theme); + } + if(theme.biomes.contains(Type.WATER) || theme.biomes.contains(Type.BEACH)) { + water.add(theme); + } + if(theme.biomes.contains(Type.OCEAN)) { + ocean.add(theme); + } + if(theme.biomes.contains(Type.HOT)) { + hot.add(theme); + } + if(theme.biomes.contains(Type.COLD)) { + cold.add(theme); + } + if(theme.biomes.contains(Type.SPARSE)) { + sparse.add(theme); + } + if(theme.biomes.contains(Type.DENSE)) { + dense.add(theme); + } + if(theme.biomes.contains(Type.WET)) { + wet.add(theme); + } + if(theme.biomes.contains(Type.DRY)) { + dry.add(theme); + } + if(theme.biomes.contains(Type.SAVANNA)) { + savanna.add(theme); + } + if(theme.biomes.contains(Type.CONIFEROUS)) { + coniferous.add(theme); + } + if(theme.biomes.contains(Type.SPOOKY)) { + spooky.add(theme); + } + if(theme.biomes.contains(Type.DEAD)) { + dead.add(theme); + } + if(theme.biomes.contains(Type.LUSH)) { + lush.add(theme); + } + if(theme.biomes.contains(Type.CONIFEROUS)) { + coniferous.add(theme); + } + if(theme.biomes.contains(Type.MESA)) { + mesa.add(theme); + } + if(theme.biomes.contains(Type.SANDY)) { + sandy.add(theme); + } + } + + + /** + * This will use a themes biome data to added it + * to set for exclusion from appearing in biomes + * of a type. + * + * @param theme + */ + public static void removeTheme(Theme theme) { + if(theme.notIn.contains(Type.END)) { + nend.add(theme); + } + if(theme.notIn.contains(Type.FOREST)) { + nforest.add(theme); + } + if(theme.notIn.contains(Type.SNOWY)) { + nfrozen.add(theme); + } + if(theme.notIn.contains(Type.HILLS)) { + nhills.add(theme); + } + if(theme.notIn.contains(Type.JUNGLE)) { + njungle.add(theme); + } + if(theme.notIn.contains(Type.MAGICAL)) { + nmagical.add(theme); + } + if(theme.notIn.contains(Type.MOUNTAIN)) { + nmountain.add(theme); + } + if(theme.notIn.contains(Type.MUSHROOM)) { + nmushroom.add(theme); + } + if(theme.notIn.contains(Type.NETHER)) { + nnether.add(theme); + } + if(theme.notIn.contains(Type.PLAINS)) { + nplains.add(theme); + } + if(theme.notIn.contains(Type.SWAMP)) { + nswamp.add(theme); + } + if(theme.notIn.contains(Type.WASTELAND)) { + nwasteland.add(theme); + } + if(theme.notIn.contains(Type.WATER) || theme.notIn.contains(Type.BEACH)) { + nwater.add(theme); + } + if(theme.notIn.contains(Type.OCEAN)) { + nocean.add(theme); + } + if(theme.notIn.contains(Type.HOT)) { + nhot.add(theme); + } + if(theme.notIn.contains(Type.COLD)) { + ncold.add(theme); + } + if(theme.notIn.contains(Type.SPARSE)) { + nsparse.add(theme); + } + if(theme.notIn.contains(Type.DENSE)) { + ndense.add(theme); + } + if(theme.notIn.contains(Type.WET)) { + nwet.add(theme); + } + if(theme.notIn.contains(Type.DRY)) { + ndry.add(theme); + } + if(theme.notIn.contains(Type.SAVANNA)) { + nsavanna.add(theme); + } + if(theme.notIn.contains(Type.CONIFEROUS)) { + nconiferous.add(theme); + } + if(theme.notIn.contains(Type.SPOOKY)) { + nspooky.add(theme); + } + if(theme.notIn.contains(Type.DEAD)) { + ndead.add(theme); + } + if(theme.notIn.contains(Type.LUSH)) { + nlush.add(theme); + } + if(theme.notIn.contains(Type.CONIFEROUS)) { + nconiferous.add(theme); + } + if(theme.notIn.contains(Type.MESA)) { + nmesa.add(theme); + } + if(theme.notIn.contains(Type.SANDY)) { + nsandy.add(theme); + } + } + + + /** + * This will perform the set logic to determine which + * themes are available in the given biome then randomly + * select one from that set. + * + * @param biome + * @param random + * @return + */ + public static Theme getTheme(Biome biome, Random random) { + HashSet set = new HashSet(); + ArrayList use = new ArrayList(); + set.clear(); + use.clear(); + if(BiomeDictionary.hasType(biome, Type.END)) { + set.addAll(end); + } + if(BiomeDictionary.hasType(biome, Type.FOREST)) { + set.addAll(forest); + } + if(BiomeDictionary.hasType(biome, Type.SNOWY)) { + set.addAll(frozen); + } + if(BiomeDictionary.hasType(biome, Type.HILLS)) { + set.addAll(hills); + } + if(BiomeDictionary.hasType(biome, Type.JUNGLE)) { + set.addAll(jungle); + } + if(BiomeDictionary.hasType(biome, Type.MAGICAL)) { + set.addAll(magical); + } + if(BiomeDictionary.hasType(biome, Type.MOUNTAIN)) { + set.addAll(mountain); + } + if(BiomeDictionary.hasType(biome, Type.MUSHROOM)) { + set.addAll(mushroom); + } + if(BiomeDictionary.hasType(biome, Type.NETHER)) { + set.addAll(nether); + } + if(BiomeDictionary.hasType(biome, Type.PLAINS)) { + set.addAll(plains); + } + if(BiomeDictionary.hasType(biome, Type.SWAMP)) { + set.addAll(swamp); + } + if(BiomeDictionary.hasType(biome, Type.WASTELAND)) { + set.addAll(wasteland); + } + if(BiomeDictionary.hasType(biome, Type.WATER) || + BiomeDictionary.hasType(biome, Type.BEACH)) { + set.addAll(water); + } + if(BiomeDictionary.hasType(biome, Type.HOT)) { + set.addAll(hot); + } + if(BiomeDictionary.hasType(biome, Type.COLD)) { + set.addAll(cold); + } + if(BiomeDictionary.hasType(biome, Type.DENSE)) { + set.addAll(dense); + } + if(BiomeDictionary.hasType(biome, Type.SPARSE)) { + set.addAll(sparse); + } + if(BiomeDictionary.hasType(biome, Type.DRY)) { + set.addAll(dry); + } + if(BiomeDictionary.hasType(biome, Type.WET)) { + set.addAll(wet); + } + if(BiomeDictionary.hasType(biome, Type.SAVANNA)) { + set.addAll(savanna); + } + if(BiomeDictionary.hasType(biome, Type.CONIFEROUS)) { + set.addAll(coniferous); + } + if(BiomeDictionary.hasType(biome, Type.SPOOKY)) { + set.addAll(spooky); + } + if(BiomeDictionary.hasType(biome, Type.DEAD)) { + set.addAll(dead); + } + if(BiomeDictionary.hasType(biome, Type.LUSH)) { + set.addAll(lush); + } + if(BiomeDictionary.hasType(biome, Type.MESA)) { + set.addAll(mesa); + } + if(BiomeDictionary.hasType(biome, Type.SANDY)) { + set.addAll(sandy); + } + + + // REMOVAL CODE BELOW + if(BiomeDictionary.hasType(biome, Type.END)) { + set.removeAll(nend); + } + if(BiomeDictionary.hasType(biome, Type.FOREST)) { + set.removeAll(nforest); + } + if(BiomeDictionary.hasType(biome, Type.HILLS)) { + set.removeAll(nhills); + } + if(BiomeDictionary.hasType(biome, Type.JUNGLE)) { + set.removeAll(njungle); + } + if(BiomeDictionary.hasType(biome, Type.MAGICAL)) { + set.removeAll(nmagical); + } + if(BiomeDictionary.hasType(biome, Type.MOUNTAIN)) { + set.removeAll(nmountain); + } + if(BiomeDictionary.hasType(biome, Type.MUSHROOM)) { + set.removeAll(nmushroom); + } + if(BiomeDictionary.hasType(biome, Type.NETHER)) { + set.removeAll(nnether); + } + if(BiomeDictionary.hasType(biome, Type.PLAINS)) { + set.removeAll(nplains); + } + if(BiomeDictionary.hasType(biome, Type.SWAMP)) { + set.removeAll(nswamp); + } + if(BiomeDictionary.hasType(biome, Type.WASTELAND)) { + set.removeAll(nwasteland); + } + if(BiomeDictionary.hasType(biome, Type.WATER) || + BiomeDictionary.hasType(biome, Type.BEACH)) { + set.removeAll(nwater); + } + if(BiomeDictionary.hasType(biome, Type.OCEAN)) { + set.removeAll(nocean); + } + if(BiomeDictionary.hasType(biome, Type.HOT)) { + set.removeAll(nhot); + } + if(BiomeDictionary.hasType(biome, Type.COLD)) { + set.removeAll(ncold); + } + if(BiomeDictionary.hasType(biome, Type.DENSE)) { + set.removeAll(ndense); + } + if(BiomeDictionary.hasType(biome, Type.SPARSE)) { + set.removeAll(nsparse); + } + if(BiomeDictionary.hasType(biome, Type.DRY)) { + set.removeAll(ndry); + } + if(BiomeDictionary.hasType(biome, Type.WET)) { + set.removeAll(nwet); + } + if(BiomeDictionary.hasType(biome, Type.SAVANNA)) { + set.removeAll(nsavanna); + } + if(BiomeDictionary.hasType(biome, Type.CONIFEROUS)) { + set.removeAll(nconiferous); + } + if(BiomeDictionary.hasType(biome, Type.SPOOKY)) { + set.removeAll(nspooky); + } + if(BiomeDictionary.hasType(biome, Type.DEAD)) { + set.removeAll(ndead); + } + if(BiomeDictionary.hasType(biome, Type.LUSH)) { + set.removeAll(nlush); + } + if(BiomeDictionary.hasType(biome, Type.MESA)) { + set.removeAll(nmesa); + } + if(BiomeDictionary.hasType(biome, Type.SANDY)) { + set.removeAll(nsandy); + } + + if(set.isEmpty()) { + return null; + } else { + use.addAll(set); + for(Theme theme : use) { + } + Theme theme = use.get((random.nextInt(use.size()))); + return theme; + } + } + + + /** + * Clears and re-initializes all the set used by this class. + * + * This is called by the /dldreload command to reload theme data. + */ + public static void reset() { + forest.clear(); + plains.clear(); + mountain.clear(); + hills.clear(); + swamp.clear(); + water.clear(); + desert.clear(); + frozen.clear(); + jungle.clear(); + wasteland.clear(); + nether.clear(); + end.clear(); + mushroom.clear(); + magical.clear(); + hot.clear(); + cold.clear(); + sparse.clear(); + dense.clear(); + wet.clear(); + dry.clear(); + savanna.clear(); + coniferous.clear(); + spooky.clear(); + dead.clear(); + lush.clear(); + mesa.clear(); + ocean.clear(); + sandy.clear(); + snowy.clear(); + nforest.clear(); + nplains.clear(); + nmountain.clear(); + nhills.clear(); + nswamp.clear(); + nwater.clear(); + ndesert.clear(); + nfrozen.clear(); + njungle.clear(); + nwasteland.clear(); + nnether.clear(); + nend.clear(); + nmushroom.clear(); + nmagical.clear(); + nhot.clear(); + ncold.clear(); + nsparse.clear(); + ndense.clear(); + nwet.clear(); + ndry.clear(); + nsavanna.clear(); + nconiferous.clear(); + nspooky.clear(); + ndead.clear(); + nlush.clear(); + nmesa.clear(); + nocean.clear(); + nsandy.clear(); + nsnowy.clear(); + ThemeReader.readThemes(); + } + +} diff --git a/src/jaredbgreat/dldungeons/themes/Degree.java b/src/jaredbgreat/dldungeons/themes/Degree.java new file mode 100644 index 0000000..5602344 --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/Degree.java @@ -0,0 +1,51 @@ +package jaredbgreat.dldungeons.themes; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import java.util.Random; + +/** + * This represents a discrete probability of a feature or + * characteristic to appear. This can be interpret as + * a degree of frequency or probability, with human-friendly + * constant names attached. + * + * @author Jared Blackurn + * + */ +public enum Degree implements Autoselectable { + + + NONE ( 0), + FEW ( 1), + SOME ( 3), + PLENTY ( 5), + HEAPS ( 9), + ALWAYS (10); + + + public final int value; + public static final int scale = 10; + + + Degree(int val) { + value = val; + } + + + /** + * This will return true or false based on the probability + * this Degree represents. + * + * @param random + * @return + */ + public boolean use(Random random) { + return(random.nextInt(scale) < value); + } +} \ No newline at end of file diff --git a/src/jaredbgreat/dldungeons/themes/Element.java b/src/jaredbgreat/dldungeons/themes/Element.java new file mode 100644 index 0000000..58410ed --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/Element.java @@ -0,0 +1,84 @@ +package jaredbgreat.dldungeons.themes; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +import java.util.Random; + +/** + * This a componenet of a theme representing a table of + * probabilities for a certain feature to be used. + * + * Typically, this is used for architectural style variation, + * such as levels of symmetry or complexity. + * + * @author Jared Blackurn + * + */ +public final class Element implements Autoselecting { + + private static final Degree NONE, FEW, SOME, PLENTY, HEAPS, ALWAYS; + private final int prob1, prob2, prob3, prob4, prob5, prob6; + private final int probScale; + private final boolean never; + + static { + NONE = Degree.NONE; + FEW = Degree.FEW; + SOME = Degree.SOME; + PLENTY = Degree.PLENTY; + HEAPS = Degree.HEAPS; + ALWAYS = Degree.ALWAYS; + + } + + public Element (int prob1, + int prob2, + int prob3, + int prob4, + int prob5, + int prob6) { + this.prob1 = prob1; + this.prob2 = this.prob1 + prob2; + this.prob3 = this.prob2 + prob3; + this.prob4 = this.prob3 + prob4; + this.prob5 = this.prob4 + prob5; + this.prob6 = this.prob5 + prob6; + probScale = this.prob6 + 1; + never = this.prob6 == this.prob1; + } + + + /** + * Returns a Degree for the given element which will + * be applied to the dungeon. + */ + public Degree select(Random random) { + int roll = random.nextInt(probScale); + if(roll < prob1) return Degree.NONE; + else if(roll < prob2) return Degree.FEW; + else if(roll < prob3) return Degree.SOME; + else if(roll < prob4) return Degree.PLENTY; + else if(roll < prob5) return Degree.HEAPS; + else if(roll < prob6) return Degree.ALWAYS; + else return Degree.NONE; + } + + + /** + * True if the theme can only return a degree of NONE, + * indicating the feature should never occur in dungeons of + * this type (for example, and entrance from the surface to + * a dungeons that is found on the surface). + * + * @return + */ + public boolean never() { + return never; + } + + +} diff --git a/src/jaredbgreat/dldungeons/themes/Setting.java b/src/jaredbgreat/dldungeons/themes/Setting.java new file mode 100644 index 0000000..b6b266f --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/Setting.java @@ -0,0 +1,43 @@ +package jaredbgreat.dldungeons.themes; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +/** + * An enumeration of general theme types, analogous to the biome types + * used by forge. This is used with the API to add monsters to themes, + * including those that may have been created by the player or a third + * party. + * + * @author Jared Blackburn + * + */ +public class Setting { + + public enum Type + { + FOREST, + PLAINS, + MOUNTAIN, + SWAMP, + WATER, + DESERT, + FROZEN, + JUNGLE, + WASTELAND, + NETHER, + END, + MUSHROOM, + MAGICAL, + DUNGEON, + URBAN, + TOMB, + INFERNO, + SPIRIT, + SHADOW, + CELESTIAL; + } + +} diff --git a/src/jaredbgreat/dldungeons/themes/SizeElement.java b/src/jaredbgreat/dldungeons/themes/SizeElement.java new file mode 100644 index 0000000..18e2e6d --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/SizeElement.java @@ -0,0 +1,61 @@ +package jaredbgreat.dldungeons.themes; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import java.util.Random; + +/** + * A theme element representing sizes that dungeons of + * using that them can occur in. + * + * @author Jared Blackburn + * + */ +public class SizeElement implements Autoselecting { + + private Sizes tiny, small, medium, large, huge; + private int prob1, prob2, prob3, prob4, prob5; + private int probScale; + + + public SizeElement (int prob1, + int prob2, + int prob3, + int prob4, + int prob5) { + this.tiny = Sizes.TINY; + this.prob1 = prob1; + this.small = Sizes.SMALL; + this.prob2 = prob2; + this.medium = Sizes.MEDIUM; + this.prob3 = prob3; + this.large = Sizes.LARGE; + this.prob4 = prob4; + this.huge = Sizes.HUGE; + this.prob5 = prob5; + probScale = prob1 + prob2 + prob3 + prob4 + prob5; + } + + + /** + * A Size category for the dungeon. + */ + public Sizes select(Random random) { + int roll = random.nextInt(probScale); + if(roll < prob1) return Sizes.TINY; + else roll -= prob1; + if(roll < prob2) return Sizes.SMALL; + else roll -= prob2; + if(roll < prob3) return Sizes.MEDIUM; + else roll -= prob3; + if(roll < prob4) return Sizes.LARGE; + else roll -= prob4; + if(roll < prob5) return Sizes.HUGE; + else return Sizes.MEDIUM; + } +} diff --git a/src/jaredbgreat/dldungeons/themes/Sizes.java b/src/jaredbgreat/dldungeons/themes/Sizes.java new file mode 100644 index 0000000..84f6386 --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/Sizes.java @@ -0,0 +1,37 @@ +package jaredbgreat.dldungeons.themes; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +/** + * An enumeration of dungeon size categories. + * + * @author Jared Blackburn + * + */ +public enum Sizes implements Autoselectable { + TINY (80, 39, 42, 12, 2, 2), + SMALL (96, 47, 50, 16, 3, 2), + MEDIUM (112, 55, 58, 20, 4, 2), + LARGE (144, 71, 82, 22, 5, 3), + HUGE (176, 87, 112, 24, 6, 4); + + public final int width; // Distance across the dungeon zone + public final int radius; // Square "radius" around center block (pre-calculated) + public final int maxRooms; + public final int maxRoomSize; + public final int maxNodes; + public final int minNodes; + + Sizes(int d, int r, int mr, int mrs, int maxn, int minn) { + width = d; + radius = r; + maxRooms = mr; + maxRoomSize = mrs; + maxNodes = maxn; + minNodes = minn; + } +} diff --git a/src/jaredbgreat/dldungeons/themes/Theme.java b/src/jaredbgreat/dldungeons/themes/Theme.java new file mode 100644 index 0000000..37b329b --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/Theme.java @@ -0,0 +1,245 @@ +package jaredbgreat.dldungeons.themes; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.builder.DBlock; +import jaredbgreat.dldungeons.pieces.chests.LootCategory; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashSet; +import me.zhehe.BiomeDictionary.Type; + +//import net.minecraftforge.common.BiomeDictionary.Type; + + +/** + * Themes represent dungeon styles, including blocks and mobs + * to use; and variables influencing architectural style elements + * such as the amount of symmetry, complexity, and height variability; + * and the frequency of various features such as platforms, sub-rooms, + * and pools of liquid. + * + * Each theme is tagged to appear in certain biome types and at certain + * altitudes. + * + * As with Room, this class is not truly encapsulated. While this could + * be fixed, so much of the code has since been written based on the + * unencapsulated version that at this time there is no plan to improve + * this. + * + * @author Jared Blackburn + * + */ +public class Theme { + + public String name; + public float version = 0f; + + public HashSet biomes = new HashSet(); + public HashSet notIn = new HashSet(); + + public EnumSet type = EnumSet.noneOf(ThemeType.class); + public EnumSet flags = EnumSet.noneOf(ThemeFlags.class); + + public int minY; + public int maxY; + public boolean buildFoundation; + + public SizeElement sizes; + + public Element outside; // Roofless, wall-less rooms (intend for outdoors in surface dungeons) + public Element liquids; // Quantity of water / lava pools + public Element subrooms; // Rooms budding of from the main one + public Element islands; // Rooms inside rooms + public Element pillars; // Uh, pillars / columns, duh! + public Element fences; // Uh, fences, duh! + public Element symmetry; // How symmetrical rooms are (technically, chance of axis mirroring) + public Element variability; // Inconsistency, that chance of using a different style in some place + public Element degeneracy; // Chance of walls / ceilings not spawning over air blocks (idea taken from Greymerk) + public Element complexity; // Basically how many shape primitives to add + public Element verticle; // How many height change and how much height change + public Element entrances; // Ways in and out / number of entrance/exit nodes (others are destination / treasure nodes) + public Element naturals; // An alternative cave done in 2 1/2 D + + public int[] walls; + public int[] caveWalls; + public int[] floors; + public int[] ceilings; + public int[] fencing; + public int[] liquid; + public int[] pillarBlock; + public int[] dimensionWhitelist; + + public ArrayList commonMobs = new ArrayList(); + public ArrayList hardMobs = new ArrayList(); + public ArrayList bruteMobs = new ArrayList(); + public ArrayList eliteMobs = new ArrayList(); + public ArrayList bossMobs = new ArrayList(); + public ArrayList[] allMobs; + + public String lootCat; + + + public Theme() { + minY = 10; + maxY = 50; + buildFoundation = false; + sizes = new SizeElement(2, 5, 10, 5, 1); + outside = new Element(25, 0, 0, 0, 0, 0); + liquids = new Element(1, 30, 50, 20, 10, 0); + subrooms = new Element(0, 5, 25, 60, 25, 5); + islands = new Element(5, 50, 10, 50, 20, 0); + pillars = new Element(5, 30, 60, 40, 20, 0); + symmetry = new Element(5, 15, 30, 75, 25, 0); + variability = new Element(5, 10, 25, 75, 50, 25); + degeneracy = new Element(50, 5, 15, 50, 10, 0); + complexity = new Element(5, 10, 25, 75, 15, 0); + verticle = new Element(5, 10, 25, 20, 10, 0); + entrances = new Element(2, 5, 25, 50, 15, 3); + fences = new Element(15, 25, 55, 15, 0, 0); + naturals = new Element(25, 5, 20, 10, 0, 0); + walls = makeBlockList(new String[]{}); + caveWalls = makeBlockList(new String[]{}); + floors = makeBlockList(new String[]{}); + ceilings = makeBlockList(new String[]{}); + fencing = makeBlockList(new String[]{}); + liquid = makeBlockList(new String[]{}); + pillarBlock = makeBlockList(new String[]{}); + dimensionWhitelist = new int[0]; + lootCat = "chests.cfg"; + + fixMobs(); + } + + + /** + * Add a mob to the list of mobs at the given difficulty level. + * + * @param mob + * @param level + */ + public void addMob(String mob, int level) { + switch(level) { + case 0: + if(!commonMobs.contains(mob)) commonMobs.add(mob); + return; + case 1: + if(!hardMobs.contains(mob)) hardMobs.add(mob); + return; + case 2: + if(!bruteMobs.contains(mob)) bruteMobs.add(mob); + return; + case 3: + if(!eliteMobs.contains(mob)) eliteMobs.add(mob); + return; + default: + System.err.println("[DLDUNGEONS] Failed to add mob " + mob + " to theme " + + name + ", illegal difficulty level " + level + " (use 0 to 3)."); + return; + } + } + + + /** + * Remove a mob from the list of mobs with the given difficulty + * level. This primarily for use with API to allow other mods + * to remove mobs, presumably when replacing then with an alternative. + * + * @param mob + * @param level + */ + public void removeMob(String mob, int level) { + switch(level) { + case 0: + while(commonMobs.contains(mob)) commonMobs.remove(mob); + return; + case 1: + while(hardMobs.contains(mob)) hardMobs.remove(mob); + return; + case 2: + while(bruteMobs.contains(mob)) bruteMobs.remove(mob); + return; + case 3: + while(eliteMobs.contains(mob)) eliteMobs.remove(mob); + return; + default: + System.err.println("[DLDUNGEONS] Failed to remove mob " + mob + " to theme " + + name + ", illegal difficulty level " + level + " (use 0 to 3)."); + return; + } + } + + + /** + * This makes sure that the complete set of lists has all + * of its elements (levels) set to the appropriate lists. + */ + public void fixMobs() { + allMobs = new ArrayList[5]; + allMobs[0] = printListDebug(commonMobs); + allMobs[1] = printListDebug(hardMobs); + allMobs[2] = printListDebug(bruteMobs); + allMobs[3] = printListDebug(eliteMobs); + allMobs[4] = printListDebug(bossMobs); + } + + + private ArrayList printListDebug(ArrayList list) {/* + System.out.println(list); + for(Object o : list) { + System.out.println(" \t " + o); + }*/ + return list; + } + + + /** + * Register the theme with biome types it should and + * should never appear in. + */ + public void biomeRegister() { + BiomeSets.registerTheme(this); + BiomeSets.removeTheme(this); + } + + + @Override + public String toString() { + if(name == null) return "null:" + super.toString(); + return name; + } + + + /** + * Register a block from the theme with the dungeon + * block registry. + * + * @param block + * @return + */ + private static int makeDBlock(String block) { + return DBlock.add(block); + } + + + /** + * Convert String block names read from the theme file to integer + * id's representing the blocks in terms of the dungeon block + * registry. + * + * @param in + * @return + */ + private static int[] makeBlockList(String[] in) { + int[] out = new int[in.length]; + for(int i = 0; i < in.length; i++) + out[i] = makeDBlock(in[i]); + return out; + } + +} diff --git a/src/jaredbgreat/dldungeons/themes/ThemeFlags.java b/src/jaredbgreat/dldungeons/themes/ThemeFlags.java new file mode 100644 index 0000000..f5278bc --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/ThemeFlags.java @@ -0,0 +1,24 @@ +package jaredbgreat.dldungeons.themes; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + +/** + * An enumeration of special flags that can effect dungeon generation + * in special ways that can't be represented in terms of style elements. + * + * The current version should never be considered complete or in a final + * form, as new flags, if needed, would be added by expanding the enum. + * + * @author Jared Blackburn + * + */ +public enum ThemeFlags { + WATER, + SWAMPY, + SURFACE, // This one still does nothing + HARD, + EASY; +} diff --git a/src/jaredbgreat/dldungeons/themes/ThemeReader.java b/src/jaredbgreat/dldungeons/themes/ThemeReader.java new file mode 100644 index 0000000..ab5f24b --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/ThemeReader.java @@ -0,0 +1,868 @@ +package jaredbgreat.dldungeons.themes; + + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.builder.DBlock; +import jaredbgreat.dldungeons.parser.Tokenizer; +import jaredbgreat.dldungeons.pieces.chests.LootCategory; +import jaredbgreat.dldungeons.pieces.chests.LootHandler; +import jaredbgreat.dldungeons.pieces.chests.LootItem; +import jaredbgreat.dldungeons.pieces.chests.LootListSet; +import jaredbgreat.dldungeons.pieces.chests.TreasureChest; +import jaredbgreat.dldungeons.setup.Externalizer; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.NoSuchElementException; +import java.util.logging.Level; +import java.util.logging.Logger; +import me.zhehe.BiomeDictionary.Type; +import me.zhehe.Logging; +import org.bukkit.Bukkit; +import org.bukkit.Material; + +//import net.minecraft.block.Block; +//import net.minecraftforge.common.BiomeDictionary.Type; + +/** + * This is the file IO class for reading theme files. + * + * @author Jared Blackburn + * + */ +public class ThemeReader { + + private static File configDir; + private static File themesDir; + private static File chestDir; + public static final String chestDirName = "SpecialChests"; + private static ArrayList files; + + private static final String ESTRING = ""; + + + /** + * Set the directory / folder in which themes are found. + * + * @param dir + */ + public static void setThemesDir(File dir) { + Logging.logInfo("themesdir is " + dir); + themesDir = dir; + } + + + /** + * Set the directory / folder in which config files are store, + * or more accurately, when this class will look for chests.cfg + * and which is the parent of the themes and list directories. + * + * @param dir + */ + public static void setConfigDir(File dir) { + Logging.logInfo("themesdir is " + dir); + configDir = dir; + + } + + + /** + * Get the path for the themes directory. + * + * @return path to themes as String + */ + public static String getThemesDir() { + return themesDir + File.separator; + } + + + /** + * Get the path for the mods config directory. + * + * @return path to the config directory as a String + */ + public static String getConfigDir() { + return configDir + File.separator; + } + + + /** + * This will look into the themes folder and add theme files + * to the list of files to read themes from. + * + * Technically it will treat any file ending in ".cfg" and found + * inside the theme's directory except for the supplied template + * as theme, whether it holds valid theme data or not. + * + * Themes are read as one per file, so no file can contain more + * than one theme, nor can a theme be split between multiple files. + * + * If the themes folder is absent of empty it will attempt to fill it + * by calling exporter.makerThemes. + * + * @return + */ + private static int findChestFiles(File dir) { + int num = 0; + files = new ArrayList(); + String[] fileNames = dir.list(); + // If still empty somehow don't try to read files! + if(fileNames.length < 1) return 0; + for(String name : fileNames) { + if(name.length() >= 5) { + if(name.substring(name.length() - 4).equals(".cfg")) { + files.add(new File(name)); + num++; + } + } + } + return num; + } + + + /** + * This will look into the themes folder and add theme files + * to the list of files to read themes from. + * + * Technically it will treat any file ending in ".cfg" and found + * inside the theme's directory except for the supplied template + * as theme, whether it holds valid theme data or not. + * + * Themes are read as one per file, so no file can contain more + * than one theme, nor can a theme be split between multiple files. + * + * If the themes folder is absent of empty it will attempt to fill it + * by calling exporter.makerThemes. + * + * @return + */ + private static int findThemeFiles(File dir) { + int num = 0; + Externalizer exporter; + files = new ArrayList(); + String[] fileNames = dir.list(); + if(fileNames.length < 1) { + // If the directory is empty, assume first run and fill it + exporter = new Externalizer(dir.toString() + File.separator); + exporter.makeThemes(); + fileNames = dir.list(); + } + // If still empty somehow don't try to read files! + if(fileNames.length < 1) return 0; + for(String name : fileNames) { + if(name.length() >= 5) { + if(name.equals("template.cfg")) continue; + else if(name.substring(name.length() - 4).equals(".cfg")) { + files.add(new File(name)); + num++; + } + } + } + return num; + } + + + /** + * This will find and read all the theme files in the themes + * directory, and will then read the chests.cfg from the main + * config directory. + * + * findFiles is called to get the list of files to read, while + * readTheme and openLoot are called to open the files. + */ + public static void readThemes() { + // Open loot first, so files are available + TreasureChest.initSlots(); +// openNBTConfig(); + openLoot("chests.cfg", true); + chestDir = new File(configDir.toString() + File.separator + chestDirName); + if(!chestDir.exists()) { + chestDir.mkdir(); + } + int num = findChestFiles(chestDir); + Logging.logInfo("Found " + num + " special chest configs."); + for(File file : files) openLoot(file.toString(), false); + + // Now the actual themes + num = findThemeFiles(themesDir); + Logging.logInfo("Found " + num + " themes."); + for(File file : files) readTheme(file); + } + + + /** + * Attempts to open chest.cfg, and if successful will call readLoot + * to read it. + */ +// public static void openNBTConfig() { +// BufferedReader instream = null; +// File nbtconfig = new File(configDir.toString() + File.separator + "nbt.cfg"); +// if(nbtconfig.exists()) try { +// instream = new BufferedReader(new +// FileReader(nbtconfig.toString())); +// readNBT(instream); +// if(instream != null) instream.close(); +// } catch (IOException e) { +// e.printStackTrace(); +// } else { +// Logging.logInfo("File nbt.cfg is missing; will fallabck on default loot"); +// } +// } + + + /** + * This will read the nbt.cfg file and populate BNT registry from + * its data. + * + * @param instream + * @throws IOException + */ +// public static void readNBT(BufferedReader instream) throws IOException { +// Logging.logInfo("Loading custom NBT tags (nbt.cfg)"); +// Tokenizer tokens = null; +// String line = null; +// while((line = instream.readLine()) != null) { +// if(line.length() < 2) continue; +// if(line.charAt(0) == '#') continue; +// NBTHelper.parseNBTLine(line); +// } +// } + + + /** + * Attempts to open chest.cfg, and if successful will call readLoot + * to read it. + */ + public static void openLoot(String name, boolean isMain) { + LootCategory cat = LootHandler.getLootHandler().createCategory(name); + BufferedReader instream = null; + File chests; + if(isMain) { + chests = new File(configDir.toString() + File.separator + name); + } else { + chests = new File(configDir.toString() + File.separator + + chestDirName + File.separator + name); + } + if(chests.exists()) try { + instream = new BufferedReader(new + FileReader(chests.toString())); + readLoot(instream, name, cat.getLists()); + if(instream != null) instream.close(); + } catch (IOException e) { + e.printStackTrace(); + } else { + Logging.logInfo("File " + name + " is missing; will fallabck on default loot"); + cat.getLists().addDefaultLoot(); + } + } + + + /** + * This will read the chests.cfg file and populate the loots list from + * its data. + * + * @param instream + * @throws IOException + */ + public static void readLoot(BufferedReader instream, String filename, LootListSet loots) throws IOException { + Logging.logInfo("Loading chest loot file (" + filename + ")"); + + Tokenizer tokens = null; + String line = null; + String token; + int itemid; + String item; + Material block; + + String type; + int level; + String modid; + String name; + LootItem loot; + int min; + int max; + + while((line = instream.readLine()) != null) { + if(line.length() < 2) continue; + if(line.charAt(0) == '#') continue; + tokens = new Tokenizer(line, " ,;:\t\n\r\f="); + if(!tokens.hasMoreTokens()) continue; + type = tokens.nextToken().toLowerCase(); + if(!tokens.hasMoreTokens()) continue; + level = intParser(tokens); + if(!tokens.hasMoreTokens() || (level == 0)) continue; + modid = tokens.nextToken(); + if(modid.toLowerCase().equals("item") + || modid.toLowerCase().equals("block")) + modid = "minecraft"; + if(!tokens.hasMoreTokens()) continue; + name = tokens.nextToken(); + if(!tokens.hasMoreTokens()) continue; + min = intParser(tokens); + if(!tokens.hasMoreTokens() || (min < 1)) continue; + max = intParser(tokens); + modid = "minecraft"; + item = modid + ":" + name; + loot = null; + try {//$$$ + loot = new LootItem(item, min, max, level); + } catch (Exception ex) { + Bukkit.getLogger().log(Level.SEVERE, "Unknown Item in config: " + item); + loot = null; + } + if(item != null && loot != null) { +// while(tokens.hasMoreTokens()) { +// loot.addNbt(tokens.nextToken()); +// } +// loot.trimNbt(); + loots.addItem(loot, type, level); + } + } + loots.addDiscs(); + } + + + /** + * This will attempt to open a theme file, and if successful will call + * parseTheme read the data. + * + * @param file + */ + private static void readTheme(File file) { + BufferedReader instream = null; + try { + instream = new BufferedReader(new + FileReader(themesDir.toString() + File.separator + file.toString())); + parseTheme(instream, file.toString()); + if(instream != null) instream.close(); + } catch (IOException e) { + e.printStackTrace(); + } catch (NoSuchElementException e) { + if(instream != null) { + try { + instream.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + Logging.logError("Theme " + file.toString() + + " contained a fatal error!"); + e.printStackTrace(); + File broken = new File(themesDir.toString() + + File.separator + file.toString()); + File errorFile; + File errorDir = new File(themesDir.toString() + + File.separator + "errors"); + if(!errorDir.exists()) { + errorDir.mkdir(); + } + int i = 0; + do { + errorFile = new File(errorDir.toString() + File.separator + + file.toString() + ".err" + i++); + } while (errorFile.exists()); + if(!broken.renameTo(errorFile)) { + try { + Files.move(broken.toPath(), errorFile.toPath()); + } catch (IOException ex) { + Logger.getLogger(ThemeReader.class.getName()).log(Level.SEVERE, null, ex); + } + } + if(errorFile.exists()) { + Logging.logError("Theme " + errorFile + + " was renamed to prevent " + + " further reading attempts; please fix it."); + + } else { + Logging.logError("Theme " + errorFile + + " was NOT renamed to prevent " + + " further reading attempts (please fix it);" + + " something went wrong!"); + } + } + } + + + /** + * This will read a themes data and convert it into a working theme in + * the running mod. + * + * @param instream + * @param name + * @throws IOException + * @throws NoSuchElementException + */ + public static void parseTheme(BufferedReader instream, String name) + throws IOException, NoSuchElementException { + //DoomlikeDungeons.profiler.startTask("Parsing theme " + name); + Theme theme = new Theme(); + theme.name = name; + theme.version = 1.0f; // Assume old version until a newer version number is detected + Tokenizer tokens = null; + String line = null; + String token; + String delimeters = " ,:;\t\n\r\f="; // Assume old version until a newer version number is detected + while((line = instream.readLine()) != null) { + if(line.length() < 2) continue; + if(line.charAt(0) == '#') continue; + tokens = new Tokenizer(line, delimeters); + if(!tokens.hasMoreTokens()) continue; + token = tokens.nextToken().toLowerCase(); + if(token.equals("miny")) { + theme.minY = intParser(theme.minY, tokens); + continue; + } if(token.equals("maxy")) { + theme.maxY = intParser(theme.maxY, tokens); + continue; + } if(token.equals("buildfoundation")) { + theme.buildFoundation = booleanParser(theme.buildFoundation, tokens); + continue; + } if(token.equals("sizes")) { + theme.sizes = sizeParser(theme.sizes, tokens); + continue; + } if(token.equals("dimensionwhitelist")) { + theme.dimensionWhitelist = dimensionParser(tokens); + continue; + } if(token.equals("outside")) { + theme.outside = elementParser(theme.outside, tokens); + continue; + } if(token.equals("liquids")) { + theme.liquids = elementParser(theme.liquids, tokens); + continue; + } if(token.equals("subrooms")) { + theme.subrooms = elementParser(theme.subrooms, tokens); + continue; + } if(token.equals("islands")) { + theme.islands = elementParser(theme.islands, tokens); + continue; + } if(token.equals("pillars")) { + theme.pillars = elementParser(theme.pillars, tokens); + continue; + } if(token.equals("symmetry")) { + theme.symmetry = elementParser(theme.symmetry, tokens); + continue; + } if(token.equals("variability")) { + theme.variability = elementParser(theme.variability, tokens); + continue; + } if(token.equals("degeneracy")) { + theme.degeneracy = elementParser(theme.degeneracy, tokens); + continue; + } if(token.equals("complexity")) { + theme.complexity = elementParser(theme.complexity, tokens); + continue; + } if(token.equals("verticle")) { + theme.verticle = elementParser(theme.verticle, tokens); + continue; + } if(token.equals("naturals")) { + theme.naturals = elementParser(theme.naturals, tokens); + continue; + } if(token.equals("entrances")) { + theme.entrances = elementParser(theme.entrances, tokens); + continue; + } if(token.equals("walls")) { + theme.walls = blockParser(theme.walls, tokens, theme.version); + continue; + } if(token.equals("caveblock")) { + theme.caveWalls = blockParser(theme.caveWalls, tokens, theme.version); + continue; + } if(token.equals("floors")) { + theme.floors = blockParser(theme.floors, tokens, theme.version); + continue; + } if(token.equals("ceilings")) { + theme.ceilings = blockParser(theme.ceilings, tokens, theme.version); + continue; + } if(token.equals("fencing")) { + theme.fencing = blockParser(theme.fencing, tokens, theme.version); + continue; + } if(token.equals("liquid")) { + theme.liquid = blockParser(theme.liquid, tokens, theme.version); + continue; + } if(token.equals("pillarblock")) { + theme.pillarBlock = blockParser(theme.pillarBlock, tokens, theme.version); + continue; + } if(token.equals("commonmobs")) { + theme.commonMobs = parseMobs(theme.commonMobs, tokens); + continue; + } if(token.equals("hardmobs")) { + theme.hardMobs = parseMobs(theme.hardMobs, tokens); + continue; + } if(token.equals("brutemobs")) { + theme.bruteMobs = parseMobs(theme.bruteMobs, tokens); + continue; + } if(token.equals("elitemobs")) { + theme.eliteMobs = parseMobs(theme.eliteMobs, tokens); + continue; + } if(token.equals("bossmobs")) { + theme.bossMobs = parseMobs(theme.bossMobs, tokens); + continue; + } if(token.equals("biomes")) { + theme.biomes = biomeParser(tokens); + continue; + } if(token.equals("notinbiomes")) { + theme.notIn = biomeParser(tokens); + continue; + } if(token.equals("chestsfile")) { + theme.lootCat = tokens.nextToken(); + continue; + } if(token.equals("type")) { + theme.type = typeParser(tokens); + for(ThemeType type : theme.type) { + type.addThemeToType(theme, type); + } + if(!(theme.version > 1.4f)) { + if(theme.type.contains(ThemeType.WATER)) theme.flags.add(ThemeFlags.WATER); + if(theme.type.contains(ThemeType.SWAMP)) theme.flags.add(ThemeFlags.SWAMPY); + } + continue; + } if(token.equals("flags")) { + theme.flags = flagParser(tokens); + continue; + } if(token.equals("version")) { + theme.version = floatParser(theme.version, tokens); + if(theme.version > 1.6) { + delimeters = " ,;\t\n\r\f="; + } else { + delimeters = " ,;:\t\n\r\f="; + } + continue; + } + } + theme.fixMobs(); + theme.biomeRegister(); + if(theme.caveWalls.length < 1) { + theme.caveWalls = theme.walls; + } + } + + + /** + * Read a Degree Element tag's data. + * + * @param el + * @param tokens + * @return + */ + private static Element elementParser(Element el, Tokenizer tokens) { + boolean valid = false; + int[] values = new int[]{0, 0, 0, 0, 0, 0}; + String num; + for(int i = 0; (i < values.length) && tokens.hasMoreTokens(); i++) { + num = tokens.nextToken(); + values[i] = Integer.parseInt(num); + if(values[i] < 0) values[i] = 0; + if(values[i] > 0) valid = true; + } + if(valid) return new Element(values[0], values[1], values[2], values[3], values[4], values[5]); + else return el; + } + + + /** + * Read a SizeElement tag's data. + * + * @param el + * @param tokens + * @return + */ + private static SizeElement sizeParser(SizeElement el, Tokenizer tokens) { + boolean valid = false; + int[] values = new int[]{0, 0, 0, 0, 0}; + String num; + for(int i = 0; (i < values.length) && tokens.hasMoreTokens(); i++) { + num = tokens.nextToken(); + values[i] = Integer.parseInt(num); + if(values[i] < 0) values[i] = 0; + if(values[i] > 0) valid = true; + } + if(valid) return new SizeElement(values[0], values[1], values[2], values[3], values[4]); + else return el; + } + + /** + * Read a DimensionList tag's data. + * @param tokens Tokenizer + * @return Dimension id array + */ + private static int[] dimensionParser(Tokenizer tokens) { + if (tokens.getToken(1) == null || tokens.getToken(1).equalsIgnoreCase("all")) + return new int[0]; + int[] rtn = new int[tokens.countTokens()-1]; + int i = 0; + while (tokens.hasMoreTokens()) + rtn[i++] = Integer.parseInt(tokens.nextToken()); + return rtn; + } + + + /** + * Read integer data, converting it from a String format to an int in + * the range from 6 to 223; values outside this range will be treat as + * el. This is used for reading the minimum and maximum altitude values. + * + * @param el + * @param tokens + * @return + */ + private static int intParser(int el, Tokenizer tokens) { + boolean valid = false; + int value = 0; + String num = ESTRING; + try { + if(tokens.hasMoreTokens()) { + num = tokens.nextToken(); + value = Integer.parseInt(num); + if((value > 5) && (value < 224)) valid = true; + } + } catch(Exception e) { + Logging.logError("ThemeReader.intParser(int el, Tokenizer tokens) tried to read non-number as integer"); + Logging.logError("Value passed as and integer was: " + num); + e.printStackTrace(); + return el; + } + if(valid) return value; + else return el; + } + + + /** + * Read floating point data, converting it from a String format to a float. + * + * @param el + * @param tokens + * @return + */ + private static float floatParser(float el, Tokenizer tokens) { + float value = 0f; + String num = ESTRING; + try { + if(tokens.hasMoreTokens()) { + num = tokens.nextToken(); + value = Float.parseFloat(num); + } + } catch(Exception e) { + Logging.logError("ThemeReader.floatParser(float el, Tokenizer tokens) tried to read non-number as float"); + Logging.logError("Value passed as and foat was: " + num); + return el; + } + return value; + } + + + /** + * This will read integer data, converting it from a String format + * to an int. This is the method that should be used for reading + * general int data. If the token passed in is not a valid integer + * the method return -1. + * + * @param tokens + * @return + */ + private static int intParser(Tokenizer tokens) { + int value = 0; + String num = ESTRING; + try { + if(tokens.hasMoreTokens()) { + num = tokens.nextToken().trim(); + value = Integer.parseInt(num); + } + } catch(Exception e) { + Logging.logError("ThemeReader.intParser(Tokenizer tokens) tried to read non-number as integer"); + Logging.logError("Value passed as and integer was: " + num); + return -1; + } + return value; + } + + + /** + * This will parse boolean data, converting it from a string format + * to a boolean. + * + * @param el + * @param tokens + * @return + */ + private static boolean booleanParser(boolean el, Tokenizer tokens) { + boolean valid = false; + boolean bool; + if(tokens.hasMoreTokens()) { + bool = Boolean.parseBoolean(tokens.nextToken()); + } else return el; + return bool; + } + + + /** + * This will read in a block data and convert it from string format to an + * of int's holding dungeon block id's (indices in DBlock.registry). The + * int's are then appended to the passed in int array "el"; this allows + * multiple lines of data to be used for one block related component. + * + * These blocks can then + * + * @param el + * @param tokens + * @param version + * @return + * @throws NoSuchElementException + */ + private static int[] blockParser(int[] el, + Tokenizer tokens, float version) throws NoSuchElementException { + ArrayList values = new ArrayList(); + String nums; + while(tokens.hasMoreTokens()) { + nums = tokens.nextToken(); + int tmp; + try { + tmp = DBlock.add(nums); + } catch (NoSuchElementException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Unknown block in config: nums"); + tmp = -1; + } + if(tmp != -1) values.add(String.valueOf(tmp)); + } + int[] out = new int[values.size() + el.length]; + for(int i = 0; i < el.length; i++) { + out[i] = el[i]; + } + for(int i = 0; i < values.size(); i++) { + out[i + el.length] = Integer.parseInt(values.get(i)); + } + return out; + } + + + /** + * This will turn tokens read from the them file to be added to the list + * of mobs names to use for creating spawners. + * + * @param el + * @param tokens + * @return + */ + private static ArrayList parseMobs(ArrayList el, Tokenizer tokens) { + ArrayList mobs; + if(el != null) { + mobs = el; + } else { + mobs = new ArrayList(); + } + while(tokens.hasMoreTokens()) { + String nextMob = tokens.nextToken(); + mobs.add(nextMob); + } + return mobs; + } + + + /** + * This will convert tokens in string format to a set of biome types. + * + * @param tokens + * @return + */ + private static HashSet biomeParser(Tokenizer tokens) { + String name; + HashSet biomes = new HashSet(); + while(tokens.hasMoreTokens()) { + name = tokens.nextToken().toUpperCase(); + // Old biome types + if(name.equals("FOREST")) biomes.add(Type.FOREST); + else if(name.equals("PLAINS")) biomes.add(Type.PLAINS); + else if(name.equals("MOUNTAINS")) biomes.add(Type.MOUNTAIN); + else if(name.equals("HILLS")) biomes.add(Type.HILLS); + else if(name.equals("SWAMP")) biomes.add(Type.SWAMP); + else if(name.equals("WATER")) biomes.add(Type.WATER); + else if(name.equals("JUNGLE")) biomes.add(Type.JUNGLE); + else if(name.equals("WASTELAND")) biomes.add(Type.WASTELAND); + else if(name.equals("BEACH")) biomes.add(Type.BEACH); + else if(name.equals("NETHER")) biomes.add(Type.NETHER); + else if(name.equals("END")) biomes.add(Type.END); + else if(name.equals("MUSHROOM")) biomes.add(Type.MUSHROOM); + else if(name.equals("MAGICAL")) biomes.add(Type.MAGICAL); + // New biome types + else if(name.equals("HOT")) biomes.add(Type.HOT); + else if(name.equals("COLD")) biomes.add(Type.COLD); + else if(name.equals("DENSE")) biomes.add(Type.DENSE); + else if(name.equals("SPARSE")) biomes.add(Type.SPARSE); + else if(name.equals("WET")) biomes.add(Type.WET); + else if(name.equals("DRY")) biomes.add(Type.DRY); + else if(name.equals("SAVANNA")) biomes.add(Type.SAVANNA); + else if(name.equals("CONIFEROUS")) biomes.add(Type.CONIFEROUS); + else if(name.equals("SPOOKY")) biomes.add(Type.SPOOKY); + else if(name.equals("DEAD")) biomes.add(Type.DEAD); + else if(name.equals("LUSH")) biomes.add(Type.LUSH); + else if(name.equals("MESA")) biomes.add(Type.MESA); + else if(name.equals("SANDY")) biomes.add(Type.SANDY); + else if(name.equals("SNOWY")) biomes.add(Type.SNOWY); + } + return biomes; + } + + + /** + * This will convert tokens in string format to a set of ThemeTypes. + * + * @param tokens + * @return + */ + private static EnumSet typeParser(Tokenizer tokens) { + String name; + EnumSet types = EnumSet.noneOf(ThemeType.class); + while(tokens.hasMoreTokens()) { + name = tokens.nextToken().toUpperCase(); + if(name.equals("FOREST")) types.add(ThemeType.FOREST); + else if(name.equals("PLAINS")) types.add(ThemeType.PLAINS); + else if(name.equals("MOUNTAINS")) types.add(ThemeType.MOUNTAIN); + else if(name.equals("SWAMP")) types.add(ThemeType.SWAMP); + else if(name.equals("WATER")) types.add(ThemeType.WATER); + else if(name.equals("DESERT")) types.add(ThemeType.DESERT); + else if(name.equals("FROZEN")) types.add(ThemeType.FROZEN); + else if(name.equals("JUNGLE")) types.add(ThemeType.JUNGLE); + else if(name.equals("WASTELAND")) types.add(ThemeType.WASTELAND); + else if(name.equals("NETHER")) types.add(ThemeType.NETHER); + else if(name.equals("END")) types.add(ThemeType.END); + else if(name.equals("MUSHROOM")) types.add(ThemeType.MUSHROOM); + else if(name.equals("MAGICAL")) types.add(ThemeType.MAGICAL); + else if(name.equals("DUNGEON")) types.add(ThemeType.DUNGEON); + else if(name.equals("URBAN")) types.add(ThemeType.URBAN); + else if(name.equals("NECRO")) types.add(ThemeType.NECRO); + else if(name.equals("FIERY")) types.add(ThemeType.FIERY); + else if(name.equals("SHADOW")) types.add(ThemeType.SHADOW); + else if(name.equals("TECH")) types.add(ThemeType.TECH); + else if(name.equals("PARADISE")) types.add(ThemeType.PARADISE); + } + return types; + } + + + /** + * This will convert tokens in string format to a set of ThemeFlags. + * + * @param tokens + * @return + */ + private static EnumSet flagParser(Tokenizer tokens) { + String name; + EnumSet flags = EnumSet.noneOf(ThemeFlags.class); + while(tokens.hasMoreTokens()) { + name = tokens.nextToken().toUpperCase(); + if(name.equals("SWAMPY")) flags.add(ThemeFlags.SWAMPY); + else if(name.equals("WATER")) flags.add(ThemeFlags.WATER); + else if(name.equals("SURFACE")) flags.add(ThemeFlags.SURFACE); + } + return flags; + } + + +} diff --git a/src/jaredbgreat/dldungeons/themes/ThemeType.java b/src/jaredbgreat/dldungeons/themes/ThemeType.java new file mode 100644 index 0000000..a89620c --- /dev/null +++ b/src/jaredbgreat/dldungeons/themes/ThemeType.java @@ -0,0 +1,214 @@ +package jaredbgreat.dldungeons.themes; + +/* + * Doomlike Dungeons by is licensed the MIT License + * Copyright (c) 2014-2018 Jared Blackburn + */ + + +import jaredbgreat.dldungeons.ConfigHandler; + +import java.util.ArrayList; +import java.util.EnumSet; + + +/*This mod 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 . +*/ + +/** + * This is an enumeration of theme types to be used with the API, primarily + * for adding mobs to themes which may have been created by another third + * party. + * + * The methods in this class should not usually be called directly; they + * are inteded to be called through the mods API. + * + * @author Jared Blackburn + * + */ +public enum ThemeType { + DUNGEON (new ArrayList[5], new ArrayList(), new ArrayList[5]), + NECRO (new ArrayList[5], new ArrayList(), new ArrayList[5]), + URBAN (new ArrayList[5], new ArrayList(), new ArrayList[5]), + FOREST (new ArrayList[5], new ArrayList(), new ArrayList[5]), + PLAINS (new ArrayList[5], new ArrayList(), new ArrayList[5]), + MOUNTAIN (new ArrayList[5], new ArrayList(), new ArrayList[5]), + SWAMP (new ArrayList[5], new ArrayList(), new ArrayList[5]), + WATER (new ArrayList[5], new ArrayList(), new ArrayList[5]), + DESERT (new ArrayList[5], new ArrayList(), new ArrayList[5]), + WASTELAND (new ArrayList[5], new ArrayList(), new ArrayList[5]), + JUNGLE (new ArrayList[5], new ArrayList(), new ArrayList[5]), + FROZEN (new ArrayList[5], new ArrayList(), new ArrayList[5]), + FIERY (new ArrayList[5], new ArrayList(), new ArrayList[5]), + NETHER (new ArrayList[5], new ArrayList(), new ArrayList[5]), + END (new ArrayList[5], new ArrayList(), new ArrayList[5]), + MUSHROOM (new ArrayList[5], new ArrayList(), new ArrayList[5]), + MAGICAL (new ArrayList[5], new ArrayList(), new ArrayList[5]), + SHADOW (new ArrayList[5], new ArrayList(), new ArrayList[5]), + PARADISE (new ArrayList[5], new ArrayList(), new ArrayList[5]), + TECH (new ArrayList[5], new ArrayList(), new ArrayList[5]); + + + public final ArrayList[] mobs; + public final ArrayList themes; + public final ArrayList[] mobsOut; + + private static final EnumSet all = EnumSet.allOf(ThemeType.class); + + + ThemeType(ArrayList[] mobs, ArrayList themes, ArrayList[] mobsOut) { + this.mobs = mobs; + this.themes = themes; + this.mobsOut = mobsOut; + for(int i = 0; i < 5; i++) { + this.mobs[i] = new ArrayList(); + this.mobsOut[i] = new ArrayList(); + } + } + + + /** + * Get a type from its name. This is mostly a wrapper for valueOf, + * but takes care of some string clean-up. + * + * @param name + * @return + */ + public static ThemeType type(String name) { + return ThemeType.valueOf(name.toUpperCase().trim()); + } + + + /** + * This will register a theme as being of the type named with the + * String. + * + * @param theme + * @param theType + */ + public static void addThemeToType(Theme theme, String theType) { + type(theType).themes.add(theme); + } + + + /** + * This will register a theme as belonging to a give type. + * + * @param theme + * @param theType + */ + public static void addThemeToType(Theme theme, ThemeType theType) { + theType.themes.add(theme); + } + + + /** + * This will register a mob to be added to themes of the given type and + * as the given difficulty level. + * + * @param mob + * @param level + * @param theType + */ + public static void addMobToType(String mob, int level, String theType) { + if(ConfigHandler.disableAPI || ConfigHandler.noMobChanges) return; + ArrayList list = type(theType).mobs[level]; + if(!list.contains(mob)) { + list.add(mob); + } + } + + + /** + * This will register a mob to be removed themes of the given type at the given + * difficulty level. + * + * @param mob + * @param level + * @param theType + */ + public static void removeMobFromType(String mob, int level, String theType) { + if(ConfigHandler.disableAPI || ConfigHandler.noMobChanges) return; + ArrayList list = type(theType).mobs[level]; + if(!list.contains(mob)) list.add(mob); + } + + + /** + * This will immediately remove the move from mob-lists of the given difficulty + * level for all themes of the given type. + * + * @param mob + * @param level + * @param theType + */ + public static void removeMobFromTypeNow(String mob, int level, String theType) { + if(ConfigHandler.disableAPI || ConfigHandler.noMobChanges) return; + for(Theme theme : type(theType).themes) { + if(!mob.isEmpty()) theme.removeMob(mob, level); + } + } + + + /** + * This will immediately add the named mob to all themes of the given type at + * the given level. + * + * @param mob + * @param level + * @param theType + */ + public static void addMobToTypeNow(String mob, int level, String theType) { + if(ConfigHandler.disableAPI || ConfigHandler.noMobChanges) return; + for(Theme theme : type(theType).themes) { + if(!mob.isEmpty()) theme.addMob(mob, level); + } + } + + + /** + * This will apply all type-based mob additions and subtraction listed for all + * themes of all types. + */ + public static void SyncMobLists() { + for(ThemeType current : all) { + //System.out.println("[DLD] Trying theme type " + current); + if(current.themes.isEmpty()) continue; + //System.out.println("[DLD] Adding to theme type " + current); + for(Theme theme : current.themes) { + for(int i = 0; i < 5; i++) { + //System.out.println("[DLD] Starting on theme " + theme); + if(current.mobs[i].isEmpty()) continue; + for(String mob : current.mobs[i]) { + //System.out.println("[DLD] Adding " + mob + "to theme " + theme); + theme.addMob(mob, i); + } + } + theme.fixMobs(); + } + } + for(ThemeType current : all) { + if(current.themes.isEmpty()) continue; + for(Theme theme : current.themes) { + for(int i = 0; i < 5; i++) { + if(current.mobsOut[i].isEmpty()) continue; + for(String mob : current.mobsOut[i]) { + theme.removeMob(mob, i); + } + } + theme.fixMobs(); + } + } + } +} diff --git a/src/me/zhehe/BiomeDictionary.java b/src/me/zhehe/BiomeDictionary.java new file mode 100644 index 0000000..5d16968 --- /dev/null +++ b/src/me/zhehe/BiomeDictionary.java @@ -0,0 +1,288 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package me.zhehe; + +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +//import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import java.util.*; +//import java.util.stream.Collectors; +//import javax.annotation.Nonnull; +import org.bukkit.block.Biome; +import static me.zhehe.BiomeDictionary.Type.*; + +public class BiomeDictionary +{ + private static final boolean DEBUG = false; + + private static final Set dict = new HashSet<>(); + + public static final class Type + { + + private static final Map byName = new HashMap(); + private static Collection allTypes = Collections.unmodifiableCollection(byName.values()); + + /*Temperature-based tags. Specifying neither implies a biome is temperate*/ + public static final Type HOT = new Type("HOT"); + public static final Type COLD = new Type("COLD"); + + /*Tags specifying the amount of vegetation a biome has. Specifying neither implies a biome to have moderate amounts*/ + public static final Type SPARSE = new Type("SPARSE"); + public static final Type DENSE = new Type("DENSE"); + + /*Tags specifying how moist a biome is. Specifying neither implies the biome as having moderate humidity*/ + public static final Type WET = new Type("WET"); + public static final Type DRY = new Type("DRY"); + + /*Tree-based tags, SAVANNA refers to dry, desert-like trees (Such as Acacia), CONIFEROUS refers to snowy trees (Such as Spruce) and JUNGLE refers to jungle trees. + * Specifying no tag implies a biome has temperate trees (Such as Oak)*/ + public static final Type SAVANNA = new Type("SAVANNA"); + public static final Type CONIFEROUS = new Type("CONIFEROUS"); + public static final Type JUNGLE = new Type("JUNGLE"); + + /*Tags specifying the nature of a biome*/ + public static final Type SPOOKY = new Type("SPOOKY"); + public static final Type DEAD = new Type("DEAD"); + public static final Type LUSH = new Type("LUSH"); + public static final Type NETHER = new Type("NETHER"); + public static final Type END = new Type("END"); + public static final Type MUSHROOM = new Type("MUSHROOM"); + public static final Type MAGICAL = new Type("MAGICAL"); + public static final Type RARE = new Type("RARE"); + + public static final Type OCEAN = new Type("OCEAN"); + public static final Type RIVER = new Type("RIVER"); + /** + * A general tag for all water-based biomes. Shown as present if OCEAN or RIVER are. + **/ + public static final Type WATER = new Type("WATER", OCEAN, RIVER); + + /*Generic types which a biome can be*/ + public static final Type MESA = new Type("MESA"); + public static final Type FOREST = new Type("FOREST"); + public static final Type PLAINS = new Type("PLAINS"); + public static final Type MOUNTAIN = new Type("MOUNTAIN"); + public static final Type HILLS = new Type("HILLS"); + public static final Type SWAMP = new Type("SWAMP"); + public static final Type SANDY = new Type("SANDY"); + public static final Type SNOWY = new Type("SNOWY"); + public static final Type WASTELAND = new Type("WASTELAND"); + public static final Type BEACH = new Type("BEACH"); + public static final Type VOID = new Type("VOID"); + + private final String name; + private final List subTypes; + private final Set biomes = new HashSet(); +// private final Set biomesUn = Collections.unmodifiableSet(biomes); + + private Type(String name, Type... subTypes) + { + this.name = name; + this.subTypes = ImmutableList.copyOf(subTypes); + + byName.put(name, this); + } + + + private boolean hasSubTypes() + { + return !subTypes.isEmpty(); + } + + /** + * Gets the name for this type. + */ + public String getName() + { + return name; + } + + public String toString() + { + return name; + } + + /** + * Retrieves a Type instance by name, + * if one does not exist already it creates one. + * This can be used as intermediate measure for modders to + * add their own Biome types. + *

+ * There are no naming conventions besides: + *

  • Must be all upper case (enforced by name.toUpper())
  • + *
  • No Special characters. {Unenforced, just don't be a pain, if it becomes a issue I WILL + * make this RTE with no worry about backwards compatibility}
+ *

+ * Note: For performance sake, the return value of this function SHOULD be cached. + * Two calls with the same name SHOULD return the same value. + * + * @param name The name of this Type + * @return An instance of Type for this name. + */ + public static Type getType(String name, Type... subTypes) + { + name = name.toUpperCase(); + Type t = byName.get(name); + if (t == null) + { + t = new Type(name, subTypes); + } + return t; + } + + /** + * @return An unmodifiable collection of all current biome types. + */ + public static Collection getAll() + { + return allTypes; + } + } + +// private static final Map biomeInfoMap = new HashMap(); + + public static boolean hasType(Biome biome, Type type) { + return type.biomes.contains(biome); + } + + private static class BiomeInfo + { + + private final Set types = new HashSet(); + private final Set typesUn = Collections.unmodifiableSet(this.types); + + } + + static + { + registerVanillaBiomes(); + } + + /** + * Adds the given types to the biome. + * + */ + public static void addTypes(Biome biome, Type... types) + { + for (Type type : types) + { + type.biomes.add(biome); + dict.add(type); + } + + } + + public static Set getTypes(Biome biome) { + Set res = new HashSet<>(); + for(Type type : dict) { + if(type.biomes.contains(biome)) res.add(type); + } + return res; + } + + + + private static void registerVanillaBiomes() + { + addTypes(Biome.OCEAN, OCEAN ); + addTypes(Biome.WARM_OCEAN, OCEAN ); + addTypes(Biome.LUKEWARM_OCEAN, OCEAN ); + addTypes(Biome.DEEP_LUKEWARM_OCEAN, OCEAN ); + addTypes(Biome.DEEP_OCEAN, OCEAN ); + addTypes(Biome.COLD_OCEAN, OCEAN ); + addTypes(Biome.DEEP_COLD_OCEAN, OCEAN ); + + addTypes(Biome.PLAINS, PLAINS ); + addTypes(Biome.DESERT, HOT, DRY, SANDY ); + addTypes(Biome.MOUNTAINS, MOUNTAIN, HILLS ); + addTypes(Biome.FOREST, FOREST ); + addTypes(Biome.TAIGA, COLD, CONIFEROUS, FOREST ); + addTypes(Biome.SWAMP, WET, SWAMP ); + addTypes(Biome.RIVER, RIVER ); + addTypes(Biome.NETHER, HOT, DRY, NETHER ); + addTypes(Biome.THE_END, COLD, DRY, END ); + addTypes(Biome.SMALL_END_ISLANDS, COLD, DRY, END ); + addTypes(Biome.END_MIDLANDS, COLD, DRY, END ); + addTypes(Biome.END_HIGHLANDS, COLD, DRY, END ); + addTypes(Biome.END_BARRENS, COLD, DRY, END ); + addTypes(Biome.FROZEN_OCEAN, COLD, OCEAN, SNOWY ); + addTypes(Biome.DEEP_FROZEN_OCEAN, COLD, OCEAN, SNOWY ); + + addTypes(Biome.FROZEN_RIVER, COLD, RIVER, SNOWY ); + addTypes(Biome.SNOWY_TUNDRA, COLD, SNOWY, WASTELAND ); + addTypes(Biome.SNOWY_MOUNTAINS, COLD, SNOWY, MOUNTAIN ); + addTypes(Biome.MUSHROOM_FIELDS, MUSHROOM, RARE ); + addTypes(Biome.MUSHROOM_FIELD_SHORE, MUSHROOM, BEACH, RARE ); + addTypes(Biome.BEACH, BEACH ); + addTypes(Biome.DESERT_HILLS, HOT, DRY, SANDY, HILLS ); + addTypes(Biome.WOODED_HILLS, FOREST, HILLS ); + addTypes(Biome.TAIGA_HILLS, COLD, CONIFEROUS, FOREST, HILLS ); + addTypes(Biome.MOUNTAIN_EDGE, MOUNTAIN ); + addTypes(Biome.JUNGLE, HOT, WET, DENSE, JUNGLE ); + addTypes(Biome.JUNGLE_HILLS, HOT, WET, DENSE, JUNGLE, HILLS ); + addTypes(Biome.JUNGLE_EDGE, HOT, WET, JUNGLE, FOREST, RARE ); + addTypes(Biome.DEEP_OCEAN, OCEAN ); + addTypes(Biome.STONE_SHORE, BEACH ); + addTypes(Biome.SNOWY_BEACH, COLD, BEACH, SNOWY ); + addTypes(Biome.BIRCH_FOREST, FOREST ); + addTypes(Biome.BIRCH_FOREST_HILLS, FOREST, HILLS ); + addTypes(Biome.DARK_FOREST, SPOOKY, DENSE, FOREST ); + addTypes(Biome.SNOWY_TAIGA, COLD, CONIFEROUS, FOREST, SNOWY ); + addTypes(Biome.SNOWY_TAIGA_HILLS, COLD, CONIFEROUS, FOREST, SNOWY, HILLS ); + addTypes(Biome.GIANT_TREE_TAIGA, COLD, CONIFEROUS, FOREST ); + addTypes(Biome.GIANT_TREE_TAIGA_HILLS, COLD, CONIFEROUS, FOREST, HILLS ); + addTypes(Biome.WOODED_MOUNTAINS, MOUNTAIN, FOREST, SPARSE ); + addTypes(Biome.SAVANNA, HOT, SAVANNA, PLAINS, SPARSE ); + addTypes(Biome.SAVANNA_PLATEAU, HOT, SAVANNA, PLAINS, SPARSE, RARE ); + addTypes(Biome.BADLANDS, MESA, SANDY, DRY ); + addTypes(Biome.WOODED_BADLANDS_PLATEAU, MESA, SANDY, DRY, SPARSE ); + addTypes(Biome.BADLANDS_PLATEAU, MESA, SANDY, DRY ); + addTypes(Biome.THE_VOID, VOID ); + addTypes(Biome.SUNFLOWER_PLAINS, PLAINS, RARE ); + addTypes(Biome.DESERT_LAKES, HOT, DRY, SANDY, RARE ); + addTypes(Biome.GRAVELLY_MOUNTAINS, MOUNTAIN, SPARSE, RARE ); + addTypes(Biome.FLOWER_FOREST, FOREST, HILLS, RARE ); + addTypes(Biome.TAIGA_MOUNTAINS, COLD, CONIFEROUS, FOREST, MOUNTAIN, RARE ); + addTypes(Biome.SWAMP_HILLS, WET, SWAMP, HILLS, RARE ); + addTypes(Biome.ICE_SPIKES, COLD, SNOWY, HILLS, RARE ); + addTypes(Biome.MODIFIED_JUNGLE, HOT, WET, DENSE, JUNGLE, MOUNTAIN, RARE); + addTypes(Biome.MODIFIED_JUNGLE_EDGE, HOT, SPARSE, JUNGLE, HILLS, RARE ); + addTypes(Biome.TALL_BIRCH_FOREST, FOREST, DENSE, HILLS, RARE ); + addTypes(Biome.TALL_BIRCH_HILLS, FOREST, DENSE, MOUNTAIN, RARE ); + addTypes(Biome.DARK_FOREST_HILLS, SPOOKY, DENSE, FOREST, MOUNTAIN, RARE ); + addTypes(Biome.SNOWY_TAIGA_MOUNTAINS, COLD, CONIFEROUS, FOREST, SNOWY, MOUNTAIN, RARE); + addTypes(Biome.GIANT_SPRUCE_TAIGA, DENSE, FOREST, RARE ); + addTypes(Biome.GIANT_SPRUCE_TAIGA_HILLS, DENSE, FOREST, HILLS, RARE ); + addTypes(Biome.MODIFIED_GRAVELLY_MOUNTAINS, MOUNTAIN, SPARSE, RARE ); + addTypes(Biome.SHATTERED_SAVANNA, HOT, DRY, SPARSE, SAVANNA, MOUNTAIN, RARE); + addTypes(Biome.SHATTERED_SAVANNA_PLATEAU, HOT, DRY, SPARSE, SAVANNA, HILLS, RARE); + addTypes(Biome.ERODED_BADLANDS, HOT, DRY, SPARSE, MOUNTAIN, RARE ); + addTypes(Biome.MODIFIED_WOODED_BADLANDS_PLATEAU, HOT, DRY, SPARSE, HILLS, RARE ); + addTypes(Biome.MODIFIED_BADLANDS_PLATEAU, HOT, DRY, SPARSE, MOUNTAIN, RARE ); + + } +} \ No newline at end of file diff --git a/src/me/zhehe/Configuration.java b/src/me/zhehe/Configuration.java new file mode 100644 index 0000000..321b328 --- /dev/null +++ b/src/me/zhehe/Configuration.java @@ -0,0 +1,183 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package me.zhehe; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * @author Zhehe + */ +public class Configuration { + public List Category = new ArrayList<>(); + public List> Content = new ArrayList<>(); + public File file; + public Configuration(File file) { + this.file = file; + } + + public void addCustomCategoryComment(String name, String comment) { + if(Category.contains(name)) return; + Category.add(name); + Content.add(new HashMap()); + } + + public IProperty get(String category, String key, int dvalue, String comment) { + if(!Category.contains(category)) { + Category.add(category); + Map sub = new HashMap<>(); + sub.put(key, Integer.toString(dvalue)); + Content.add(sub); + return new IProperty(Integer.toString(dvalue)); + } + int index = Category.indexOf(category); + Map dict = Content.get(index); + if(!dict.containsKey(key)) { + dict.put(key, Integer.toString(dvalue)); + return new IProperty(Integer.toString(dvalue)); + } + return new IProperty(dict.get(key)); + } + + public IProperty get(String category, String key, int[] array, String comment) { + if(!Category.contains(category)) { + Category.add(category); + Map sub = new HashMap<>(); + sub.put(key, intArrayToString(array)); + Content.add(sub); + return new IProperty(intArrayToString(array)); + } + int index = Category.indexOf(category); + Map dict = Content.get(index); + if(!dict.containsKey(key)) { + dict.put(key, intArrayToString(array)); + return new IProperty(intArrayToString(array)); + } + return new IProperty(dict.get(key)); + } + + public IProperty get(String category, String key, boolean bool, String comment) { + if(!Category.contains(category)) { + Category.add(category); + Map sub = new HashMap<>(); + sub.put(key, Boolean.toString(bool)); + Content.add(sub); + return new IProperty(Boolean.toString(bool)); + } + int index = Category.indexOf(category); + Map dict = Content.get(index); + if(!dict.containsKey(key)) { + dict.put(key, Boolean.toString(bool)); + return new IProperty(Boolean.toString(bool)); + } + return new IProperty(dict.get(key)); + } + + public IProperty get(String category, String key, String[] array, String comment) { + if(!Category.contains(category)) { + Category.add(category); + Map sub = new HashMap<>(); + sub.put(key, StringArrayToString(array)); + Content.add(sub); + return new IProperty(StringArrayToString(array)); + } + int index = Category.indexOf(category); + Map dict = Content.get(index); + if(!dict.containsKey(key)) { + dict.put(key, StringArrayToString(array)); + return new IProperty(StringArrayToString(array)); + } + return new IProperty(dict.get(key)); + } + + private static String intArrayToString(int[] array) { + StringBuilder sb = new StringBuilder(); + for(int value : array) { + sb.append(value); + sb.append(','); + } + sb.setLength(sb.length() - 1); + return sb.toString(); + } + + private static String StringArrayToString(String[] array) { + StringBuilder sb = new StringBuilder(); + for(String value : array) { + sb.append(value); + sb.append(','); + } + sb.setLength(sb.length() - 1); + return sb.toString(); + } + + public int getInt(String name, String category, int defaultValue, int minValue, int maxValue, String comment) { + if(!Category.contains(category)) { + Category.add(category); + Map sub = new HashMap<>(); + sub.put(name, Integer.toString(defaultValue)); + Content.add(sub); + return defaultValue; + } + int index = Category.indexOf(category); + Map dict = Content.get(index); + if(!dict.containsKey(name)) { + dict.put(name, Integer.toString(defaultValue)); + return defaultValue; + } + String tmp = dict.get(name); + int res; + try { + res = Integer.parseInt(tmp); + } catch (Exception ex) { + res = defaultValue; + } + + if(res < minValue) res = minValue; + if(res > maxValue) res = maxValue; + return res; + } + + public void load() { + Configuration cf; + try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"))) { + StringBuilder sb = new StringBuilder(); + String line = reader.readLine(); + while (line != null) { + sb.append(line); + line = reader.readLine(); + } + cf = (new Gson()).fromJson(sb.toString(), Configuration.class); + } catch (Exception ex) { + return; + } + if(cf == null) return; + this.Category = cf.Category; + this.Content = cf.Content; + } + + public void save() { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + String json = gson.toJson(this); + try(OutputStreamWriter oStreamWriter = new OutputStreamWriter(new FileOutputStream(file), "utf-8")) { + oStreamWriter.append(json); + oStreamWriter.close(); + } catch (IOException ex) { + + } + } +} diff --git a/src/me/zhehe/Constant.java b/src/me/zhehe/Constant.java new file mode 100644 index 0000000..471e430 --- /dev/null +++ b/src/me/zhehe/Constant.java @@ -0,0 +1,20 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package me.zhehe; + +import org.bukkit.Bukkit; +import org.bukkit.block.data.BlockData; + +public class Constant { + public static BlockData ladder5 = Bukkit.createBlockData("minecraft:ladder[facing=east]"); + public static BlockData ladder4 = Bukkit.createBlockData("minecraft:ladder[facing=west]"); + public static BlockData ladder3 = Bukkit.createBlockData("minecraft:ladder[facing=south]"); + public static BlockData ladder2 = Bukkit.createBlockData("minecraft:ladder[facing=north]"); + + public static BlockData slab0 = Bukkit.createBlockData("minecraft:stone_slab[type=bottom]"); + public static BlockData slab8 = Bukkit.createBlockData("minecraft:stone_slab[type=top]"); +} diff --git a/src/me/zhehe/DungeonPopulator.java b/src/me/zhehe/DungeonPopulator.java new file mode 100644 index 0000000..f2f7f0b --- /dev/null +++ b/src/me/zhehe/DungeonPopulator.java @@ -0,0 +1,52 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package me.zhehe; + +import jaredbgreat.dldungeons.ConfigHandler; +import static jaredbgreat.dldungeons.builder.Builder.placeDungeon; +import java.util.Random; +import java.util.Set; +import me.zhehe.BiomeDictionary.Type; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.generator.BlockPopulator; + +public class DungeonPopulator extends BlockPopulator { + private static int factor = 6; + + @Override + public void populate(final World world, final Random random, final Chunk source) { + if(!Main.enable) return; + boolean blockedBiome = false; + Biome biome = world.getBiome(source.getX() * 16, source.getZ() * 16); + if(biome == Biome.NETHER) { + if(random.nextInt(5) > 0) return; + } + Set types = BiomeDictionary.getTypes(biome); + for(Type type : types) { + blockedBiome = ConfigHandler.biomeExclusions.contains(type) || blockedBiome; + } + if(blockedBiome) return; + + Random mrand = new Random(world.getSeed() + + (2027 * (long)(source.getX() / factor)) + + (1987 * (long)(source.getX() / factor))); + int xrand = mrand.nextInt(); + int zrand = mrand.nextInt(); + int xuse = ((source.getX() + xrand) % factor); + int zuse = ((source.getZ() + zrand) % factor); + + if((xuse == 0) && (zuse == 0)) { + try { + placeDungeon(random, source.getX(), source.getZ(), world); + } catch (Throwable e) { + System.err.println("[DLDUNGEONS] Danger! Failed to finalize a dungeon after building!"); + e.printStackTrace(); + } + } + } +} diff --git a/src/me/zhehe/IProperty.java b/src/me/zhehe/IProperty.java new file mode 100644 index 0000000..e6e0e4f --- /dev/null +++ b/src/me/zhehe/IProperty.java @@ -0,0 +1,70 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package me.zhehe; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Zhehe + */ +public class IProperty { + String value; + public IProperty(String value) { + this.value = value; + } + + public int getInt() { + try { + return Integer.parseInt(value); + } catch(Exception ex) { + return 0; + } + } + + public boolean getBoolean(Boolean bool) { + try { + return Boolean.parseBoolean(value); + } catch(Exception ex) { + return bool; + } + } + + public String[] getStringList() { + List list = new ArrayList<>(); + String[] array = value.split(","); + for(String sub : array) { + try { + list.add(sub); + } catch(Exception ex) { + + } + } + String[] res = new String[list.size()]; + for(int i = 0; i < res.length; i++) { + res[i] = list.get(i); + } + return res; + } + + public int[] getIntList() { + List list = new ArrayList<>(); + String[] array = value.split(","); + for(String sub : array) { + try { + list.add(Integer.parseInt(sub)); + } catch(Exception ex) { + + } + } + int[] res = new int[list.size()]; + for(int i = 0; i < res.length; i++) { + res[i] = list.get(i); + } + return res; + } +} diff --git a/src/me/zhehe/Logging.java b/src/me/zhehe/Logging.java new file mode 100644 index 0000000..322a1b0 --- /dev/null +++ b/src/me/zhehe/Logging.java @@ -0,0 +1,19 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package me.zhehe; + +import java.util.logging.Level; +import org.bukkit.Bukkit; + +public class Logging { + public static void logInfo(String str) { + Bukkit.getLogger().log(Level.INFO, str); + } + public static void logError(String str) { + Bukkit.getLogger().log(Level.SEVERE, str); + } +} diff --git a/src/me/zhehe/Main.java b/src/me/zhehe/Main.java new file mode 100644 index 0000000..a337586 --- /dev/null +++ b/src/me/zhehe/Main.java @@ -0,0 +1,95 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package me.zhehe; + +import jaredbgreat.dldungeons.ConfigHandler; +import static jaredbgreat.dldungeons.builder.Builder.placeDungeon; +import jaredbgreat.dldungeons.themes.ThemeReader; +import jaredbgreat.dldungeons.themes.ThemeType; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Random; +import java.util.logging.Level; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.WorldCreator; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.world.WorldInitEvent; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; + +/** + * + * @author Zhehe + */ +public class Main extends JavaPlugin { + WorldConfig wc; + public static boolean enable; + + @Override + public void onEnable() { + enable = true; + ConfigHandler.configDir = this.getDataFolder(); + if(!ConfigHandler.configDir.exists()) ConfigHandler.configDir.mkdirs(); + ThemeReader.setConfigDir(this.getDataFolder()); + ConfigHandler.reload(); + + ConfigHandler.generateLists(); + ThemeReader.readThemes(); + ThemeType.SyncMobLists(); + + wc = new WorldConfig(this); + wc.load(); + + getServer().getPluginManager().registerEvents(new DLDWorldListener(), this); + } + + @Override + public void onDisable() { + enable = false; + } + + private class DLDWorldListener implements Listener { + @EventHandler(priority = EventPriority.LOW) + public void onWorldInit(WorldInitEvent event) { + if(!enable) return; + String world_name = event.getWorld().getName(); + if(wc.world.contains(world_name)) { + Logging.logInfo("Add DoomlikeDungeon Populator to world: " + world_name); + event.getWorld().getPopulators().add(new DungeonPopulator()); + } else { + Logging.logInfo("DoomlikeDungeon Populator is not used in " + world_name); + } + } + } + + @Override + public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) { + if(sender instanceof Player) { + Player player = (Player) sender; + if (!player.hasPermission("DoomlikeDungeonSpigot.command")) { + player.sendMessage("You don't have the permission required to use this plugin"); + return true; + } + } + if (command.getName().equalsIgnoreCase("doomlikedungeonspigot")) { + String worldName; + if(args.length == 0) { + sender.sendMessage("Wrong world name"); + return true; + } + worldName = args[0]; + wc.addWorld(worldName); + return true; + } + return false; + } +} diff --git a/src/me/zhehe/WorldConfig.java b/src/me/zhehe/WorldConfig.java new file mode 100644 index 0000000..f03158e --- /dev/null +++ b/src/me/zhehe/WorldConfig.java @@ -0,0 +1,64 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package me.zhehe; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.HashSet; +import java.util.Set; +import org.bukkit.plugin.java.JavaPlugin; + +public class WorldConfig { + public Set world = new HashSet<>(); + public transient File file; + public transient JavaPlugin plugin; + + public WorldConfig(JavaPlugin plugin) { + this.plugin = plugin; + file = new File(plugin.getDataFolder().toString() + File.separator + "world.json"); + } + + public void addWorld(String world_name) { + world.add(world_name); + save(); + } + + public void save() { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + String json = gson.toJson(this); + try(OutputStreamWriter oStreamWriter = new OutputStreamWriter(new FileOutputStream(file), "utf-8")) { + oStreamWriter.append(json); + oStreamWriter.close(); + } catch (IOException ex) { + Logging.logError("Error while saving world config file."); + } + } + + public void load() { + WorldConfig wc; + try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"))) { + StringBuilder sb = new StringBuilder(); + String line = reader.readLine(); + while (line != null) { + sb.append(line); + line = reader.readLine(); + } + wc = (new Gson()).fromJson(sb.toString(), WorldConfig.class); + } catch (Exception ex) { + Logging.logError("Error while loading world config file."); + return; + } + if(wc == null) return; + this.world = wc.world; + } +} diff --git a/src/plugin.yml b/src/plugin.yml new file mode 100644 index 0000000..e57ca34 --- /dev/null +++ b/src/plugin.yml @@ -0,0 +1,10 @@ +name: DoomlikeDungeonsSpigot +authors: [JaredBGreat,zhehe] +main: me.zhehe.Main +load: startup +api-version: 1.13 +version: 0.1 +commands: + doomlikedungeonspigot: + aliases: [dld] + permission: dld.admin