moved shooting mechanic to ShootingTower, added money
This commit is contained in:
parent
867bee1c5a
commit
e3068be160
@ -30,6 +30,11 @@ public class Towerdefense extends StatelessGame {
|
|||||||
Material.ZOMBIE_SPAWN_EGG, ZombieTower.class,
|
Material.ZOMBIE_SPAWN_EGG, ZombieTower.class,
|
||||||
Material.BLAZE_SPAWN_EGG, BlazeTower.class
|
Material.BLAZE_SPAWN_EGG, BlazeTower.class
|
||||||
);
|
);
|
||||||
|
private final Map<Class<? extends Tower>, Integer> prices = Map.of(
|
||||||
|
ZombieTower.class, 5,
|
||||||
|
SkeletonTower.class, 10,
|
||||||
|
BlazeTower.class, 15
|
||||||
|
);
|
||||||
|
|
||||||
private static final int pathLength = 10;
|
private static final int pathLength = 10;
|
||||||
|
|
||||||
@ -96,6 +101,10 @@ public class Towerdefense extends StatelessGame {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<Class<? extends Tower>, Integer> getPrices() {
|
||||||
|
return this.prices;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Material, Class<? extends Tower>> getAvailableTowers() {
|
public Map<Material, Class<? extends Tower>> getAvailableTowers() {
|
||||||
return this.availableTowers;
|
return this.availableTowers;
|
||||||
}
|
}
|
||||||
|
@ -6,33 +6,39 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.towe
|
|||||||
import eu.mhsl.minenet.minigames.util.BatchUtil;
|
import eu.mhsl.minenet.minigames.util.BatchUtil;
|
||||||
import eu.mhsl.minenet.minigames.util.CommonEventHandles;
|
import eu.mhsl.minenet.minigames.util.CommonEventHandles;
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
|
import net.minestom.server.collision.Aerodynamics;
|
||||||
import net.minestom.server.coordinate.Point;
|
import net.minestom.server.coordinate.Point;
|
||||||
import net.minestom.server.coordinate.Pos;
|
import net.minestom.server.coordinate.Pos;
|
||||||
|
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;
|
||||||
import net.minestom.server.entity.damage.DamageType;
|
import net.minestom.server.entity.damage.DamageType;
|
||||||
import net.minestom.server.event.entity.EntityDeathEvent;
|
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.inventory.InventoryPreClickEvent;
|
||||||
import net.minestom.server.event.item.ItemDropEvent;
|
import net.minestom.server.event.item.ItemDropEvent;
|
||||||
import net.minestom.server.event.player.PlayerEntityInteractEvent;
|
import net.minestom.server.event.player.*;
|
||||||
import net.minestom.server.event.player.PlayerSwapItemEvent;
|
|
||||||
import net.minestom.server.event.player.PlayerTickEvent;
|
|
||||||
import net.minestom.server.event.player.PlayerUseItemEvent;
|
|
||||||
import net.minestom.server.instance.InstanceContainer;
|
import net.minestom.server.instance.InstanceContainer;
|
||||||
import net.minestom.server.instance.block.Block;
|
import net.minestom.server.instance.block.Block;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import net.minestom.server.item.Material;
|
import net.minestom.server.item.Material;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class TowerdefenseRoom extends InstanceContainer {
|
public class TowerdefenseRoom extends InstanceContainer {
|
||||||
|
private final static int reach = 30;
|
||||||
|
private long lastPlayerAttack = 0;
|
||||||
private final Player player;
|
private final Player player;
|
||||||
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 Entity cursor;
|
||||||
|
private int money = 1000;
|
||||||
|
|
||||||
public TowerdefenseRoom(Player player, Towerdefense game) {
|
public TowerdefenseRoom(Player player, Towerdefense game) {
|
||||||
super(UUID.randomUUID(), Dimension.OVERWORLD.key);
|
super(UUID.randomUUID(), Dimension.OVERWORLD.key);
|
||||||
@ -41,8 +47,11 @@ public class TowerdefenseRoom extends InstanceContainer {
|
|||||||
this.game = game;
|
this.game = game;
|
||||||
this.player.setGameMode(GameMode.ADVENTURE);
|
this.player.setGameMode(GameMode.ADVENTURE);
|
||||||
this.player.setAllowFlying(true);
|
this.player.setAllowFlying(true);
|
||||||
this.player.getAttribute(Attribute.BLOCK_INTERACTION_RANGE).setBaseValue(200);
|
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.SPECTRAL_ARROW));
|
||||||
this.game.getAvailableTowers().keySet().forEach(material -> this.player.getInventory().addItemStack(ItemStack.of(material)));
|
this.game.getAvailableTowers().keySet().forEach(material -> this.player.getInventory().addItemStack(ItemStack.of(material)));
|
||||||
|
|
||||||
this.setGenerator(new MazeGenerator());
|
this.setGenerator(new MazeGenerator());
|
||||||
@ -58,15 +67,55 @@ public class TowerdefenseRoom extends InstanceContainer {
|
|||||||
this.enemies.remove(enemy);
|
this.enemies.remove(enemy);
|
||||||
})
|
})
|
||||||
.addListener(PlayerTickEvent.class, this::setCursorPosition)
|
.addListener(PlayerTickEvent.class, this::setCursorPosition)
|
||||||
.addListener(PlayerUseItemEvent.class, event -> this.setTower(event.getItemStack().material()))
|
.addListener(PlayerUseItemEvent.class, event -> this.useItem())
|
||||||
.addListener(PlayerEntityInteractEvent.class, event -> this.setTower(event.getPlayer().getItemInMainHand().material()))
|
.addListener(PlayerUseItemOnBlockEvent.class, event -> this.useItem())
|
||||||
|
.addListener(PlayerEntityInteractEvent.class, event -> this.useItem())
|
||||||
|
.addListener(PlayerHandAnimationEvent.class, event -> this.useItem())
|
||||||
.addListener(ItemDropEvent.class, CommonEventHandles::cancel)
|
.addListener(ItemDropEvent.class, CommonEventHandles::cancel)
|
||||||
.addListener(InventoryPreClickEvent.class, CommonEventHandles::cancel)
|
.addListener(InventoryPreClickEvent.class, CommonEventHandles::cancel)
|
||||||
.addListener(PlayerSwapItemEvent.class, CommonEventHandles::cancel);
|
.addListener(PlayerSwapItemEvent.class, CommonEventHandles::cancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTower(Material usedMaterial) {
|
private void useItem() {
|
||||||
if(!this.canPlaceTower()) return;
|
if(this.player.getItemInMainHand().material().equals(Material.SPECTRAL_ARROW)) {
|
||||||
|
this.playerAttack();
|
||||||
|
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));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void placeTower() {
|
||||||
|
Material usedMaterial = this.player.getItemInMainHand().material();
|
||||||
|
if(!this.canPlaceTower(usedMaterial)) return;
|
||||||
try {
|
try {
|
||||||
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))
|
||||||
@ -82,20 +131,24 @@ public class TowerdefenseRoom extends InstanceContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<EntityCreature> getEnemies() {
|
|
||||||
return this.enemies;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setCursorPosition(PlayerTickEvent event) {
|
private void setCursorPosition(PlayerTickEvent event) {
|
||||||
Point newPosition = this.player.getTargetBlockPosition(20);
|
Point newPosition = this.player.getTargetBlockPosition(reach);
|
||||||
if(newPosition == null) return;
|
if(newPosition == null) return;
|
||||||
newPosition = newPosition.add(0.5,1,0.5);
|
newPosition = newPosition.add(0.5,1,0.5);
|
||||||
this.cursor.teleport(new Pos(newPosition));
|
this.cursor.teleport(new Pos(newPosition));
|
||||||
this.cursor.setInvisible(!this.canPlaceTower());
|
this.cursor.setInvisible(!(this.canPlaceTower((Material) null) && this.game.getAvailableTowers().containsKey(this.player.getItemInMainHand().material())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canPlaceTower() {
|
private boolean canPlaceTower(@Nullable Material usedMaterial) {
|
||||||
return this.getBlock(this.cursor.getPosition().sub(0, 1, 0)).equals(Block.BLACK_WOOL);
|
if(usedMaterial == null) return this.canPlaceTower((Class<Tower>) null);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void startWave(List<GroupFactory> enemyGroups) {
|
void startWave(List<GroupFactory> enemyGroups) {
|
||||||
@ -108,10 +161,6 @@ public class TowerdefenseRoom extends InstanceContainer {
|
|||||||
this.changeEnemyGoal(enemy, 0);
|
this.changeEnemyGoal(enemy, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Towerdefense getGame() {
|
|
||||||
return this.game;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void changeEnemyGoal(EntityCreature enemy, int positionIndex) {
|
private void changeEnemyGoal(EntityCreature enemy, int positionIndex) {
|
||||||
if(positionIndex == this.game.getMazePath().size()-1) {
|
if(positionIndex == this.game.getMazePath().size()-1) {
|
||||||
this.enemies.remove(enemy);
|
this.enemies.remove(enemy);
|
||||||
@ -121,4 +170,12 @@ public class TowerdefenseRoom extends InstanceContainer {
|
|||||||
}
|
}
|
||||||
enemy.getNavigator().setPathTo(this.game.getMazePath().get(positionIndex+1), 0.6, () -> this.changeEnemyGoal(enemy, positionIndex+1));
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,14 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.tow
|
|||||||
import net.minestom.server.entity.EntityCreature;
|
import net.minestom.server.entity.EntityCreature;
|
||||||
import net.minestom.server.entity.EntityType;
|
import net.minestom.server.entity.EntityType;
|
||||||
|
|
||||||
public class BlazeTower extends Tower {
|
public class BlazeTower extends ShootingTower {
|
||||||
public BlazeTower() {
|
public BlazeTower() {
|
||||||
super(EntityType.BLAZE, 2, 1, 20);
|
super(EntityType.BLAZE, 1, 1, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void attack(EntityCreature enemy) {
|
protected void attack(EntityCreature enemy) {
|
||||||
|
this.swingMainHand();
|
||||||
this.shootProjectile(enemy, EntityType.FIREBALL, 2, 0);
|
this.shootProjectile(enemy, EntityType.FIREBALL, 2, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ import net.minestom.server.entity.EntityType;
|
|||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import net.minestom.server.item.Material;
|
import net.minestom.server.item.Material;
|
||||||
|
|
||||||
public class SkeletonTower extends Tower {
|
public class SkeletonTower extends ShootingTower {
|
||||||
public SkeletonTower() {
|
public SkeletonTower() {
|
||||||
super(EntityType.SKELETON, 1, 3, 15);
|
super(EntityType.SKELETON, 1, 3, 15);
|
||||||
this.setItemInMainHand(ItemStack.of(Material.BOW));
|
this.setItemInMainHand(ItemStack.of(Material.BOW));
|
||||||
@ -13,6 +13,7 @@ public class SkeletonTower extends Tower {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void attack(EntityCreature enemy) {
|
protected void attack(EntityCreature enemy) {
|
||||||
|
this.swingMainHand();
|
||||||
this.shootProjectile(enemy, EntityType.ARROW, 2, 0);
|
this.shootProjectile(enemy, EntityType.ARROW, 2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,21 +2,15 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.tow
|
|||||||
|
|
||||||
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.TowerdefenseRoom;
|
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.TowerdefenseRoom;
|
||||||
import net.minestom.server.MinecraftServer;
|
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.Pos;
|
||||||
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;
|
||||||
import net.minestom.server.entity.damage.DamageType;
|
import net.minestom.server.entity.damage.DamageType;
|
||||||
import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
|
|
||||||
import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
|
|
||||||
import net.minestom.server.timer.Task;
|
import net.minestom.server.timer.Task;
|
||||||
import net.minestom.server.timer.TaskSchedule;
|
import net.minestom.server.timer.TaskSchedule;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@ -50,14 +44,14 @@ public abstract class Tower extends EntityCreature {
|
|||||||
protected float damage;
|
protected float damage;
|
||||||
protected int range;
|
protected int range;
|
||||||
protected TaskSchedule attackDelay;
|
protected TaskSchedule attackDelay;
|
||||||
private final Task shootTask;
|
private final Task attackTask;
|
||||||
|
|
||||||
public Tower(@NotNull EntityType entityType, int damage, double attacksPerSecond, int range) {
|
public Tower(@NotNull EntityType entityType, int damage, double attacksPerSecond, int range) {
|
||||||
super(entityType);
|
super(entityType);
|
||||||
this.damage = (float) damage / damageDivider;
|
this.damage = (float) damage / damageDivider;
|
||||||
this.range = range;
|
this.range = range;
|
||||||
this.attackDelay = TaskSchedule.millis((long) (1000/attacksPerSecond));
|
this.attackDelay = TaskSchedule.millis((long) (1000/attacksPerSecond));
|
||||||
this.shootTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> {
|
this.attackTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> {
|
||||||
EntityCreature nextEnemy = this.getNextEnemy();
|
EntityCreature nextEnemy = this.getNextEnemy();
|
||||||
if(nextEnemy == null) return this.attackDelay;
|
if(nextEnemy == null) return this.attackDelay;
|
||||||
this.lookAt(nextEnemy);
|
this.lookAt(nextEnemy);
|
||||||
@ -66,44 +60,10 @@ public abstract class Tower extends EntityCreature {
|
|||||||
}, TaskSchedule.immediate());
|
}, TaskSchedule.immediate());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void shootProjectile(EntityCreature enemy, EntityType projectileType, double power, double spread) {
|
@Override
|
||||||
EntityProjectile projectile = new EntityProjectile(this, projectileType);
|
protected void remove(boolean permanent) {
|
||||||
projectile.setView(this.getPosition().yaw(), this.getPosition().pitch());
|
this.attackTask.cancel();
|
||||||
projectile.setNoGravity(true);
|
super.remove(permanent);
|
||||||
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;
|
|
||||||
target.damage(DamageType.PLAYER_ATTACK, this.damage);
|
|
||||||
this.onProjectileHit(target);
|
|
||||||
projectile.remove();
|
|
||||||
})
|
|
||||||
.addListener(ProjectileCollideWithBlockEvent.class, event -> projectile.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onProjectileHit(EntityCreature enemy) {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TowerdefenseRoom getRoomInstance() {
|
|
||||||
return (TowerdefenseRoom) this.getInstance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable EntityCreature getNextEnemy() {
|
private @Nullable EntityCreature getNextEnemy() {
|
||||||
@ -140,10 +100,17 @@ public abstract class Tower extends EntityCreature {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected TowerdefenseRoom getRoomInstance() {
|
||||||
protected void remove(boolean permanent) {
|
return (TowerdefenseRoom) this.getInstance();
|
||||||
this.shootTask.cancel();
|
}
|
||||||
super.remove(permanent);
|
|
||||||
|
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);
|
protected abstract void attack(EntityCreature enemy);
|
||||||
|
@ -2,19 +2,18 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.tow
|
|||||||
|
|
||||||
import net.minestom.server.entity.EntityCreature;
|
import net.minestom.server.entity.EntityCreature;
|
||||||
import net.minestom.server.entity.EntityType;
|
import net.minestom.server.entity.EntityType;
|
||||||
import net.minestom.server.entity.damage.DamageType;
|
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import net.minestom.server.item.Material;
|
import net.minestom.server.item.Material;
|
||||||
|
|
||||||
public class ZombieTower extends Tower {
|
public class ZombieTower extends Tower {
|
||||||
public ZombieTower() {
|
public ZombieTower() {
|
||||||
super(EntityType.ZOMBIE, 3, 0.7, 4);
|
super(EntityType.ZOMBIE, 2, 0.7, 4);
|
||||||
this.setItemInMainHand(ItemStack.of(Material.IRON_SWORD));
|
this.setItemInMainHand(ItemStack.of(Material.IRON_SWORD));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void attack(EntityCreature enemy) {
|
protected void attack(EntityCreature enemy) {
|
||||||
this.swingMainHand();
|
this.swingMainHand();
|
||||||
enemy.damage(DamageType.PLAYER_ATTACK, this.damage);
|
this.causeDamage(enemy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user