added tower value calculation and delete tower mechanic
This commit is contained in:
parent
e3068be160
commit
e77879c657
@ -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() {
|
||||
|
@ -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, 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;
|
||||
}
|
||||
|
||||
|
@ -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<EntityCreature> enemies = new ArrayList<>();
|
||||
private final List<Tower> 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<? 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);
|
||||
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));
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user