REWRITE INIT.
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
package fyi.tiko.battletower;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
/**
|
||||
* @author Tiko
|
||||
* @since 03.02.2026, 19:33
|
||||
*/
|
||||
public class BattleTowerPlugin extends JavaPlugin {
|
||||
private TowerSpawnManager spawnManager;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
saveDefaultConfig();
|
||||
|
||||
spawnManager = new TowerSpawnManager(this);
|
||||
|
||||
getServer().getPluginManager().registerEvents(
|
||||
new ChunkPopulateListener(spawnManager),
|
||||
this
|
||||
);
|
||||
|
||||
getLogger().info("Enabled BattleTowerPlugin");
|
||||
}
|
||||
|
||||
public TowerSpawnManager spawnManager() {
|
||||
return spawnManager;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package fyi.tiko.battletower;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkPopulateEvent;
|
||||
|
||||
/**
|
||||
* @author Tiko
|
||||
* @since 03.02.2026, 19:37
|
||||
*/
|
||||
public class ChunkPopulateListener implements Listener {
|
||||
private final TowerSpawnManager spawnManager;
|
||||
|
||||
public ChunkPopulateListener(final TowerSpawnManager spawnManager) {
|
||||
this.spawnManager = spawnManager;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void handleChunkPopulate(final ChunkPopulateEvent event) {
|
||||
spawnManager.attemptSpawn(event.getChunk());
|
||||
}
|
||||
}
|
||||
@@ -1,296 +0,0 @@
|
||||
package fyi.tiko.battletower;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Chest;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class OriginalTowerGenerator {
|
||||
|
||||
private int floor = 1;
|
||||
private int floorIterator = 0;
|
||||
private boolean topFloor;
|
||||
|
||||
public boolean generate(World world, Random random, int ix, int surfaceY, int kz) {
|
||||
|
||||
TowerType type = TowerType.COBBLE;
|
||||
|
||||
Material WALL = type.wall();
|
||||
Material FLOOR = type.floor();
|
||||
Material PILLAR = type.pillar();
|
||||
Material LIGHT = type.light();
|
||||
Material STAIRS = type.stairs();
|
||||
|
||||
int startY = surfaceY - 6;
|
||||
int maxHeight = 120;
|
||||
|
||||
floor = 1;
|
||||
|
||||
for (int builderHeight = startY; builderHeight < maxHeight; builderHeight += 7) {
|
||||
|
||||
topFloor = builderHeight + 7 >= maxHeight;
|
||||
|
||||
// ✅ FULL Forge Pattern Segment
|
||||
buildSegment(world, random, ix, builderHeight, kz,
|
||||
WALL, FLOOR, PILLAR, STAIRS);
|
||||
|
||||
// ✅ Spawner/Floor
|
||||
if (!topFloor) {
|
||||
placeSpawner(world, ix + 2, builderHeight + 6, kz + 2, random);
|
||||
placeSpawner(world, ix - 3, builderHeight + 6, kz + 2, random);
|
||||
}
|
||||
|
||||
// ✅ Chests
|
||||
placeChests(world, ix, builderHeight + 7, kz);
|
||||
|
||||
// ✅ Lights
|
||||
placeLights(world, ix, builderHeight, kz, LIGHT);
|
||||
|
||||
// ✅ Random Damage Holes (Original feel)
|
||||
randomDamage(world, random, ix, builderHeight + 5, kz, FLOOR);
|
||||
|
||||
floor++;
|
||||
}
|
||||
|
||||
// ✅ Boss Placeholder
|
||||
spawnBoss(world, ix, maxHeight, kz);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ========================================================= */
|
||||
|
||||
private void buildSegment(World world, Random random,
|
||||
int ix, int baseY, int kz,
|
||||
Material WALL,
|
||||
Material FLOOR,
|
||||
Material PILLAR,
|
||||
Material STAIRS) {
|
||||
|
||||
for (floorIterator = 0; floorIterator < 7; floorIterator++) {
|
||||
|
||||
if (floor == 1 && floorIterator < 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int xIt = -7; xIt < 7; xIt++) {
|
||||
for (int zIt = -7; zIt < 7; zIt++) {
|
||||
|
||||
int x = ix + xIt;
|
||||
int y = baseY + floorIterator;
|
||||
int z = kz + zIt;
|
||||
|
||||
// ==== EXACT FORGE SHAPE ====
|
||||
|
||||
if (zIt == -7) {
|
||||
if (xIt > -5 && xIt < 4) {
|
||||
wallPiece(world, x, y, z, WALL);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Main interior
|
||||
if (zIt != -6 && zIt != -5) {
|
||||
|
||||
// Window rows excluded
|
||||
if (zIt != -4 && zIt != -3 && zIt != 2 && zIt != 3) {
|
||||
|
||||
if (zIt > -3 && zIt < 2) {
|
||||
|
||||
if (xIt != -7 && xIt != 6) {
|
||||
|
||||
if (floorIterator == 5) {
|
||||
place(world, x, y, z, FLOOR);
|
||||
} else {
|
||||
place(world, x, y, z, Material.AIR);
|
||||
}
|
||||
|
||||
} else {
|
||||
wallPiece(world, x, y, z, WALL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else if (zIt == 4) {
|
||||
|
||||
if (xIt != -5 && xIt != 4) {
|
||||
if (floorIterator == 5) {
|
||||
place(world, x, y, z, FLOOR);
|
||||
} else {
|
||||
place(world, x, y, z, Material.AIR);
|
||||
}
|
||||
} else {
|
||||
wallPiece(world, x, y, z, WALL);
|
||||
}
|
||||
}
|
||||
|
||||
else if (zIt == 5) {
|
||||
|
||||
if (xIt != -4 && xIt != -3 && xIt != 2 && xIt != 3) {
|
||||
|
||||
if (xIt > -3 && xIt < 2) {
|
||||
if (floorIterator == 5) {
|
||||
place(world, x, y, z, FLOOR);
|
||||
} else {
|
||||
wallPiece(world, x, y, z, WALL);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
wallPiece(world, x, y, z, WALL);
|
||||
}
|
||||
}
|
||||
|
||||
else if (zIt == 6 && xIt > -3 && xIt < 2) {
|
||||
wallPiece(world, x, y, z, WALL);
|
||||
}
|
||||
}
|
||||
|
||||
// Window rows (-4,-3,2,3)
|
||||
else {
|
||||
|
||||
if (xIt != -6 && xIt != 5) {
|
||||
if (floorIterator == 5) {
|
||||
place(world, x, y, z, FLOOR);
|
||||
} else {
|
||||
place(world, x, y, z, Material.AIR);
|
||||
}
|
||||
} else {
|
||||
wallPiece(world, x, y, z, WALL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Stair gap
|
||||
else {
|
||||
|
||||
if (xIt == -5 || xIt == 4) {
|
||||
wallPiece(world, x, y, z, WALL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zIt == -6) {
|
||||
|
||||
int stairX = (floorIterator + 1) % 7 - 3;
|
||||
|
||||
if (xIt == stairX) {
|
||||
place(world, x, y, z, STAIRS);
|
||||
} else if (xIt > -5 && xIt < 4) {
|
||||
place(world, x, y, z, Material.AIR);
|
||||
}
|
||||
}
|
||||
|
||||
if (zIt == -5) {
|
||||
wallPiece(world, x, y, z, WALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================= */
|
||||
|
||||
private void wallPiece(World world, int x, int y, int z, Material wall) {
|
||||
|
||||
// Mossy pillar accents
|
||||
if ((x % 5 == 0) && (z % 5 == 0)) {
|
||||
place(world, x, y, z, Material.MOSSY_COBBLESTONE);
|
||||
} else {
|
||||
place(world, x, y, z, wall);
|
||||
}
|
||||
|
||||
// Fill base into ground
|
||||
if (floor == 1 && floorIterator == 4) {
|
||||
fillDown(world, x, y, z, wall);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillDown(World world, int x, int y, int z, Material mat) {
|
||||
for (int yy = y - 1; yy > 0; yy--) {
|
||||
Block b = world.getBlockAt(x, yy, z);
|
||||
if (b.getType().isSolid()) break;
|
||||
b.setType(mat, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================= */
|
||||
|
||||
private void randomDamage(World world, Random random,
|
||||
int ix, int y, int kz, Material floorMat) {
|
||||
|
||||
if (topFloor) return;
|
||||
|
||||
int holes = floor * 2;
|
||||
|
||||
for (int i = 0; i < holes; i++) {
|
||||
|
||||
int dx = random.nextInt(10) - 5;
|
||||
int dz = random.nextInt(10) - 5;
|
||||
|
||||
if (Math.abs(dx) < 2 && Math.abs(dz) < 2) continue;
|
||||
|
||||
Block b = world.getBlockAt(ix + dx, y, kz + dz);
|
||||
|
||||
if (b.getType() == floorMat) {
|
||||
b.setType(Material.AIR, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================= Spawner ================= */
|
||||
|
||||
private void placeSpawner(World world, int x, int y, int z, Random random) {
|
||||
|
||||
Block b = world.getBlockAt(x, y, z);
|
||||
b.setType(Material.SPAWNER);
|
||||
|
||||
CreatureSpawner spawner = (CreatureSpawner) b.getState();
|
||||
spawner.setSpawnedType(EntityType.ZOMBIE);
|
||||
spawner.update();
|
||||
}
|
||||
|
||||
/* ================= Loot ================= */
|
||||
|
||||
private void placeChests(World world, int ix, int y, int kz) {
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
|
||||
Block chestBlock = world.getBlockAt(ix - i, y, kz + 3);
|
||||
chestBlock.setType(Material.CHEST);
|
||||
|
||||
Chest chest = (Chest) chestBlock.getState();
|
||||
chest.getInventory().addItem(new ItemStack(Material.BREAD, 2));
|
||||
chest.getInventory().addItem(new ItemStack(Material.IRON_INGOT, 2));
|
||||
chest.update();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================= Lights ================= */
|
||||
|
||||
private void placeLights(World world, int ix, int y, int kz, Material light) {
|
||||
|
||||
place(world, ix + 3, y + 1, kz - 6, light);
|
||||
place(world, ix - 4, y + 1, kz - 6, light);
|
||||
}
|
||||
|
||||
/* ================= Boss ================= */
|
||||
|
||||
private void spawnBoss(World world, int ix, int y, int kz) {
|
||||
|
||||
world.spawnEntity(
|
||||
new Location(world, ix + 0.5, y + 2, kz + 0.5),
|
||||
EntityType.IRON_GOLEM
|
||||
);
|
||||
}
|
||||
|
||||
/* ========================================================= */
|
||||
|
||||
private void place(World world, int x, int y, int z, Material mat) {
|
||||
world.getBlockAt(x, y, z).setType(mat, false);
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package fyi.tiko.battletower;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
/**
|
||||
* @author Tiko
|
||||
* @since 03.02.2026, 19:41
|
||||
*/
|
||||
public class TowerGenerator {
|
||||
// 7 blöcke hoch pro etage
|
||||
private static final int FLOOR_HEIGHT = 7;
|
||||
|
||||
// tower radius in blöcken
|
||||
private static final int RADIUS = 7;
|
||||
|
||||
public boolean generate(final Location location) {
|
||||
final var world = location.getWorld();
|
||||
final var x = location.getBlockX();
|
||||
final var z = location.getBlockZ();
|
||||
|
||||
final var surfaceY = world.getHighestBlockYAt(x, z);
|
||||
|
||||
if (surfaceY < 60) {
|
||||
return false; // zu niedrig
|
||||
}
|
||||
|
||||
// original: tower soll leicht im boden starten
|
||||
final var startY = surfaceY - 6;
|
||||
|
||||
TowerType type = TowerType.COBBLE;
|
||||
|
||||
// 6 etagen hoch (zusammenbasteln hier)
|
||||
for (var floor = 0; floor < 6; floor++) {
|
||||
final var floorBaseY = startY + (floor * FLOOR_HEIGHT);
|
||||
buildFloor(world, x, floorBaseY, z, type);
|
||||
buildWalls(world, x, floorBaseY, z, type);
|
||||
}
|
||||
|
||||
// top zusammenbasteln hier
|
||||
buildTop(world, x, startY + (6 * FLOOR_HEIGHT), z, type);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void buildFloor(
|
||||
final World world,
|
||||
final int centerX,
|
||||
final int y,
|
||||
final int centerZ,
|
||||
final TowerType type
|
||||
) {
|
||||
for (var dx = -6; dx <= 6; dx++) {
|
||||
for (var dz = -6; dz <= 6; dz++) {
|
||||
// nur drinnen
|
||||
if (Math.abs(dx) < 6 && Math.abs(dz) < 6) {
|
||||
world.getBlockAt(centerX + dx, y, centerZ + dz).setType(type.floor());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildWalls(
|
||||
final World world,
|
||||
final int centerX,
|
||||
final int y,
|
||||
final int centerZ,
|
||||
final TowerType type
|
||||
) {
|
||||
for (var dy = 0; dy < FLOOR_HEIGHT; dy++) {
|
||||
final var currentY = y + dy;
|
||||
|
||||
for (int dx = -RADIUS; dx <= RADIUS; dx++) {
|
||||
for (int dz = -RADIUS; dz <= RADIUS; dz++) {
|
||||
// outer border = wall
|
||||
if (Math.abs(dx) == RADIUS || Math.abs(dz) == RADIUS) {
|
||||
world.getBlockAt(centerX + dx, currentY, centerZ + dz).setType(type.wall());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildTop(
|
||||
final World world,
|
||||
final int centerX,
|
||||
final int y,
|
||||
final int centerZ,
|
||||
final TowerType type
|
||||
) {
|
||||
for(var dx = -6; dx <= 6; dx++) {
|
||||
for(var dz = -6; dz <= 6; dz++) {
|
||||
world.getBlockAt(centerX + dx, y, centerZ + dz).setType(type.floor());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package fyi.tiko.battletower;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
/**
|
||||
* @author Tiko
|
||||
* @since 03.02.2026, 19:37
|
||||
*/
|
||||
public class TowerSpawnManager {
|
||||
private final JavaPlugin plugin;
|
||||
private final Random random = new Random();
|
||||
private final Set<Location> towerPositions = new HashSet<>();
|
||||
|
||||
public TowerSpawnManager(final JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void attemptSpawn(final Chunk chunk) {
|
||||
final var chance = plugin.getConfig().getInt("spawn.chance-per-chunk");
|
||||
|
||||
if (random.nextInt(chance) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var world = chunk.getWorld();
|
||||
final var x = chunk.getX() * 16 + 8;
|
||||
final var z = chunk.getZ() * 16 + 8;
|
||||
final var y = world.getHighestBlockYAt(x, z);
|
||||
|
||||
final var baseLocation = new Location(world, x, y, z);
|
||||
|
||||
if (!canSpawnAt(baseLocation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var generator = new OriginalTowerGenerator();
|
||||
final var success = generator.generate(world, random, x, y, z);
|
||||
|
||||
if (success) {
|
||||
towerPositions.add(baseLocation);
|
||||
plugin.getLogger().info("Spawned tower at " + baseLocation);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canSpawnAt(final Location location) {
|
||||
final var minDistance = plugin.getConfig().getInt("spawn.min-distance");
|
||||
|
||||
for (final var other : towerPositions) {
|
||||
if (other.getWorld() != location.getWorld()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (other.distanceSquared(location) < minDistance) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package fyi.tiko.battletower;
|
||||
|
||||
import org.bukkit.Material;
|
||||
|
||||
public enum TowerType {
|
||||
|
||||
COBBLE(
|
||||
Material.COBBLESTONE,
|
||||
Material.STONE_BRICKS,
|
||||
Material.MOSSY_COBBLESTONE, // ✅ Pillars
|
||||
Material.TORCH,
|
||||
Material.COBBLESTONE_STAIRS
|
||||
);
|
||||
|
||||
private final Material wall;
|
||||
private final Material floor;
|
||||
private final Material pillar;
|
||||
private final Material light;
|
||||
private final Material stairs;
|
||||
|
||||
TowerType(Material wall,
|
||||
Material floor,
|
||||
Material pillar,
|
||||
Material light,
|
||||
Material stairs) {
|
||||
|
||||
this.wall = wall;
|
||||
this.floor = floor;
|
||||
this.pillar = pillar;
|
||||
this.light = light;
|
||||
this.stairs = stairs;
|
||||
}
|
||||
|
||||
public Material wall() { return wall; }
|
||||
public Material floor() { return floor; }
|
||||
public Material pillar() { return pillar; }
|
||||
public Material light() { return light; }
|
||||
public Material stairs() { return stairs; }
|
||||
}
|
||||
54
src/main/java/fyi/tiko/battletowers/BattleTowersPlugin.java
Normal file
54
src/main/java/fyi/tiko/battletowers/BattleTowersPlugin.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package fyi.tiko.battletowers;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public final class BattleTowersPlugin extends JavaPlugin {
|
||||
|
||||
private static BattleTowersPlugin instance;
|
||||
|
||||
public static BattleTowersPlugin instance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private TowerLootManager lootManager;
|
||||
private NamespacedKey towerKey;
|
||||
|
||||
public NamespacedKey towerKey() {
|
||||
return towerKey;
|
||||
}
|
||||
|
||||
public TowerLootManager getLootManager() {
|
||||
return lootManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
|
||||
saveDefaultConfig();
|
||||
|
||||
towerKey = new NamespacedKey(this, "tower_location");
|
||||
lootManager = new TowerLootManager();
|
||||
|
||||
Bukkit.getWorlds().forEach(world -> {
|
||||
world.getPopulators().add(new TowerPopulator());
|
||||
});
|
||||
|
||||
getServer().getPluginManager().registerEvents(
|
||||
new TowerChestListener(), this
|
||||
);
|
||||
|
||||
getServer().getPluginManager().registerEvents(
|
||||
new TowerBossDeathListener(), this
|
||||
);
|
||||
|
||||
getLogger().info("BattleTowers enabled!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
getLogger().info("BattleTowers disabled!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package fyi.tiko.battletowers;
|
||||
|
||||
import org.bukkit.entity.IronGolem;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
|
||||
import static fyi.tiko.battletowers.BattleTowersPlugin.instance;
|
||||
|
||||
public class TowerBossDeathListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onBossDeath(EntityDeathEvent event) {
|
||||
|
||||
if (!(event.getEntity() instanceof IronGolem golem)) return;
|
||||
|
||||
var data = golem.getPersistentDataContainer().get(
|
||||
instance().towerKey(),
|
||||
org.bukkit.persistence.PersistentDataType.STRING
|
||||
);
|
||||
|
||||
if (data == null) return;
|
||||
|
||||
// Tower Collapse Start
|
||||
TowerDestroyer.startCollapse(golem.getLocation(), event.getEntity().getKiller());
|
||||
}
|
||||
}
|
||||
50
src/main/java/fyi/tiko/battletowers/TowerBossSpawner.java
Normal file
50
src/main/java/fyi/tiko/battletowers/TowerBossSpawner.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package fyi.tiko.battletowers;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.entity.IronGolem;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import static fyi.tiko.battletowers.BattleTowersPlugin.instance;
|
||||
|
||||
public class TowerBossSpawner {
|
||||
|
||||
public static void spawnDormantBoss(org.bukkit.World world,
|
||||
Location loc,
|
||||
int towerX, int towerY, int towerZ) {
|
||||
|
||||
IronGolem golem = world.spawn(loc, IronGolem.class);
|
||||
|
||||
// ===== Boss Stats like Forge =====
|
||||
golem.getAttribute(Attribute.MAX_HEALTH).setBaseValue(300.0);
|
||||
golem.setHealth(300.0);
|
||||
|
||||
golem.getAttribute(Attribute.ATTACK_DAMAGE).setBaseValue(12.0);
|
||||
golem.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(0.30);
|
||||
|
||||
golem.setCustomName("§6Battletower Guardian");
|
||||
golem.setCustomNameVisible(true);
|
||||
|
||||
// ===== Dormant Mode =====
|
||||
golem.setAI(false);
|
||||
|
||||
// Save tower coords inside entity
|
||||
golem.getPersistentDataContainer().set(
|
||||
instance().towerKey(),
|
||||
PersistentDataType.STRING,
|
||||
towerX + ";" + towerY + ";" + towerZ
|
||||
);
|
||||
}
|
||||
|
||||
public static void wakeUp(IronGolem golem) {
|
||||
|
||||
if (golem.hasAI()) return;
|
||||
|
||||
golem.setAI(true);
|
||||
golem.getWorld().playSound(
|
||||
golem.getLocation(),
|
||||
"entity.iron_golem.repair",
|
||||
3f, 0.6f
|
||||
);
|
||||
}
|
||||
}
|
||||
31
src/main/java/fyi/tiko/battletowers/TowerChestListener.java
Normal file
31
src/main/java/fyi/tiko/battletowers/TowerChestListener.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package fyi.tiko.battletowers;
|
||||
|
||||
import org.bukkit.entity.IronGolem;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
|
||||
public class TowerChestListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onChestOpen(InventoryOpenEvent event) {
|
||||
|
||||
if (!(event.getInventory().getHolder() instanceof org.bukkit.block.Chest)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var player = event.getPlayer();
|
||||
|
||||
// Search nearby golems
|
||||
for (var entity : player.getNearbyEntities(8, 8, 8)) {
|
||||
|
||||
if (entity instanceof IronGolem golem) {
|
||||
|
||||
if (!golem.hasAI()) {
|
||||
TowerBossSpawner.wakeUp(golem);
|
||||
golem.setTarget(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/main/java/fyi/tiko/battletowers/TowerDestroyer.java
Normal file
40
src/main/java/fyi/tiko/battletowers/TowerDestroyer.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package fyi.tiko.battletowers;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import static fyi.tiko.battletowers.BattleTowersPlugin.instance;
|
||||
|
||||
public class TowerDestroyer {
|
||||
|
||||
// TODO: die einzelnen floors werden nicht kaputt gemacht, sondern nur ganz oben + nachricht nur an spielern in reichweite von X blöcken...
|
||||
public static void startCollapse(Location center, Player killer) {
|
||||
|
||||
World world = center.getWorld();
|
||||
|
||||
Bukkit.broadcastMessage("§cA Battletower's Guardian has fallen! The Tower will collapse...");
|
||||
|
||||
new BukkitRunnable() {
|
||||
|
||||
int floor = 6;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if (floor <= 0) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
double y = center.getY() - (floor * 7);
|
||||
|
||||
world.createExplosion(center, 10f);
|
||||
floor--;
|
||||
}
|
||||
|
||||
}.runTaskTimer(instance(), 20 * 15, 20 * 5);
|
||||
}
|
||||
}
|
||||
528
src/main/java/fyi/tiko/battletowers/TowerGenerator.java
Normal file
528
src/main/java/fyi/tiko/battletowers/TowerGenerator.java
Normal file
@@ -0,0 +1,528 @@
|
||||
package fyi.tiko.battletowers;
|
||||
|
||||
import java.util.Random;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class TowerGenerator {
|
||||
|
||||
private static final int MAX_HOLE_DEPTH = 22;
|
||||
|
||||
private static final int[][] CANDIDATES = {
|
||||
{4, -5}, {4, 0}, {4, 5},
|
||||
{0, -5}, {0, 0}, {0, 5},
|
||||
{-4, -5}, {-4, 0}, {-4, 5}
|
||||
};
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
public void trySpawnTower(World world, Random random, int x, int z) {
|
||||
|
||||
int surfaceY = getSurfaceY(world, x, z);
|
||||
if (surfaceY < 60) {
|
||||
return;
|
||||
}
|
||||
|
||||
TowerType type = pickTowerType(world, random, x, z, surfaceY);
|
||||
if (type == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean underground = random.nextInt(100) < 15;
|
||||
|
||||
generate(world, x, surfaceY, z, type, underground);
|
||||
|
||||
Bukkit.getLogger().info("Spawned BattleTower at " + x + " " + z + " type=" + type);
|
||||
}
|
||||
|
||||
private TowerType pickTowerType(World world, Random random, int x, int z, int centerY) {
|
||||
|
||||
int water = 0, snow = 0, sand = 0, foliage = 0, other = 0;
|
||||
|
||||
for (int[] pair : CANDIDATES) {
|
||||
|
||||
int checkY = getSurfaceY(world, x + pair[0], z + pair[1]);
|
||||
Block block = world.getBlockAt(x + pair[0], checkY, z + pair[1]);
|
||||
|
||||
Material mat = block.getType();
|
||||
|
||||
if (mat == Material.SNOW || mat == Material.ICE) {
|
||||
snow++;
|
||||
} else if (mat == Material.SAND || mat == Material.SANDSTONE) {
|
||||
sand++;
|
||||
} else if (mat == Material.WATER) {
|
||||
water++;
|
||||
} else if (mat.name().contains("LEAVES") || mat.name().contains("LOG")) {
|
||||
foliage++;
|
||||
} else {
|
||||
other++;
|
||||
}
|
||||
|
||||
if (Math.abs(checkY - centerY) > MAX_HOLE_DEPTH) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (sand >= snow && sand >= water && sand >= foliage) {
|
||||
return TowerType.SANDSTONE;
|
||||
}
|
||||
if (snow >= water && snow >= foliage) {
|
||||
return TowerType.ICE;
|
||||
}
|
||||
if (water >= foliage) {
|
||||
return TowerType.MOSSY;
|
||||
}
|
||||
if (random.nextInt(10) == 0) {
|
||||
return TowerType.NETHER;
|
||||
}
|
||||
|
||||
return random.nextInt(5) == 0 ? TowerType.SMOOTH : TowerType.COBBLE;
|
||||
}
|
||||
|
||||
private int getSurfaceY(World world, int x, int z) {
|
||||
int y = world.getHighestBlockYAt(x, z);
|
||||
return y;
|
||||
}
|
||||
|
||||
// ✅ 1:1 Block Placement Core
|
||||
public void generate(World world, int ix, int jy, int kz, TowerType towerChosen, boolean underground) {
|
||||
|
||||
Material towerWallBlock = towerChosen.wall();
|
||||
Material towerLightBlock = towerChosen.light();
|
||||
Material towerFloorBlock = towerChosen.floor();
|
||||
Material towerStairBlock = towerChosen.stair();
|
||||
|
||||
int startingHeight = underground ? Math.max(jy - 70, 15) : jy - 6;
|
||||
int maximumHeight = underground ? jy + 7 : 120;
|
||||
|
||||
int floor = 1;
|
||||
|
||||
for (int builderHeight = startingHeight; builderHeight < maximumHeight; builderHeight += 7) {
|
||||
|
||||
boolean topFloor = builderHeight + 7 >= maximumHeight;
|
||||
|
||||
// ============================
|
||||
// BUILD FLOOR (7 BLOCK HIGH)
|
||||
// ============================
|
||||
for (int floorIterator = 0; floorIterator < 7; floorIterator++) {
|
||||
|
||||
// initial floor skip like Forge
|
||||
if (floor == 1 && floorIterator < 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int xIterator = -7; xIterator < 7; xIterator++) {
|
||||
for (int zIterator = -7; zIterator < 7; zIterator++) {
|
||||
|
||||
int x = ix + xIterator;
|
||||
int y = builderHeight + floorIterator;
|
||||
int z = kz + zIterator;
|
||||
|
||||
// ============================
|
||||
// ORIGINAL FORGE SHAPE LOGIC
|
||||
// ============================
|
||||
|
||||
// ---- Back wall row z=-7
|
||||
if (zIterator == -7) {
|
||||
if (xIterator > -5 && xIterator < 4) {
|
||||
buildWallPiece(world, x, y, z, towerWallBlock, floor, floorIterator);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Stairwell rows z=-6,-5
|
||||
if (zIterator == -6 || zIterator == -5) {
|
||||
|
||||
// Outer wall supports
|
||||
if (xIterator == -5 || xIterator == 4) {
|
||||
buildWallPiece(world, x, y, z, towerWallBlock, floor, floorIterator);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Stairwell special row z=-6
|
||||
if (zIterator == -6) {
|
||||
|
||||
// Stairwell column formula
|
||||
if (xIterator == (floorIterator + 1) % 7 - 3) {
|
||||
|
||||
if (!(underground && floor == 1)) {
|
||||
placeStair(world, x, y, z, towerStairBlock, floorIterator);
|
||||
}
|
||||
|
||||
// floorIterator=5 → platform extension
|
||||
if (floorIterator == 5) {
|
||||
setBlock(world, x - 7, y, z, towerFloorBlock);
|
||||
}
|
||||
|
||||
// Top ledge
|
||||
if (floorIterator == 6 && topFloor) {
|
||||
buildWallPiece(world, x, y, z, towerWallBlock, floor, floorIterator);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Tower inside air clearing
|
||||
if (xIterator < 4 && xIterator > -5) {
|
||||
setBlock(world, x, y, z, Material.AIR);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// row z=-5 outer bounds
|
||||
if (xIterator <= -5 || xIterator >= 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// under stairwell blocks
|
||||
if ((floorIterator != 0 && floorIterator != 6)
|
||||
|| (xIterator != -4 && xIterator != 3)) {
|
||||
|
||||
if (floorIterator == 5 && (xIterator == 3 || xIterator == -4)) {
|
||||
buildFloorPiece(world, x, y, z, towerFloorBlock);
|
||||
} else {
|
||||
buildWallPiece(world, x, y, z, towerWallBlock, floor, floorIterator);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Stairwell space
|
||||
setBlock(world, x, y, z, Material.AIR);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Side rows z=-4,-3,z=2,3
|
||||
if (zIterator == -4 || zIterator == -3 || zIterator == 2 || zIterator == 3) {
|
||||
|
||||
if (xIterator == -6 || xIterator == 5) {
|
||||
buildWallPiece(world, x, y, z, towerWallBlock, floor, floorIterator);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xIterator <= -6 || xIterator >= 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (floorIterator == 5) {
|
||||
buildFloorPiece(world, x, y, z, towerFloorBlock);
|
||||
continue;
|
||||
}
|
||||
|
||||
// NEU: SCHUTZ FÜR DIE KISTEN
|
||||
// Wenn wir im neuen Stockwerk ganz unten sind (floorIterator == 0),
|
||||
// dürfen wir an der Stelle x=0 und x=-1 bei z=3 die Luft nicht löschen,
|
||||
// weil dort die Kisten vom Stockwerk darunter stehen.
|
||||
if (floorIterator == 0 && zIterator == 3 && (xIterator == 0 || xIterator == -1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
setBlock(world, x, y, z, Material.AIR);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Middle rows z=-2,-1,0,1
|
||||
if (zIterator > -3 && zIterator < 2) {
|
||||
|
||||
if (xIterator == -7 || xIterator == 6) {
|
||||
|
||||
// Window logic
|
||||
if (floorIterator < 0 || floorIterator > 3
|
||||
|| underground
|
||||
|| (zIterator != -1 && zIterator != 0)) {
|
||||
buildWallPiece(world, x, y, z, towerWallBlock, floor, floorIterator);
|
||||
} else {
|
||||
setBlock(world, x, y, z, Material.AIR);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xIterator <= -7 || xIterator >= 6) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (floorIterator == 5) {
|
||||
buildFloorPiece(world, x, y, z, towerFloorBlock);
|
||||
} else {
|
||||
setBlock(world, x, y, z, Material.AIR);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Front row z=4
|
||||
if (zIterator == 4) {
|
||||
|
||||
if (xIterator == -5 || xIterator == 4) {
|
||||
buildWallPiece(world, x, y, z, towerWallBlock, floor, floorIterator);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xIterator <= -5 || xIterator >= 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (floorIterator == 5) {
|
||||
buildFloorPiece(world, x, y, z, towerFloorBlock);
|
||||
} else {
|
||||
setBlock(world, x, y, z, Material.AIR);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Row z=5 entrance ring
|
||||
if (zIterator == 5) {
|
||||
|
||||
if (xIterator == -4 || xIterator == -3 || xIterator == 2 || xIterator == 3) {
|
||||
buildWallPiece(world, x, y, z, towerWallBlock, floor, floorIterator);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xIterator <= -3 || xIterator >= 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (floorIterator == 5) {
|
||||
buildFloorPiece(world, x, y, z, towerFloorBlock);
|
||||
} else {
|
||||
buildWallPiece(world, x, y, z, towerWallBlock, floor, floorIterator);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Final row z=6
|
||||
if (zIterator == 6 && xIterator > -3 && xIterator < 2) {
|
||||
|
||||
buildWallPiece(world, x, y, z, towerWallBlock, floor, floorIterator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================
|
||||
// FLOOR LIGHTS (EXACT)
|
||||
// ============================
|
||||
setBlock(world, ix + 3, builderHeight + 2, kz - 6, towerLightBlock);
|
||||
setBlock(world, ix - 4, builderHeight + 2, kz - 6, towerLightBlock);
|
||||
|
||||
setBlock(world, ix + 1, builderHeight + 2, kz - 4, towerLightBlock);
|
||||
setBlock(world, ix - 2, builderHeight + 2, kz - 4, towerLightBlock);
|
||||
|
||||
// ============================
|
||||
// SPAWNERS OR BOSS
|
||||
// ============================
|
||||
|
||||
if ((!underground && topFloor) || (underground && floor == 1)) {
|
||||
|
||||
// ===== TOP FLOOR → BOSS GOLEM =====
|
||||
TowerBossSpawner.spawnDormantBoss(world,
|
||||
new Location(world, ix + 0.5, builderHeight + 6, kz + 0.5),
|
||||
ix, builderHeight + 6, kz);
|
||||
|
||||
} else {
|
||||
|
||||
// ===== NORMAL FLOOR → 2 SPAWNERS =====
|
||||
spawnMobSpawner(world, ix + 2, builderHeight + 6, kz + 2);
|
||||
spawnMobSpawner(world, ix - 3, builderHeight + 6, kz + 2);
|
||||
}
|
||||
|
||||
// ============================
|
||||
// ALWAYS PLACE FLOOR CHESTS
|
||||
// ============================
|
||||
// ============================
|
||||
// FIXED: PLACE FLOOR CHESTS
|
||||
// ============================
|
||||
|
||||
// Wir übergeben 'false' für topFloor, damit wir die Logik in der Methode selbst regeln können
|
||||
// oder nutzen einfach deine Logik weiter, aber rufen es sicher auf.
|
||||
placeFloorChests(world, ix, builderHeight, kz, floor, underground, topFloor);
|
||||
|
||||
|
||||
// ============================
|
||||
// CHEST PETAL (PODEST) - WIEDER EINGEFÜGT
|
||||
// ============================
|
||||
// Das Podest kommt auf Höhe +6 (einen Block über dem normalen Boden)
|
||||
setBlock(world, ix, builderHeight + 6, kz + 3, towerFloorBlock);
|
||||
setBlock(world, ix - 1, builderHeight + 6, kz + 3, towerFloorBlock);
|
||||
|
||||
floor++;
|
||||
}
|
||||
}
|
||||
|
||||
private void placeStair(World world, int x, int y, int z, Material stairMat, int floorIterator) {
|
||||
var stair = (org.bukkit.block.data.type.Stairs) stairMat.createBlockData();
|
||||
|
||||
// KORREKTUR:
|
||||
// Da deine Treppen sich in der `generate`-Methode nur entlang der X-Achse bewegen
|
||||
// (Z ist fest auf -6), ist es eine gerade Treppe.
|
||||
// Die X-Werte steigen an (-2, -1, 0...), also laufen wir nach OSTEN hoch.
|
||||
// Deshalb müssen alle Treppen stur nach Osten zeigen.
|
||||
|
||||
stair.setFacing(BlockFace.EAST);
|
||||
|
||||
stair.setHalf(org.bukkit.block.data.type.Stairs.Half.BOTTOM);
|
||||
|
||||
world.getBlockAt(x, y, z).setBlockData(stair, false);
|
||||
}
|
||||
|
||||
private void placeFloorChests(World world,
|
||||
int ix,
|
||||
int builderHeight,
|
||||
int kz,
|
||||
int floor,
|
||||
boolean underground,
|
||||
boolean topFloor
|
||||
) {
|
||||
TowerLootManager loot = BattleTowersPlugin.instance().getLootManager();
|
||||
TowerStageItemManager floorChestManager;
|
||||
|
||||
// 1. Loot-Logik (Original Forge Style)
|
||||
if (!underground) {
|
||||
floorChestManager = topFloor
|
||||
? loot.getManagerForFloor(10, random)
|
||||
: loot.getManagerForFloor(floor, random);
|
||||
} else {
|
||||
floorChestManager = (floor == 1)
|
||||
? loot.getManagerForFloor(10, random)
|
||||
: loot.getManagerForFloor(Math.abs(11 - floor), random);
|
||||
}
|
||||
|
||||
// 2. Koordinaten berechnen
|
||||
// cy = builderHeight + 7 stellt die Kisten auf das Podest (welches auf +6 ist)
|
||||
int cx = ix;
|
||||
int cy = builderHeight + 7;
|
||||
int cz = kz + 3;
|
||||
|
||||
// 3. Blöcke initial auf Kiste setzen
|
||||
world.getBlockAt(cx, cy, cz).setType(Material.CHEST, false);
|
||||
world.getBlockAt(cx - 1, cy, cz).setType(Material.CHEST, false);
|
||||
|
||||
// 4. Doppelkisten-Daten anwenden (Verbindung korrigieren)
|
||||
// Von vorne (Norden) betrachtet:
|
||||
// cx - 1 ist LINKS (Westen) -> Type.LEFT
|
||||
// cx ist RECHTS (Osten) -> Type.RIGHT
|
||||
|
||||
// Linke Hälfte (cx - 1)
|
||||
var leftData = (org.bukkit.block.data.type.Chest) Material.CHEST.createBlockData();
|
||||
leftData.setFacing(BlockFace.NORTH);
|
||||
leftData.setType(org.bukkit.block.data.type.Chest.Type.LEFT);
|
||||
|
||||
// Rechte Hälfte (cx)
|
||||
var rightData = (org.bukkit.block.data.type.Chest) Material.CHEST.createBlockData();
|
||||
rightData.setFacing(BlockFace.NORTH);
|
||||
rightData.setType(org.bukkit.block.data.type.Chest.Type.RIGHT);
|
||||
|
||||
// Daten auf die Blöcke schreiben
|
||||
world.getBlockAt(cx - 1, cy, cz).setBlockData(leftData, false);
|
||||
world.getBlockAt(cx, cy, cz).setBlockData(rightData, false);
|
||||
|
||||
// 5. Inventar füllen
|
||||
fillChest(world, cx, cy, cz, floorChestManager, underground);
|
||||
fillChest(world, cx - 1, cy, cz, floorChestManager, underground);
|
||||
}
|
||||
|
||||
private void fillChest(World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
TowerStageItemManager manager,
|
||||
boolean underground) {
|
||||
|
||||
var state = world.getBlockAt(x, y, z).getState();
|
||||
if (!(state instanceof org.bukkit.block.Chest chest)) return;
|
||||
|
||||
int attempts = BattleTowersPlugin.instance()
|
||||
.getConfig()
|
||||
.getInt("tower.itemGenerateAttemptsPerFloor");
|
||||
|
||||
if (underground) attempts *= 2;
|
||||
|
||||
for (int i = 0; i < attempts; i++) {
|
||||
|
||||
ItemStack item = manager.getStageItem(random);
|
||||
if (item == null) continue;
|
||||
|
||||
chest.getInventory().setItem(
|
||||
random.nextInt(chest.getInventory().getSize()),
|
||||
item
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void spawnMobSpawner(World world, int x, int y, int z) {
|
||||
|
||||
Block block = world.getBlockAt(x, y, z);
|
||||
block.setType(Material.SPAWNER, false);
|
||||
|
||||
if (block.getState() instanceof CreatureSpawner spawner) {
|
||||
|
||||
EntityType mob = switch (new Random().nextInt(4)) {
|
||||
case 0 -> EntityType.SKELETON;
|
||||
case 1 -> EntityType.ZOMBIE;
|
||||
case 2 -> EntityType.SPIDER;
|
||||
default -> EntityType.CAVE_SPIDER;
|
||||
};
|
||||
|
||||
spawner.setSpawnedType(mob);
|
||||
spawner.update(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void buildFloorPiece(World world, int x, int y, int z, Material floor) {
|
||||
setBlock(world, x, y, z, floor);
|
||||
}
|
||||
|
||||
private void buildWallPiece(World world, int x, int y, int z,
|
||||
Material wall, int floor, int floorIterator) {
|
||||
|
||||
setBlock(world, x, y, z, wall);
|
||||
|
||||
// Forge: fill base downwards
|
||||
if (floor == 1 && floorIterator == 4) {
|
||||
fillTowerBaseToGround(world, x, y, z, wall);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillTowerBaseToGround(World world, int x, int y, int z, Material wall) {
|
||||
|
||||
int yy = y - 1;
|
||||
|
||||
while (yy > 0) {
|
||||
|
||||
Material below = world.getBlockAt(x, yy, z).getType();
|
||||
|
||||
if (isBuildableBlock(below)) {
|
||||
break;
|
||||
}
|
||||
|
||||
setBlock(world, x, yy, z, wall);
|
||||
yy--;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBuildableBlock(Material mat) {
|
||||
return mat == Material.STONE
|
||||
|| mat == Material.GRASS_BLOCK
|
||||
|| mat == Material.DIRT
|
||||
|| mat == Material.SAND
|
||||
|| mat == Material.SANDSTONE
|
||||
|| mat == Material.GRAVEL;
|
||||
}
|
||||
|
||||
private void setBlock(World world, int x, int y, int z, Material mat) {
|
||||
world.getBlockAt(x, y, z).setType(mat, false);
|
||||
}
|
||||
}
|
||||
36
src/main/java/fyi/tiko/battletowers/TowerLootManager.java
Normal file
36
src/main/java/fyi/tiko/battletowers/TowerLootManager.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package fyi.tiko.battletowers;
|
||||
|
||||
import fyi.tiko.battletowers.BattleTowersPlugin;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class TowerLootManager {
|
||||
|
||||
private final TowerStageItemManager[] floors = new TowerStageItemManager[10];
|
||||
|
||||
public TowerLootManager() {
|
||||
|
||||
var cfg = BattleTowersPlugin.instance().getConfig();
|
||||
|
||||
floors[0] = new TowerStageItemManager(cfg.getString("loot.floor1"));
|
||||
floors[1] = new TowerStageItemManager(cfg.getString("loot.floor2"));
|
||||
floors[2] = new TowerStageItemManager(cfg.getString("loot.floor3"));
|
||||
floors[3] = new TowerStageItemManager(cfg.getString("loot.floor4"));
|
||||
floors[4] = new TowerStageItemManager(cfg.getString("loot.floor5"));
|
||||
floors[5] = new TowerStageItemManager(cfg.getString("loot.floor6"));
|
||||
floors[6] = new TowerStageItemManager(cfg.getString("loot.floor7"));
|
||||
floors[7] = new TowerStageItemManager(cfg.getString("loot.floor8"));
|
||||
floors[8] = new TowerStageItemManager(cfg.getString("loot.floor9"));
|
||||
floors[9] = new TowerStageItemManager(cfg.getString("loot.top"));
|
||||
}
|
||||
|
||||
public TowerStageItemManager getManagerForFloor(int floor, Random rand) {
|
||||
|
||||
floor--; // Forge subtract
|
||||
|
||||
if (floor < 0) floor = 0;
|
||||
if (floor >= floors.length) floor = floors.length - 1;
|
||||
|
||||
return new TowerStageItemManager(floors[floor]);
|
||||
}
|
||||
}
|
||||
24
src/main/java/fyi/tiko/battletowers/TowerPopulator.java
Normal file
24
src/main/java/fyi/tiko/battletowers/TowerPopulator.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package fyi.tiko.battletowers;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class TowerPopulator extends BlockPopulator {
|
||||
|
||||
private final TowerGenerator generator = new TowerGenerator();
|
||||
|
||||
@Override
|
||||
public void populate(World world, Random random, Chunk chunk) {
|
||||
|
||||
// Chance pro Chunk (erstmal test)
|
||||
if (random.nextInt(250) != 0) return;
|
||||
|
||||
int x = chunk.getX() * 16 + 8;
|
||||
int z = chunk.getZ() * 16 + 8;
|
||||
|
||||
generator.trySpawnTower(world, random, x, z);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package fyi.tiko.battletowers;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class TowerStageItemManager {
|
||||
|
||||
private final List<LootEntry> entries = new ArrayList<>();
|
||||
private int curIndex = 0;
|
||||
|
||||
public TowerStageItemManager(String configString) {
|
||||
|
||||
String[] elements = configString.split(";");
|
||||
|
||||
for (String element : elements) {
|
||||
|
||||
String[] data = element.trim().split("-");
|
||||
|
||||
if (data.length < 5) {
|
||||
System.err.println("Invalid loot entry: " + element);
|
||||
continue;
|
||||
}
|
||||
|
||||
Material mat = Material.matchMaterial(data[0].toUpperCase());
|
||||
if (mat == null) {
|
||||
System.err.println("Unknown material: " + data[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
int damage = Integer.parseInt(data[1]); // ignored in modern MC
|
||||
int chance = Integer.parseInt(data[2]);
|
||||
int min = Integer.parseInt(data[3]);
|
||||
int max = Integer.parseInt(data[4]);
|
||||
|
||||
entries.add(new LootEntry(mat, chance, min, max));
|
||||
}
|
||||
}
|
||||
|
||||
public TowerStageItemManager(TowerStageItemManager copy) {
|
||||
entries.addAll(copy.entries);
|
||||
}
|
||||
|
||||
public boolean floorHasItemsLeft() {
|
||||
return curIndex < entries.size();
|
||||
}
|
||||
|
||||
public ItemStack getStageItem(Random rand) {
|
||||
|
||||
if (!floorHasItemsLeft()) return null;
|
||||
|
||||
LootEntry entry = entries.get(curIndex);
|
||||
|
||||
ItemStack result = null;
|
||||
|
||||
if (rand.nextInt(100) < entry.chance) {
|
||||
int amount = entry.min + rand.nextInt(entry.max - entry.min + 1);
|
||||
result = new ItemStack(entry.material, amount);
|
||||
}
|
||||
|
||||
curIndex++;
|
||||
return result;
|
||||
}
|
||||
|
||||
private record LootEntry(Material material, int chance, int min, int max) {}
|
||||
}
|
||||
30
src/main/java/fyi/tiko/battletowers/TowerType.java
Normal file
30
src/main/java/fyi/tiko/battletowers/TowerType.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package fyi.tiko.battletowers;
|
||||
|
||||
import org.bukkit.Material;
|
||||
|
||||
public enum TowerType {
|
||||
|
||||
COBBLE(Material.COBBLESTONE, Material.STONE_BRICKS, Material.TORCH, Material.STONE_STAIRS),
|
||||
MOSSY(Material.MOSSY_COBBLESTONE, Material.STONE_BRICKS, Material.TORCH, Material.STONE_STAIRS),
|
||||
SANDSTONE(Material.SANDSTONE, Material.CUT_SANDSTONE, Material.TORCH, Material.SANDSTONE_STAIRS),
|
||||
ICE(Material.ICE, Material.CLAY, Material.AIR, Material.OAK_STAIRS),
|
||||
SMOOTH(Material.STONE, Material.SMOOTH_STONE, Material.TORCH, Material.STONE_STAIRS),
|
||||
NETHER(Material.NETHERRACK, Material.SOUL_SAND, Material.GLOWSTONE, Material.NETHER_BRICK_STAIRS);
|
||||
|
||||
private final Material wall;
|
||||
private final Material floor;
|
||||
private final Material light;
|
||||
private final Material stair;
|
||||
|
||||
TowerType(Material wall, Material floor, Material light, Material stair) {
|
||||
this.wall = wall;
|
||||
this.floor = floor;
|
||||
this.light = light;
|
||||
this.stair = stair;
|
||||
}
|
||||
|
||||
public Material wall() { return wall; }
|
||||
public Material floor() { return floor; }
|
||||
public Material light() { return light; }
|
||||
public Material stair() { return stair; }
|
||||
}
|
||||
@@ -3,4 +3,19 @@ spawn:
|
||||
min-distance: 196 # wie original
|
||||
max-y-difference: 22
|
||||
|
||||
debug: true
|
||||
debug: true
|
||||
|
||||
tower:
|
||||
itemGenerateAttemptsPerFloor: 7
|
||||
|
||||
loot:
|
||||
floor1: "stick-0-75-5-6;wheat_seeds-0-75-3-5;oak_planks-0-75-5-6;sugar_cane-0-75-3-5"
|
||||
floor2: "stone_pickaxe-0-50-1-1;stone_axe-0-50-1-1;torch-0-80-3-3;stone_button-0-50-2-2"
|
||||
floor3: "bowl-0-75-2-4;coal-0-90-4-4;string-0-80-5-5;white_wool-0-75-2-2"
|
||||
floor4: "glass-0-75-3-3;feather-0-75-4-4;bread-0-75-2-2;apple-0-75-2-2"
|
||||
floor5: "brown_mushroom-0-75-2-2;red_mushroom-0-75-2-2;oak_sapling-0-90-3-3;wheat-0-75-4-4"
|
||||
floor6: "oak_sign-0-50-1-2;fishing_rod-0-75-1-1;pumpkin_seeds-0-60-2-2;melon_seeds-0-60-3-3"
|
||||
floor7: "iron_sword-0-60-1-1;gunpowder-0-75-3-3;leather-0-75-4-4;cod-0-75-3-3;blue_dye-0-60-1-2"
|
||||
floor8: "chainmail_helmet-0-40-1-1;chainmail_chestplate-0-40-1-1;chainmail_leggings-0-40-1-1;chainmail_boots-0-40-1-1"
|
||||
floor9: "bookshelf-0-70-1-3;redstone_lamp-0-60-2-2;lily_pad-0-75-3-3;brewing_stand-0-50-1-1"
|
||||
top: "ender_pearl-0-50-2-2;diamond-0-70-2-2;redstone-0-75-5-5;gold_ingot-0-90-8-8"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: battle-towers-revamped
|
||||
version: 0.0.1
|
||||
main: fyi.tiko.battletower.BattleTowerPlugin
|
||||
main: fyi.tiko.battletowers.BattleTowersPlugin
|
||||
api-version: 1.21
|
||||
author: tiko
|
||||
description: A revamped version of the old battle towers mod for the old modpack "hexxit". Ported from 1.5.2 to paper 1.21
|
||||
|
||||
Reference in New Issue
Block a user