added own cursor class

This commit is contained in:
Lars Neuhaus 2025-04-13 23:28:46 +02:00
parent e77879c657
commit 5e5f36153e
3 changed files with 110 additions and 30 deletions

View File

@ -0,0 +1,58 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.block.Block;
import org.jetbrains.annotations.Nullable;
public class Cursor extends Entity {
private boolean cursorActive = false;
private final int reach;
public Cursor(int reach) {
super(EntityType.ARMOR_STAND);
this.setBoundingBox(0,0,0);
this.reach = reach;
}
public void updateCursorPosition(Player player) {
Point targetPosition = player.getTargetBlockPosition(this.reach);
this.moveCursorTo(targetPosition);
}
private void moveCursorTo(@Nullable Point newTargetBlockPosition) {
this.setCursorEnabled(true);
if(newTargetBlockPosition == null) {
this.setCursorEnabled(false);
return;
}
if(!this.getInstance().getBlock(newTargetBlockPosition).equals(Block.BLACK_WOOL)) this.setCursorEnabled(false);
if(!this.getInstance().getGame().getAvailableTowers().containsKey(this.getInstance().getPlayer().getItemInMainHand().material())) this.setCursorEnabled(false);
this.teleport(new Pos(newTargetBlockPosition.add(0.5,1,0.5)));
}
private void setCursorEnabled(boolean enabled) {
this.cursorActive = enabled;
this.setInvisible(!enabled);
}
@Override
public TowerdefenseRoom getInstance() {
return (TowerdefenseRoom) super.getInstance();
}
public boolean isCursorActive() {
return this.cursorActive;
}
public Block getTargetBlock() {
return this.getInstance().getBlock(this.getTargetBlockPosition());
}
public Pos getTargetBlockPosition() {
return this.getPosition().sub(0, 0.5, 0);
}
}

View File

@ -31,9 +31,9 @@ public class Towerdefense extends StatelessGame {
Material.BLAZE_SPAWN_EGG, BlazeTower.class Material.BLAZE_SPAWN_EGG, BlazeTower.class
); );
private final Map<Class<? extends Tower>, Integer> prices = Map.of( private final Map<Class<? extends Tower>, Integer> prices = Map.of(
ZombieTower.class, 14, ZombieTower.class, 4,
SkeletonTower.class, 10, SkeletonTower.class, 3,
BlazeTower.class, 30 BlazeTower.class, 8
); );
private static final int pathLength = 10; private static final int pathLength = 10;
@ -45,6 +45,13 @@ public class Towerdefense extends StatelessGame {
this.generateMaze(); this.generateMaze();
} }
@Override
protected void checkAbandoned() {
this.scheduleNextTick((instance) -> {
if(this.instances.stream().allMatch(room -> room.getPlayers().isEmpty()) && this.getPlayers().isEmpty()) this.unload();
});
}
@Override @Override
protected void onStart() { protected void onStart() {
this.getPlayers().forEach(player -> { this.getPlayers().forEach(player -> {
@ -52,7 +59,7 @@ public class Towerdefense extends StatelessGame {
this.instances.add(newRoom); this.instances.add(newRoom);
player.setInstance(newRoom); player.setInstance(newRoom);
newRoom.startWave(List.of( newRoom.startWave(List.of(
new GroupFactory(new EnemyFactory(EntityType.VILLAGER), 1, 800) new GroupFactory(new EnemyFactory(EntityType.VILLAGER, 2, 0.1), 1, 800)
)); ));
}); });
} }

View File

@ -9,8 +9,6 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextColor;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.collision.Aerodynamics; import net.minestom.server.collision.Aerodynamics;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.*; import net.minestom.server.entity.*;
import net.minestom.server.entity.attribute.Attribute; import net.minestom.server.entity.attribute.Attribute;
@ -40,7 +38,7 @@ public class TowerdefenseRoom extends InstanceContainer {
private final Towerdefense game; private final Towerdefense game;
private final List<EntityCreature> enemies = new ArrayList<>(); private final List<EntityCreature> enemies = new ArrayList<>();
private final List<Tower> towers = new ArrayList<>(); private final List<Tower> towers = new ArrayList<>();
private final Entity cursor; private final Cursor cursor;
private int money = 0; private int money = 0;
public TowerdefenseRoom(Player player, Towerdefense game) { public TowerdefenseRoom(Player player, Towerdefense game) {
@ -56,31 +54,37 @@ public class TowerdefenseRoom extends InstanceContainer {
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.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.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.game.getAvailableTowers().forEach((material, tower) -> {
int price = this.game.getPrices().get(tower);
this.player.getInventory().addItemStack(ItemStack.of(material).withMaxStackSize(price).withAmount(price));
});
this.setGenerator(new MazeGenerator()); this.setGenerator(new MazeGenerator());
BatchUtil.loadAndApplyBatch(this.game.getMazeBatch(), this, () -> {}); BatchUtil.loadAndApplyBatch(this.game.getMazeBatch(), this, () -> {});
this.cursor = new Entity(EntityType.ARMOR_STAND); this.cursor = new Cursor(reach);
this.cursor.setInstance(this); this.cursor.setInstance(this);
this.cursor.setBoundingBox(0,0,0); this.cursor.setBoundingBox(0,0,0);
MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of( MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of(
new GroupFactory(new EnemyFactory(EntityType.VILLAGER), 2, 800) new GroupFactory(new EnemyFactory(EntityType.VILLAGER, 3, 0.1), 1, 800)
)), TaskSchedule.seconds(20), TaskSchedule.stop()); )), TaskSchedule.seconds(20), TaskSchedule.stop());
MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of( MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of(
new GroupFactory(new EnemyFactory(EntityType.VILLAGER), 4, 800) new GroupFactory(new EnemyFactory(EntityType.VILLAGER, 3, 0.1), 2, 800)
)), TaskSchedule.seconds(50), TaskSchedule.stop()); )), TaskSchedule.seconds(50), TaskSchedule.stop());
MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of( MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of(
new GroupFactory(new EnemyFactory(EntityType.VILLAGER), 6, 800) new GroupFactory(new EnemyFactory(EntityType.VILLAGER), 2, 800)
)), TaskSchedule.seconds(90), TaskSchedule.stop()); )), TaskSchedule.seconds(90), TaskSchedule.stop());
MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of(
new GroupFactory(new EnemyFactory(EntityType.EGG), 200, 800)
)), TaskSchedule.seconds(150), TaskSchedule.stop());
this.eventNode() this.eventNode()
.addListener(EntityDeathEvent.class, event -> { .addListener(EntityDeathEvent.class, event -> {
if(!(event.getEntity() instanceof EntityCreature enemy)) return; if(!(event.getEntity() instanceof EntityCreature enemy)) return;
this.enemies.remove(enemy); this.enemies.remove(enemy);
}) })
.addListener(PlayerTickEvent.class, this::setCursorPosition) .addListener(PlayerTickEvent.class, event -> this.cursor.updateCursorPosition(this.player))
.addListener(PlayerUseItemEvent.class, event -> this.useItem()) .addListener(PlayerUseItemEvent.class, event -> this.useItem())
.addListener(PlayerUseItemOnBlockEvent.class, event -> this.useItem()) .addListener(PlayerUseItemOnBlockEvent.class, event -> this.useItem())
.addListener(PlayerEntityInteractEvent.class, event -> this.useItem()) .addListener(PlayerEntityInteractEvent.class, event -> this.useItem())
@ -133,9 +137,14 @@ public class TowerdefenseRoom extends InstanceContainer {
} }
private void placeTower() { private void placeTower() {
Material usedMaterial = this.player.getItemInMainHand().material(); if(!this.canPlaceActiveTower()) {
if(!this.canPlaceTower(usedMaterial)) return; if(this.cursor.isCursorActive() && !this.enoughMoneyForActiveTower()) {
this.player.sendActionBar(Component.text("Nicht genug Geld!", TextColor.color(255,0,0)));
}
return;
}
try { try {
Material usedMaterial = this.player.getItemInMainHand().material();
Tower tower = this.game.getAvailableTowers().entrySet().stream() Tower tower = this.game.getAvailableTowers().entrySet().stream()
.filter(materialClassEntry -> materialClassEntry.getKey().equals(usedMaterial)) .filter(materialClassEntry -> materialClassEntry.getKey().equals(usedMaterial))
.findFirst() .findFirst()
@ -143,7 +152,7 @@ public class TowerdefenseRoom extends InstanceContainer {
.getValue() .getValue()
.getConstructor() .getConstructor()
.newInstance(); .newInstance();
this.setBlock(this.cursor.getPosition().sub(0, 0.5, 0), Block.BLUE_WOOL); this.setBlock(this.cursor.getTargetBlockPosition(), Block.BLUE_WOOL);
tower.setInstance(this, this.cursor.getPosition()); tower.setInstance(this, this.cursor.getPosition());
this.towers.add(tower); this.towers.add(tower);
this.addMoney(-this.game.getPrices().get(tower.getClass())); this.addMoney(-this.game.getPrices().get(tower.getClass()));
@ -162,24 +171,24 @@ public class TowerdefenseRoom extends InstanceContainer {
tower.remove(); tower.remove();
} }
private void setCursorPosition(PlayerTickEvent event) { private boolean canPlaceActiveTower() {
Point newPosition = this.player.getTargetBlockPosition(reach); Material usedMaterial = this.player.getItemInMainHand().material();
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())));
}
private boolean canPlaceTower(@Nullable Material usedMaterial) {
if(usedMaterial == null) return this.canPlaceTower((Class<Tower>) null);
return this.canPlaceTower(this.game.getAvailableTowers().get(usedMaterial)); return this.canPlaceTower(this.game.getAvailableTowers().get(usedMaterial));
} }
private boolean canPlaceTower(@Nullable Class<? extends Tower> towerClass) { private boolean canPlaceTower(@Nullable Class<? extends Tower> towerClass) {
boolean blockAllowed = this.getBlock(this.cursor.getPosition().sub(0, 1, 0)).equals(Block.BLACK_WOOL); if(towerClass == null) return false;
if(towerClass == null) return blockAllowed; return this.cursor.isCursorActive() && this.enoughMoney(towerClass);
boolean enoughMoney = this.money >= this.game.getPrices().get(towerClass); }
return blockAllowed && enoughMoney;
private boolean enoughMoneyForActiveTower() {
Material usedMaterial = this.player.getItemInMainHand().material();
return this.enoughMoney(this.game.getAvailableTowers().get(usedMaterial));
}
private boolean enoughMoney(@Nullable Class<? extends Tower> towerClass) {
if(towerClass == null) return true;
return this.money >= this.game.getPrices().get(towerClass);
} }
void startWave(List<GroupFactory> enemyGroups) { void startWave(List<GroupFactory> enemyGroups) {
@ -199,6 +208,8 @@ public class TowerdefenseRoom extends InstanceContainer {
float damage = (float) Math.ceil(enemy.getHealth()/10); float damage = (float) Math.ceil(enemy.getHealth()/10);
if(this.player.getHealth() - damage <= 0) { if(this.player.getHealth() - damage <= 0) {
this.player.setInstance(this.game); this.player.setInstance(this.game);
this.getEnemies().forEach(Entity::remove);
this.towers.forEach(Entity::remove);
this.game.getScore().insertResult(this.player); this.game.getScore().insertResult(this.player);
return; return;
} }
@ -215,4 +226,8 @@ public class TowerdefenseRoom extends InstanceContainer {
public List<EntityCreature> getEnemies() { public List<EntityCreature> getEnemies() {
return this.enemies; return this.enemies;
} }
public Player getPlayer() {
return this.player;
}
} }