From e77879c65734be2cdb391c185416b76cc56ae912 Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 13 Apr 2025 18:35:50 +0200 Subject: [PATCH] added tower value calculation and delete tower mechanic --- .../types/towerdefense/EnemyFactory.java | 6 +-- .../types/towerdefense/Towerdefense.java | 24 +++++---- .../types/towerdefense/TowerdefenseRoom.java | 49 ++++++++++++++++--- .../types/towerdefense/towers/BlazeTower.java | 2 +- .../towerdefense/towers/SkeletonTower.java | 2 +- .../types/towerdefense/towers/Tower.java | 11 +++++ .../towerdefense/towers/ZombieTower.java | 2 +- 7 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/EnemyFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/EnemyFactory.java index 02b23a0..a869dd6 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/EnemyFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/EnemyFactory.java @@ -8,15 +8,15 @@ record EnemyFactory(EntityType entityType, float health, double speed) { /** * Factory for a tower defense enemy. * @param entityType type of enemy - * @param health base health, between 0 and 1024 - * @param speed walk speed of enemy + * @param health base health (between 0 and 1024, default 10) + * @param speed walk speed (default 0.1) */ public EnemyFactory { if(health > 1024 || health <= 0) throw new IllegalArgumentException("Enemy health has to be between 0 and 1024"); } public EnemyFactory(EntityType entityType) { - this(entityType, 20, 0.3); + this(entityType, 10, 0.1); } public EntityCreature buildEntity() { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/Towerdefense.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/Towerdefense.java index d5d9237..48b4422 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/Towerdefense.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/Towerdefense.java @@ -31,9 +31,9 @@ public class Towerdefense extends StatelessGame { Material.BLAZE_SPAWN_EGG, BlazeTower.class ); private final Map, Integer> prices = Map.of( - ZombieTower.class, 5, + ZombieTower.class, 14, SkeletonTower.class, 10, - BlazeTower.class, 15 + BlazeTower.class, 30 ); private static final int pathLength = 10; @@ -45,6 +45,18 @@ public class Towerdefense extends StatelessGame { this.generateMaze(); } + @Override + protected void onStart() { + this.getPlayers().forEach(player -> { + TowerdefenseRoom newRoom = new TowerdefenseRoom(player, this); + this.instances.add(newRoom); + player.setInstance(newRoom); + newRoom.startWave(List.of( + new GroupFactory(new EnemyFactory(EntityType.VILLAGER), 1, 800) + )); + }); + } + private void generateMaze() { Pos position = new Pos(0, 0, 0); this.addMazePosition(position, Block.GREEN_WOOL); @@ -90,14 +102,6 @@ public class Towerdefense extends StatelessGame { @Override protected boolean onPlayerJoin(Player p) { - TowerdefenseRoom newRoom = new TowerdefenseRoom(p, this); - this.instances.add(newRoom); - p.setInstance(newRoom); - newRoom.startWave(List.of( - new GroupFactory(new EnemyFactory(EntityType.VILLAGER, 20, 0.1), 5, 800), - new GroupFactory(new EnemyFactory(EntityType.BEE, 10, 1), 3, 400), - new GroupFactory(new EnemyFactory(EntityType.SNIFFER, 1000, 0.02), 1, 0) - )); return false; } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/TowerdefenseRoom.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/TowerdefenseRoom.java index 966d759..c96dda8 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/TowerdefenseRoom.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/TowerdefenseRoom.java @@ -5,6 +5,8 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.gene import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers.Tower; import eu.mhsl.minenet.minigames.util.BatchUtil; import eu.mhsl.minenet.minigames.util.CommonEventHandles; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextColor; import net.minestom.server.MinecraftServer; import net.minestom.server.collision.Aerodynamics; import net.minestom.server.coordinate.Point; @@ -23,6 +25,7 @@ import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.block.Block; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.timer.TaskSchedule; import org.jetbrains.annotations.Nullable; import java.time.Duration; @@ -38,7 +41,7 @@ public class TowerdefenseRoom extends InstanceContainer { private final List enemies = new ArrayList<>(); private final List towers = new ArrayList<>(); private final Entity cursor; - private int money = 1000; + private int money = 0; public TowerdefenseRoom(Player player, Towerdefense game) { super(UUID.randomUUID(), Dimension.OVERWORLD.key); @@ -51,7 +54,8 @@ public class TowerdefenseRoom extends InstanceContainer { this.player.getAttribute(Attribute.BLOCK_INTERACTION_RANGE).setBaseValue(reach); this.player.getAttribute(Attribute.ENTITY_INTERACTION_RANGE).setBaseValue(reach); - this.player.getInventory().addItemStack(ItemStack.of(Material.SPECTRAL_ARROW)); + this.player.getInventory().addItemStack(ItemStack.of(Material.SPECTRAL_ARROW).withCustomName(Component.text("Schießen", TextColor.color(255, 180, 0)))); + this.player.getInventory().addItemStack(ItemStack.of(Material.BARRIER).withCustomName(Component.text("Löschen", TextColor.color(255,0,0)))); this.game.getAvailableTowers().keySet().forEach(material -> this.player.getInventory().addItemStack(ItemStack.of(material))); this.setGenerator(new MazeGenerator()); @@ -61,6 +65,16 @@ public class TowerdefenseRoom extends InstanceContainer { this.cursor.setInstance(this); this.cursor.setBoundingBox(0,0,0); + MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of( + new GroupFactory(new EnemyFactory(EntityType.VILLAGER), 2, 800) + )), TaskSchedule.seconds(20), TaskSchedule.stop()); + MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of( + new GroupFactory(new EnemyFactory(EntityType.VILLAGER), 4, 800) + )), TaskSchedule.seconds(50), TaskSchedule.stop()); + MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of( + new GroupFactory(new EnemyFactory(EntityType.VILLAGER), 6, 800) + )), TaskSchedule.seconds(90), TaskSchedule.stop()); + this.eventNode() .addListener(EntityDeathEvent.class, event -> { if(!(event.getEntity() instanceof EntityCreature enemy)) return; @@ -77,10 +91,15 @@ public class TowerdefenseRoom extends InstanceContainer { } private void useItem() { - if(this.player.getItemInMainHand().material().equals(Material.SPECTRAL_ARROW)) { + Material itemInHand = this.player.getItemInMainHand().material(); + if(itemInHand.equals(Material.SPECTRAL_ARROW)) { this.playerAttack(); return; } + if(itemInHand.equals(Material.BARRIER)) { + this.removeTower(); + return; + } this.placeTower(); } @@ -127,13 +146,25 @@ public class TowerdefenseRoom extends InstanceContainer { this.setBlock(this.cursor.getPosition().sub(0, 0.5, 0), Block.BLUE_WOOL); tower.setInstance(this, this.cursor.getPosition()); this.towers.add(tower); + this.addMoney(-this.game.getPrices().get(tower.getClass())); } catch (Exception ignored) { } } + private void removeTower() { + Entity entity = this.player.getLineOfSightEntity(reach, entity1 -> true); + if(!(entity instanceof Tower tower)) return; + if(!this.towers.contains(tower)) return; + + this.setBlock(tower.getPosition().sub(0, 0.5, 0), Block.BLACK_WOOL); + this.addMoney(tower.getSellingPrice(this.game.getPrices().get(tower.getClass()))); + this.towers.remove(tower); + tower.remove(); + } + private void setCursorPosition(PlayerTickEvent event) { Point newPosition = this.player.getTargetBlockPosition(reach); - if(newPosition == null) return; + if(newPosition == null) newPosition = this.cursor.getPosition().withY(-2); newPosition = newPosition.add(0.5,1,0.5); this.cursor.teleport(new Pos(newPosition)); this.cursor.setInvisible(!(this.canPlaceTower((Material) null) && this.game.getAvailableTowers().containsKey(this.player.getItemInMainHand().material()))); @@ -147,7 +178,7 @@ public class TowerdefenseRoom extends InstanceContainer { private boolean canPlaceTower(@Nullable Class towerClass) { boolean blockAllowed = this.getBlock(this.cursor.getPosition().sub(0, 1, 0)).equals(Block.BLACK_WOOL); if(towerClass == null) return blockAllowed; - boolean enoughMoney = this.money > this.game.getPrices().get(towerClass); + boolean enoughMoney = this.money >= this.game.getPrices().get(towerClass); return blockAllowed && enoughMoney; } @@ -165,7 +196,13 @@ public class TowerdefenseRoom extends InstanceContainer { if(positionIndex == this.game.getMazePath().size()-1) { this.enemies.remove(enemy); enemy.remove(); - this.player.damage(DamageType.PLAYER_ATTACK, enemy.getHealth()/10); + float damage = (float) Math.ceil(enemy.getHealth()/10); + if(this.player.getHealth() - damage <= 0) { + this.player.setInstance(this.game); + this.game.getScore().insertResult(this.player); + return; + } + this.player.damage(DamageType.PLAYER_ATTACK, damage); return; } enemy.getNavigator().setPathTo(this.game.getMazePath().get(positionIndex+1), 0.6, () -> this.changeEnemyGoal(enemy, positionIndex+1)); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/BlazeTower.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/BlazeTower.java index f711661..1d32d1c 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/BlazeTower.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/BlazeTower.java @@ -5,7 +5,7 @@ import net.minestom.server.entity.EntityType; public class BlazeTower extends ShootingTower { public BlazeTower() { - super(EntityType.BLAZE, 1, 1, 20); + super(EntityType.BLAZE, 2, 2, 15); } @Override diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/SkeletonTower.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/SkeletonTower.java index 7c8f9b4..d1c10e9 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/SkeletonTower.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/SkeletonTower.java @@ -7,7 +7,7 @@ import net.minestom.server.item.Material; public class SkeletonTower extends ShootingTower { public SkeletonTower() { - super(EntityType.SKELETON, 1, 3, 15); + super(EntityType.SKELETON, 1, 2, 10); this.setItemInMainHand(ItemStack.of(Material.BOW)); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/Tower.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/Tower.java index 002af1d..7edab7f 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/Tower.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/Tower.java @@ -43,13 +43,16 @@ public abstract class Tower extends EntityCreature { private Priority priority = Priority.FIRST; protected float damage; protected int range; + protected double attacksPerSecond; protected TaskSchedule attackDelay; private final Task attackTask; + private float sellingPriceMultiplier = 1; public Tower(@NotNull EntityType entityType, int damage, double attacksPerSecond, int range) { super(entityType); this.damage = (float) damage / damageDivider; this.range = range; + this.attacksPerSecond = attacksPerSecond; this.attackDelay = TaskSchedule.millis((long) (1000/attacksPerSecond)); this.attackTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> { EntityCreature nextEnemy = this.getNextEnemy(); @@ -104,6 +107,14 @@ public abstract class Tower extends EntityCreature { return (TowerdefenseRoom) this.getInstance(); } + public int getSellingPrice(int buyPrice) { + return (int) (this.sellingPriceMultiplier * buyPrice); + } + + public double getValue() { + return this.damage * this.attacksPerSecond * this.range * 2; + } + protected void causeDamage(EntityCreature enemy) { this.causeDamage(enemy, this.damage); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/ZombieTower.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/ZombieTower.java index a9c6262..894df57 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/ZombieTower.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/towerdefense/towers/ZombieTower.java @@ -7,7 +7,7 @@ import net.minestom.server.item.Material; public class ZombieTower extends Tower { public ZombieTower() { - super(EntityType.ZOMBIE, 2, 0.7, 4); + super(EntityType.ZOMBIE, 7, 1, 4); this.setItemInMainHand(ItemStack.of(Material.IRON_SWORD)); }