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
);
private final Map<Class<? extends Tower>, Integer> prices = Map.of(
ZombieTower.class, 14,
SkeletonTower.class, 10,
BlazeTower.class, 30
ZombieTower.class, 4,
SkeletonTower.class, 3,
BlazeTower.class, 8
);
private static final int pathLength = 10;
@ -45,6 +45,13 @@ public class Towerdefense extends StatelessGame {
this.generateMaze();
}
@Override
protected void checkAbandoned() {
this.scheduleNextTick((instance) -> {
if(this.instances.stream().allMatch(room -> room.getPlayers().isEmpty()) && this.getPlayers().isEmpty()) this.unload();
});
}
@Override
protected void onStart() {
this.getPlayers().forEach(player -> {
@ -52,7 +59,7 @@ public class Towerdefense extends StatelessGame {
this.instances.add(newRoom);
player.setInstance(newRoom);
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.minestom.server.MinecraftServer;
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.entity.*;
import net.minestom.server.entity.attribute.Attribute;
@ -40,7 +38,7 @@ public class TowerdefenseRoom extends InstanceContainer {
private final Towerdefense game;
private final List<EntityCreature> enemies = new ArrayList<>();
private final List<Tower> towers = new ArrayList<>();
private final Entity cursor;
private final Cursor cursor;
private int money = 0;
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.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());
BatchUtil.loadAndApplyBatch(this.game.getMazeBatch(), this, () -> {});
this.cursor = new Entity(EntityType.ARMOR_STAND);
this.cursor = new Cursor(reach);
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)
new GroupFactory(new EnemyFactory(EntityType.VILLAGER, 3, 0.1), 1, 800)
)), TaskSchedule.seconds(20), TaskSchedule.stop());
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());
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());
MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of(
new GroupFactory(new EnemyFactory(EntityType.EGG), 200, 800)
)), TaskSchedule.seconds(150), TaskSchedule.stop());
this.eventNode()
.addListener(EntityDeathEvent.class, event -> {
if(!(event.getEntity() instanceof EntityCreature enemy)) return;
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(PlayerUseItemOnBlockEvent.class, event -> this.useItem())
.addListener(PlayerEntityInteractEvent.class, event -> this.useItem())
@ -133,9 +137,14 @@ public class TowerdefenseRoom extends InstanceContainer {
}
private void placeTower() {
Material usedMaterial = this.player.getItemInMainHand().material();
if(!this.canPlaceTower(usedMaterial)) return;
if(!this.canPlaceActiveTower()) {
if(this.cursor.isCursorActive() && !this.enoughMoneyForActiveTower()) {
this.player.sendActionBar(Component.text("Nicht genug Geld!", TextColor.color(255,0,0)));
}
return;
}
try {
Material usedMaterial = this.player.getItemInMainHand().material();
Tower tower = this.game.getAvailableTowers().entrySet().stream()
.filter(materialClassEntry -> materialClassEntry.getKey().equals(usedMaterial))
.findFirst()
@ -143,7 +152,7 @@ public class TowerdefenseRoom extends InstanceContainer {
.getValue()
.getConstructor()
.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());
this.towers.add(tower);
this.addMoney(-this.game.getPrices().get(tower.getClass()));
@ -162,24 +171,24 @@ public class TowerdefenseRoom extends InstanceContainer {
tower.remove();
}
private void setCursorPosition(PlayerTickEvent event) {
Point newPosition = this.player.getTargetBlockPosition(reach);
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);
private boolean canPlaceActiveTower() {
Material usedMaterial = this.player.getItemInMainHand().material();
return this.canPlaceTower(this.game.getAvailableTowers().get(usedMaterial));
}
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 blockAllowed;
boolean enoughMoney = this.money >= this.game.getPrices().get(towerClass);
return blockAllowed && enoughMoney;
if(towerClass == null) return false;
return this.cursor.isCursorActive() && this.enoughMoney(towerClass);
}
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) {
@ -199,6 +208,8 @@ public class TowerdefenseRoom extends InstanceContainer {
float damage = (float) Math.ceil(enemy.getHealth()/10);
if(this.player.getHealth() - damage <= 0) {
this.player.setInstance(this.game);
this.getEnemies().forEach(Entity::remove);
this.towers.forEach(Entity::remove);
this.game.getScore().insertResult(this.player);
return;
}
@ -215,4 +226,8 @@ public class TowerdefenseRoom extends InstanceContainer {
public List<EntityCreature> getEnemies() {
return this.enemies;
}
public Player getPlayer() {
return this.player;
}
}