Compare commits
1 Commits
develop-to
...
develop-bu
Author | SHA1 | Date | |
---|---|---|---|
535008a31e |
@ -3,6 +3,7 @@ package eu.mhsl.minenet.minigames.instance.game;
|
|||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory;
|
import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory;
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.anvilRun.AnvilRunFactory;
|
import eu.mhsl.minenet.minigames.instance.game.stateless.types.anvilRun.AnvilRunFactory;
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.bowSpleef.BowSpleefFactory;
|
import eu.mhsl.minenet.minigames.instance.game.stateless.types.bowSpleef.BowSpleefFactory;
|
||||||
|
import eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle.BuildBattleFactory;
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.elytraRace.ElytraRaceFactory;
|
import eu.mhsl.minenet.minigames.instance.game.stateless.types.elytraRace.ElytraRaceFactory;
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.backrooms.BackroomsFactory;
|
import eu.mhsl.minenet.minigames.instance.game.stateless.types.backrooms.BackroomsFactory;
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.bedwars.BedwarsFactory;
|
import eu.mhsl.minenet.minigames.instance.game.stateless.types.bedwars.BedwarsFactory;
|
||||||
@ -32,7 +33,8 @@ public enum GameList {
|
|||||||
ACIDRAIN(new AcidRainFactory(), GameType.PVE),
|
ACIDRAIN(new AcidRainFactory(), GameType.PVE),
|
||||||
ELYTRARACE(new ElytraRaceFactory(), GameType.PVP),
|
ELYTRARACE(new ElytraRaceFactory(), GameType.PVP),
|
||||||
SPLEEF(new SpleefFactory(), GameType.PVP),
|
SPLEEF(new SpleefFactory(), GameType.PVP),
|
||||||
JUMPDIVE(new JumpDiveFactory(), GameType.JUMPNRUN);
|
JUMPDIVE(new JumpDiveFactory(), GameType.JUMPNRUN),
|
||||||
|
BUILDBATTLE(new BuildBattleFactory(), GameType.OTHER);
|
||||||
|
|
||||||
private final GameFactory factory;
|
private final GameFactory factory;
|
||||||
private final GameType type;
|
private final GameType type;
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle;
|
||||||
|
|
||||||
|
import eu.mhsl.minenet.minigames.instance.Dimension;
|
||||||
|
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
|
||||||
|
import eu.mhsl.minenet.minigames.score.NoScore;
|
||||||
|
|
||||||
|
public class BuildBattle extends StatelessGame {
|
||||||
|
public BuildBattle() {
|
||||||
|
super(Dimension.OVERWORLD.key, "buildBattle", new NoScore());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle;
|
||||||
|
|
||||||
|
import eu.mhsl.minenet.minigames.instance.game.Game;
|
||||||
|
import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory;
|
||||||
|
import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option;
|
||||||
|
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||||
|
import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class BuildBattleFactory implements GameFactory {
|
||||||
|
@Override
|
||||||
|
public TranslatedComponent name() {
|
||||||
|
return TranslatedComponent.byId("game_BuildBattle#name");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception {
|
||||||
|
return new BuildBattle();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle;
|
||||||
|
|
||||||
|
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
|
||||||
|
import eu.mhsl.minenet.minigames.score.Score;
|
||||||
|
import net.minestom.server.registry.DynamicRegistry;
|
||||||
|
import net.minestom.server.world.DimensionType;
|
||||||
|
|
||||||
|
class BuilderWorld extends StatelessGame {
|
||||||
|
public BuilderWorld(DynamicRegistry.Key<DimensionType> dimensionType, String gameName, Score score) {
|
||||||
|
super(dimensionType, gameName, score);
|
||||||
|
}
|
||||||
|
}
|
@ -1,89 +0,0 @@
|
|||||||
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense;
|
|
||||||
|
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers.Tower;
|
|
||||||
import net.minestom.server.coordinate.Point;
|
|
||||||
import net.minestom.server.coordinate.Pos;
|
|
||||||
import net.minestom.server.coordinate.Vec;
|
|
||||||
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 net.minestom.server.item.Material;
|
|
||||||
import net.minestom.server.network.packet.server.SendablePacket;
|
|
||||||
import net.minestom.server.network.packet.server.play.ParticlePacket;
|
|
||||||
import net.minestom.server.particle.Particle;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
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);
|
|
||||||
Material holdingMaterial = this.getInstance().getPlayerHandMaterial();
|
|
||||||
if(!this.getInstance().getGame().getAvailableTowers().containsKey(holdingMaterial)) this.setCursorEnabled(false);
|
|
||||||
this.teleport(new Pos(newTargetBlockPosition.add(0.5,1,0.5)));
|
|
||||||
this.showRange(this.getInstance().getGame().getAvailableTowers().get(holdingMaterial));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setCursorEnabled(boolean enabled) {
|
|
||||||
this.cursorActive = enabled;
|
|
||||||
this.setInvisible(!enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showRange(@Nullable Class<? extends Tower> towerClass) {
|
|
||||||
if(towerClass == null) return;
|
|
||||||
if(!this.isCursorActive()) return;
|
|
||||||
try {
|
|
||||||
int range = towerClass.getConstructor().newInstance().getRange();
|
|
||||||
Collection<SendablePacket> particles = new ArrayList<>();
|
|
||||||
double circumference = 2 * Math.PI * range;
|
|
||||||
int count = (int) (circumference * 1.5);
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
double radians = ((2 * Math.PI) / count) * i;
|
|
||||||
Vec relativePosition = new Vec(Math.sin(radians)*range, 0, Math.cos(radians)*range);
|
|
||||||
ParticlePacket particle = new ParticlePacket(Particle.COMPOSTER, this.position.add(relativePosition), Pos.ZERO, 0, 1);
|
|
||||||
particles.add(particle);
|
|
||||||
}
|
|
||||||
this.getInstance().getPlayer().sendPackets(particles);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense;
|
|
||||||
|
|
||||||
import net.minestom.server.entity.EntityCreature;
|
|
||||||
import net.minestom.server.entity.EntityType;
|
|
||||||
import net.minestom.server.entity.attribute.Attribute;
|
|
||||||
|
|
||||||
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, 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, 10, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityCreature buildEntity() {
|
|
||||||
EntityCreature entity = new EntityCreature(this.entityType);
|
|
||||||
entity.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(this.speed);
|
|
||||||
entity.getAttribute(Attribute.MAX_HEALTH).setBaseValue(this.health);
|
|
||||||
entity.setHealth(this.health);
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense;
|
|
||||||
|
|
||||||
import net.minestom.server.MinecraftServer;
|
|
||||||
import net.minestom.server.timer.TaskSchedule;
|
|
||||||
|
|
||||||
record GroupFactory(EnemyFactory enemyFactory, int count, long delay) {
|
|
||||||
public void summonGroup(TowerdefenseRoom instance) {
|
|
||||||
for (int i = 0; i < this.count; i++) {
|
|
||||||
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
|
|
||||||
instance.addEnemy(this.enemyFactory.buildEntity());
|
|
||||||
return TaskSchedule.stop();
|
|
||||||
}, TaskSchedule.millis(this.delay*i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,120 +3,23 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense;
|
|||||||
import eu.mhsl.minenet.minigames.instance.Dimension;
|
import eu.mhsl.minenet.minigames.instance.Dimension;
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
|
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.generator.MazeGenerator;
|
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.generator.MazeGenerator;
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers.BlazeTower;
|
import eu.mhsl.minenet.minigames.score.NoScore;
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers.SkeletonTower;
|
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers.Tower;
|
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers.ZombieTower;
|
|
||||||
import eu.mhsl.minenet.minigames.score.LastWinsScore;
|
|
||||||
import net.minestom.server.coordinate.Pos;
|
|
||||||
import net.minestom.server.entity.EntityType;
|
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
|
import net.minestom.server.item.ItemStack;
|
||||||
import net.minestom.server.instance.block.Block;
|
|
||||||
import net.minestom.server.item.Material;
|
import net.minestom.server.item.Material;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class Towerdefense extends StatelessGame {
|
public class Towerdefense extends StatelessGame {
|
||||||
private final Random random = new Random();
|
|
||||||
private final AbsoluteBlockBatch mazeBatch = new AbsoluteBlockBatch();
|
|
||||||
private final List<Pos> mazePath = new ArrayList<>();
|
|
||||||
private final List<TowerdefenseRoom> instances = new ArrayList<>();
|
|
||||||
private final Map<Material, Class<? extends Tower>> availableTowers = Map.of(
|
|
||||||
Material.SKELETON_SPAWN_EGG, SkeletonTower.class,
|
|
||||||
Material.ZOMBIE_SPAWN_EGG, ZombieTower.class,
|
|
||||||
Material.BLAZE_SPAWN_EGG, BlazeTower.class
|
|
||||||
);
|
|
||||||
private final Map<Class<? extends Tower>, Integer> prices = Map.of(
|
|
||||||
ZombieTower.class, 4,
|
|
||||||
SkeletonTower.class, 3,
|
|
||||||
BlazeTower.class, 8
|
|
||||||
);
|
|
||||||
|
|
||||||
private static final int pathLength = 10;
|
|
||||||
|
|
||||||
public Towerdefense() {
|
public Towerdefense() {
|
||||||
super(Dimension.NETHER.key, "Towerdefense", new LastWinsScore());
|
super(Dimension.NETHER.key, "Towerdefense", new NoScore());
|
||||||
|
|
||||||
this.setGenerator(new MazeGenerator());
|
setGenerator(new MazeGenerator());
|
||||||
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 -> {
|
|
||||||
TowerdefenseRoom newRoom = new TowerdefenseRoom(player, this);
|
|
||||||
this.instances.add(newRoom);
|
|
||||||
player.setInstance(newRoom, new Pos(0, 1, 0));
|
|
||||||
newRoom.startWave(List.of(
|
|
||||||
new GroupFactory(new EnemyFactory(EntityType.VILLAGER, 2, 0.1), 1, 800)
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateMaze() {
|
|
||||||
Pos position = new Pos(0, 0, 0);
|
|
||||||
this.addMazePosition(position, Block.GREEN_WOOL);
|
|
||||||
position = position.add(0,0,2);
|
|
||||||
|
|
||||||
List<Integer> previousDirections = new ArrayList<>();
|
|
||||||
int direction = 1; // 0 -> right; 1 -> straight; 2 -> left
|
|
||||||
for (int i = 0; i < pathLength; i++) {
|
|
||||||
for (int j = 0; j < 9; j++) {
|
|
||||||
position = position.add(direction-1,0,direction%2);
|
|
||||||
this.addMazePosition(position, Block.WHITE_WOOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int origin = 0;
|
|
||||||
int bound = 3;
|
|
||||||
long rightLeftDifference = previousDirections.stream().filter(integer -> integer == 0).count() - previousDirections.stream().filter(integer -> integer == 2).count();
|
|
||||||
if(rightLeftDifference >= 2 || direction == 2) origin = 1;
|
|
||||||
if(rightLeftDifference <= -2 || direction == 0) bound = 2;
|
|
||||||
direction = this.random.nextInt(origin, bound);
|
|
||||||
previousDirections.add(direction);
|
|
||||||
}
|
|
||||||
this.addMazePosition(position, Block.WHITE_WOOL);
|
|
||||||
this.addMazePosition(position.add(0,0,3), Block.WHITE_WOOL);
|
|
||||||
this.addMazePosition(position.add(0,0,6), Block.RED_WOOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addMazePosition(Pos position, Block pathBlock) {
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
for (int j = 0; j < 3; j++) {
|
|
||||||
this.mazeBatch.setBlock(position.add(i-1,0,j-1), pathBlock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.mazePath.add(position.add(0.5,1,0.5));
|
|
||||||
}
|
|
||||||
|
|
||||||
public AbsoluteBlockBatch getMazeBatch() {
|
|
||||||
return this.mazeBatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Pos> getMazePath() {
|
|
||||||
return this.mazePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onPlayerJoin(Player p) {
|
protected boolean onPlayerJoin(Player p) {
|
||||||
|
p.getInventory().setItemStack(1, ItemStack.of(Material.ARMOR_STAND));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Class<? extends Tower>, Integer> getPrices() {
|
|
||||||
return this.prices;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Material, Class<? extends Tower>> getAvailableTowers() {
|
|
||||||
return this.availableTowers;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,249 +0,0 @@
|
|||||||
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense;
|
|
||||||
|
|
||||||
import eu.mhsl.minenet.minigames.instance.Dimension;
|
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.generator.MazeGenerator;
|
|
||||||
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.Vec;
|
|
||||||
import net.minestom.server.entity.*;
|
|
||||||
import net.minestom.server.entity.attribute.Attribute;
|
|
||||||
import net.minestom.server.entity.damage.DamageType;
|
|
||||||
import net.minestom.server.event.entity.EntityDeathEvent;
|
|
||||||
import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
|
|
||||||
import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
|
|
||||||
import net.minestom.server.event.inventory.InventoryPreClickEvent;
|
|
||||||
import net.minestom.server.event.item.ItemDropEvent;
|
|
||||||
import net.minestom.server.event.item.PlayerBeginItemUseEvent;
|
|
||||||
import net.minestom.server.event.player.*;
|
|
||||||
import net.minestom.server.instance.InstanceContainer;
|
|
||||||
import net.minestom.server.instance.block.Block;
|
|
||||||
import net.minestom.server.item.ItemAnimation;
|
|
||||||
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;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class TowerdefenseRoom extends InstanceContainer {
|
|
||||||
private final static int reach = 30;
|
|
||||||
private long lastPlayerAttack = 0;
|
|
||||||
private final Player player;
|
|
||||||
private final Towerdefense game;
|
|
||||||
private final List<EntityCreature> enemies = new ArrayList<>();
|
|
||||||
private final List<Tower> towers = new ArrayList<>();
|
|
||||||
private final Cursor cursor;
|
|
||||||
private int money = 0;
|
|
||||||
|
|
||||||
public TowerdefenseRoom(Player player, Towerdefense game) {
|
|
||||||
super(UUID.randomUUID(), Dimension.OVERWORLD.key);
|
|
||||||
MinecraftServer.getInstanceManager().registerInstance(this);
|
|
||||||
this.player = player;
|
|
||||||
this.game = game;
|
|
||||||
this.player.setGameMode(GameMode.ADVENTURE);
|
|
||||||
this.player.setAllowFlying(true);
|
|
||||||
this.addMoney(0);
|
|
||||||
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.BOW).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().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 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, 3, 0.1), 1, 800)
|
|
||||||
)), TaskSchedule.seconds(20), TaskSchedule.stop());
|
|
||||||
MinecraftServer.getSchedulerManager().scheduleTask(() -> this.startWave(List.of(
|
|
||||||
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), 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, event -> this.cursor.updateCursorPosition(this.player))
|
|
||||||
.addListener(PlayerUseItemEvent.class, event -> this.useItem())
|
|
||||||
.addListener(PlayerUseItemOnBlockEvent.class, event -> this.useItem())
|
|
||||||
.addListener(PlayerEntityInteractEvent.class, event -> this.useItem())
|
|
||||||
.addListener(PlayerHandAnimationEvent.class, event -> this.useItem())
|
|
||||||
.addListener(ItemDropEvent.class, CommonEventHandles::cancel)
|
|
||||||
.addListener(InventoryPreClickEvent.class, CommonEventHandles::cancel)
|
|
||||||
.addListener(PlayerSwapItemEvent.class, CommonEventHandles::cancel)
|
|
||||||
.addListener(PlayerBeginItemUseEvent.class, event -> {
|
|
||||||
if(event.getAnimation().equals(ItemAnimation.BOW)) event.setCancelled(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void useItem() {
|
|
||||||
Material itemInHand = this.player.getItemInMainHand().material();
|
|
||||||
if(itemInHand.equals(Material.BOW)) {
|
|
||||||
this.playerAttack();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(itemInHand.equals(Material.BARRIER)) {
|
|
||||||
this.removeTower();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.placeTower();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void playerAttack() {
|
|
||||||
if(this.lastPlayerAttack > System.currentTimeMillis()-200) return;
|
|
||||||
Player p = this.player;
|
|
||||||
this.lastPlayerAttack = System.currentTimeMillis();
|
|
||||||
EntityProjectile projectile = new EntityProjectile(p, EntityType.SPECTRAL_ARROW);
|
|
||||||
projectile.setView(p.getPosition().yaw(), p.getPosition().pitch());
|
|
||||||
projectile.setNoGravity(true);
|
|
||||||
projectile.setAerodynamics(new Aerodynamics(0, 1, 0));
|
|
||||||
|
|
||||||
Vec projectileVelocity = p.getPosition().direction().normalize().mul(20);
|
|
||||||
projectile.setVelocity(projectileVelocity);
|
|
||||||
projectile.scheduleRemove(Duration.ofSeconds(5));
|
|
||||||
projectile.setInstance(this, p.getPosition().add(0, p.getEyeHeight()-0.5, 0));
|
|
||||||
projectile.eventNode()
|
|
||||||
.addListener(ProjectileCollideWithEntityEvent.class, hitEvent -> {
|
|
||||||
if(!(hitEvent.getTarget() instanceof EntityCreature target)) return;
|
|
||||||
if(!this.getEnemies().stream().filter(entityCreature -> !entityCreature.isDead()).toList().contains(target)) return;
|
|
||||||
target.damage(DamageType.PLAYER_ATTACK, 0.1f);
|
|
||||||
if(target.isDead()) this.addMoney((int) target.getAttribute(Attribute.MAX_HEALTH).getBaseValue());
|
|
||||||
projectile.remove();
|
|
||||||
})
|
|
||||||
.addListener(ProjectileCollideWithBlockEvent.class, collisionEvent -> projectile.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addMoney(int amount) {
|
|
||||||
this.money += amount;
|
|
||||||
this.player.setLevel(this.money);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Material getPlayerHandMaterial() {
|
|
||||||
return this.player.getItemInMainHand().material();
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void placeTower() {
|
|
||||||
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()
|
|
||||||
.orElseThrow()
|
|
||||||
.getValue()
|
|
||||||
.getConstructor()
|
|
||||||
.newInstance();
|
|
||||||
this.setBlock(this.cursor.getTargetBlockPosition(), Block.BLUE_WOOL);
|
|
||||||
tower.setInstance(this, this.cursor.getPosition());
|
|
||||||
this.towers.add(tower);
|
|
||||||
tower.startShooting();
|
|
||||||
this.addMoney(-this.game.getPrices().get(tower.getClass()));
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
this.cursor.updateCursorPosition(this.player);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 boolean canPlaceActiveTower() {
|
|
||||||
Material usedMaterial = this.player.getItemInMainHand().material();
|
|
||||||
return this.canPlaceTower(this.game.getAvailableTowers().get(usedMaterial));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canPlaceTower(@Nullable Class<? extends Tower> towerClass) {
|
|
||||||
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) {
|
|
||||||
enemyGroups.forEach(groupFactory -> groupFactory.summonGroup(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addEnemy(EntityCreature enemy) {
|
|
||||||
enemy.setInstance(this, this.game.getMazePath().getFirst());
|
|
||||||
this.enemies.add(enemy);
|
|
||||||
this.changeEnemyGoal(enemy, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void changeEnemyGoal(EntityCreature enemy, int positionIndex) {
|
|
||||||
if(positionIndex == this.game.getMazePath().size()-1) {
|
|
||||||
this.enemies.remove(enemy);
|
|
||||||
enemy.remove();
|
|
||||||
float damage = (float) Math.ceil(enemy.getHealth()/10);
|
|
||||||
if(this.player.getHealth() - damage <= 0) {
|
|
||||||
this.getEnemies().forEach(Entity::remove);
|
|
||||||
this.towers.forEach(Entity::remove);
|
|
||||||
this.player.setInstance(this.game).thenRun(() -> MinecraftServer.getInstanceManager().unregisterInstance(this));
|
|
||||||
this.player.heal();
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Towerdefense getGame() {
|
|
||||||
return this.game;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<EntityCreature> getEnemies() {
|
|
||||||
return this.enemies;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Player getPlayer() {
|
|
||||||
return this.player;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers;
|
|
||||||
|
|
||||||
import net.minestom.server.entity.EntityCreature;
|
|
||||||
import net.minestom.server.entity.EntityType;
|
|
||||||
|
|
||||||
public class BlazeTower extends ShootingTower {
|
|
||||||
public BlazeTower() {
|
|
||||||
super(EntityType.BLAZE, 2, 2, 15);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void attack(EntityCreature enemy) {
|
|
||||||
this.swingMainHand();
|
|
||||||
this.shootProjectile(enemy, EntityType.FIREBALL, 2, 0);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers;
|
|
||||||
|
|
||||||
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.EntityCreature;
|
|
||||||
import net.minestom.server.entity.EntityProjectile;
|
|
||||||
import net.minestom.server.entity.EntityType;
|
|
||||||
import net.minestom.server.entity.attribute.Attribute;
|
|
||||||
import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
|
|
||||||
import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
|
|
||||||
public abstract class ShootingTower extends Tower {
|
|
||||||
public ShootingTower(@NotNull EntityType entityType, int damage, double attacksPerSecond, int range) {
|
|
||||||
super(entityType, damage, attacksPerSecond, range);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void shootProjectile(EntityCreature enemy, EntityType projectileType, double power, double spread) {
|
|
||||||
EntityProjectile projectile = new EntityProjectile(this, projectileType);
|
|
||||||
projectile.setView(this.getPosition().yaw(), this.getPosition().pitch());
|
|
||||||
projectile.setNoGravity(true);
|
|
||||||
projectile.setAerodynamics(new Aerodynamics(0, 1, 0));
|
|
||||||
Pos startingPoint = this.getPosition().add(0, this.getEyeHeight(), 0);
|
|
||||||
|
|
||||||
double enemySpeed = enemy.getAttribute(Attribute.MOVEMENT_SPEED).getBaseValue() / 0.05;
|
|
||||||
Point enemyGoal = enemy.getNavigator().getGoalPosition();
|
|
||||||
if(enemyGoal == null) enemyGoal = enemy.getPosition();
|
|
||||||
Pos enemyPosition = enemy.getPosition();
|
|
||||||
Vec enemyMovement = Vec.fromPoint(enemyGoal.sub(enemyPosition)).normalize().mul(enemySpeed);
|
|
||||||
|
|
||||||
// just an approximation, not calculated correctly:
|
|
||||||
double projectileSpeed = 20 * power;
|
|
||||||
double enemyTowerDistance = startingPoint.distance(enemyPosition);
|
|
||||||
double estimatedFlightTime = (enemyTowerDistance / projectileSpeed);
|
|
||||||
Pos targetPosition = enemyPosition.add(enemyMovement.mul(estimatedFlightTime)).withY(enemyPosition.y()+enemy.getEyeHeight());
|
|
||||||
|
|
||||||
projectile.shoot(targetPosition, power, spread);
|
|
||||||
projectile.scheduleRemove(Duration.ofSeconds(5));
|
|
||||||
projectile.setInstance(this.getInstance(), startingPoint);
|
|
||||||
projectile.eventNode()
|
|
||||||
.addListener(ProjectileCollideWithEntityEvent.class, event -> {
|
|
||||||
if(!(event.getTarget() instanceof EntityCreature target)) return;
|
|
||||||
if(!this.getRoomInstance().getEnemies().contains(target)) return;
|
|
||||||
this.causeDamage(target);
|
|
||||||
this.onProjectileHit(target);
|
|
||||||
target.setFlyingWithElytra(true);
|
|
||||||
projectile.remove();
|
|
||||||
})
|
|
||||||
.addListener(ProjectileCollideWithBlockEvent.class, event -> projectile.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onProjectileHit(EntityCreature enemy) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void attack(EntityCreature enemy) {
|
|
||||||
this.shootProjectile(enemy, EntityType.ARROW, 2, 0);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers;
|
|
||||||
|
|
||||||
import net.minestom.server.entity.EntityCreature;
|
|
||||||
import net.minestom.server.entity.EntityType;
|
|
||||||
import net.minestom.server.item.ItemStack;
|
|
||||||
import net.minestom.server.item.Material;
|
|
||||||
|
|
||||||
public class SkeletonTower extends ShootingTower {
|
|
||||||
public SkeletonTower() {
|
|
||||||
super(EntityType.SKELETON, 1, 2, 10);
|
|
||||||
this.setItemInMainHand(ItemStack.of(Material.BOW));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void attack(EntityCreature enemy) {
|
|
||||||
this.swingMainHand();
|
|
||||||
this.shootProjectile(enemy, EntityType.ARROW, 2, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onProjectileHit(EntityCreature enemy) {
|
|
||||||
super.onProjectileHit(enemy);
|
|
||||||
// enemy.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(enemy.getAttribute(Attribute.MOVEMENT_SPEED).getBaseValue()*0.5);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,135 +0,0 @@
|
|||||||
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers;
|
|
||||||
|
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.TowerdefenseRoom;
|
|
||||||
import net.minestom.server.MinecraftServer;
|
|
||||||
import net.minestom.server.coordinate.Pos;
|
|
||||||
import net.minestom.server.entity.*;
|
|
||||||
import net.minestom.server.entity.attribute.Attribute;
|
|
||||||
import net.minestom.server.entity.damage.DamageType;
|
|
||||||
import net.minestom.server.timer.Task;
|
|
||||||
import net.minestom.server.timer.TaskSchedule;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public abstract class Tower extends EntityCreature {
|
|
||||||
public enum Priority {
|
|
||||||
FIRST(Type.PATH_DISTANCE),
|
|
||||||
LAST(Type.PATH_DISTANCE),
|
|
||||||
STRONG(Type.HEALTH),
|
|
||||||
WEAK(Type.HEALTH),
|
|
||||||
CLOSE(Type.TOWER_DISTANCE),
|
|
||||||
FAR(Type.TOWER_DISTANCE);
|
|
||||||
|
|
||||||
final Type type;
|
|
||||||
Priority(Type type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getType() {
|
|
||||||
return this.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Type {
|
|
||||||
PATH_DISTANCE,
|
|
||||||
HEALTH,
|
|
||||||
TOWER_DISTANCE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final static int damageDivider = 10;
|
|
||||||
private Priority priority = Priority.FIRST;
|
|
||||||
protected float damage;
|
|
||||||
protected int range;
|
|
||||||
protected double attacksPerSecond;
|
|
||||||
protected TaskSchedule attackDelay;
|
|
||||||
private @Nullable 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startShooting() {
|
|
||||||
this.attackTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> {
|
|
||||||
EntityCreature nextEnemy = this.getNextEnemy();
|
|
||||||
if(nextEnemy == null) return this.attackDelay;
|
|
||||||
this.lookAt(nextEnemy);
|
|
||||||
this.attack(nextEnemy);
|
|
||||||
return this.attackDelay;
|
|
||||||
}, TaskSchedule.immediate());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void remove(boolean permanent) {
|
|
||||||
if(this.attackTask != null) this.attackTask.cancel();
|
|
||||||
super.remove(permanent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @Nullable EntityCreature getNextEnemy() {
|
|
||||||
List<EntityCreature> enemies = this.getSortedEnemies();
|
|
||||||
if(enemies.isEmpty()) return null;
|
|
||||||
|
|
||||||
return switch (this.priority) {
|
|
||||||
case LAST, STRONG, FAR -> enemies.getLast();
|
|
||||||
case FIRST, WEAK, CLOSE -> enemies.getFirst();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<EntityCreature> getSortedEnemies() {
|
|
||||||
Stream<EntityCreature> enemyStream = this.getRoomInstance().getEnemies().stream().parallel()
|
|
||||||
.filter(enemy -> !enemy.isDead())
|
|
||||||
.filter(enemy -> enemy.getPosition().distance(this.getPosition()) <= this.range);
|
|
||||||
return switch (this.priority.getType()) {
|
|
||||||
case PATH_DISTANCE -> enemyStream
|
|
||||||
.sorted((o1, o2) -> {
|
|
||||||
Pos endPoint = this.getRoomInstance().getGame().getMazePath().getLast();
|
|
||||||
return Double.compare(
|
|
||||||
o1.getPosition().distance(endPoint),
|
|
||||||
o2.getPosition().distance(endPoint)
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
case TOWER_DISTANCE -> enemyStream
|
|
||||||
.sorted((o1, o2) -> Double.compare(
|
|
||||||
o1.getPosition().distance(this.getPosition()),
|
|
||||||
o2.getPosition().distance(this.getPosition())
|
|
||||||
)).toList();
|
|
||||||
case HEALTH -> enemyStream
|
|
||||||
.sorted((o1, o2) -> Float.compare(o1.getHealth(), o2.getHealth()))
|
|
||||||
.toList();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TowerdefenseRoom getRoomInstance() {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRange() {
|
|
||||||
return this.range;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void causeDamage(EntityCreature enemy) {
|
|
||||||
this.causeDamage(enemy, this.damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void causeDamage(EntityCreature enemy, float amount) {
|
|
||||||
enemy.damage(DamageType.PLAYER_ATTACK, amount);
|
|
||||||
if(enemy.isDead()) this.getRoomInstance().addMoney((int) enemy.getAttribute(Attribute.MAX_HEALTH).getBaseValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void attack(EntityCreature enemy);
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towers;
|
|
||||||
|
|
||||||
import net.minestom.server.entity.EntityCreature;
|
|
||||||
import net.minestom.server.entity.EntityType;
|
|
||||||
import net.minestom.server.item.ItemStack;
|
|
||||||
import net.minestom.server.item.Material;
|
|
||||||
|
|
||||||
public class ZombieTower extends Tower {
|
|
||||||
public ZombieTower() {
|
|
||||||
super(EntityType.ZOMBIE, 7, 1, 4);
|
|
||||||
this.setItemInMainHand(ItemStack.of(Material.IRON_SWORD));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void attack(EntityCreature enemy) {
|
|
||||||
this.swingMainHand();
|
|
||||||
this.causeDamage(enemy);
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user