diff --git a/dungeon/src/contrib/utils/components/skill/DamageProjectile.java b/dungeon/src/contrib/utils/components/skill/DamageProjectile.java index 837e2c203c..146962383e 100644 --- a/dungeon/src/contrib/utils/components/skill/DamageProjectile.java +++ b/dungeon/src/contrib/utils/components/skill/DamageProjectile.java @@ -16,6 +16,9 @@ import core.utils.components.MissingComponentException; import core.utils.components.path.IPath; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.logging.Logger; @@ -29,6 +32,7 @@ public abstract class DamageProjectile implements Consumer { private static final Consumer DEFAULT_ON_WALL_HIT = Game::remove; + private static final BiConsumer DEFAULT_ON_ENTITY_HIT = (a, b) -> {}; private static final Logger LOGGER = Logger.getLogger(DamageProjectile.class.getSimpleName()); private final IPath pathToTexturesOfProjectile; private final float projectileSpeed; @@ -38,15 +42,27 @@ public abstract class DamageProjectile implements Consumer { private final Point projectileHitBoxSize; private final Supplier selectionFunction; private final Consumer onWallHit; + private final String name; + private static int nextId = 0; + private final List ignoreEntities = new ArrayList<>(); /** - * The DamageProjectile constructor sets the path to the textures of the projectile, the speed of - * the projectile, the damage amount and type to be dealt, the size of the projectile's hit box, - * the target selection function, the range of the projectile, and the behavior when a wall is - * hit. + * The behavior when an entity is hit. (The first parameter is the projectile, the second the + * entity that was hit) + */ + private final BiConsumer onEntityHit; + + private int tintColor = -1; // -1 means no tint + + /** + * The DamageProjectile constructor sets the name, the path to the textures of the projectile, the + * speed of the projectile, the damage amount and type to be dealt, the size of the projectile's + * hit box, the target selection function, the range of the projectile, and the behavior when a + * wall is hit. * *

For a specific implementation, see {@link FireballSkill}. * + * @param name Name of the projectile. * @param pathToTexturesOfProjectile Path to the textures of the projectile. * @param projectileSpeed Speed of the projectile. * @param damageAmount Amount of damage to be dealt. @@ -55,8 +71,10 @@ public abstract class DamageProjectile implements Consumer { * @param selectionFunction Specific functionality of the projectile. * @param projectileRange Range in which the projectile is effective. * @param onWallHit Behavior when a wall is hit. + * @param onEntityHit Behavior when an entity is hit before the damage is applied. */ public DamageProjectile( + final String name, final IPath pathToTexturesOfProjectile, float projectileSpeed, int damageAmount, @@ -64,7 +82,9 @@ public DamageProjectile( final Point projectileHitBoxSize, final Supplier selectionFunction, float projectileRange, - final Consumer onWallHit) { + final Consumer onWallHit, + final BiConsumer onEntityHit) { + this.name = name + "_" + nextId++; this.pathToTexturesOfProjectile = pathToTexturesOfProjectile; this.damageAmount = damageAmount; this.damageType = damageType; @@ -73,6 +93,45 @@ public DamageProjectile( this.projectileHitBoxSize = projectileHitBoxSize; this.selectionFunction = selectionFunction; this.onWallHit = onWallHit; + this.onEntityHit = onEntityHit; + } + + /** + * The DamageProjectile constructor sets the name, the path to the textures of the projectile, the + * speed of the projectile, the damage amount and type to be dealt, the size of the projectile's + * hit box, the target selection function, and the range of the projectile. + * + *

For a specific implementation, see {@link FireballSkill} + * + * @param name Name of the projectile. + * @param pathToTexturesOfProjectile Path to the textures of the projectile. + * @param projectileSpeed Speed of the projectile. + * @param damageAmount Amount of damage to be dealt. + * @param damageType Type of damage to be dealt. + * @param projectileHitBoxSize Size of the hit box. + * @param selectionFunction Specific functionality of the projectile. + * @param projectileRange Range in which the projectile is effective. + */ + public DamageProjectile( + String name, + final IPath pathToTexturesOfProjectile, + float projectileSpeed, + int damageAmount, + final DamageType damageType, + final Point projectileHitBoxSize, + final Supplier selectionFunction, + float projectileRange) { + this( + name, + pathToTexturesOfProjectile, + projectileSpeed, + damageAmount, + damageType, + projectileHitBoxSize, + selectionFunction, + projectileRange, + DEFAULT_ON_WALL_HIT, + DEFAULT_ON_ENTITY_HIT); } /** @@ -99,14 +158,14 @@ public DamageProjectile( final Supplier selectionFunction, float projectileRange) { this( + "DamageProjectile", pathToTexturesOfProjectile, projectileSpeed, damageAmount, damageType, projectileHitBoxSize, selectionFunction, - projectileRange, - DEFAULT_ON_WALL_HIT); + projectileRange); } /** @@ -124,7 +183,7 @@ public DamageProjectile( */ @Override public void accept(final Entity entity) { - Entity projectile = new Entity("Projectile"); + Entity projectile = new Entity(name); // Get the PositionComponent of the entity PositionComponent epc = entity @@ -133,7 +192,9 @@ public void accept(final Entity entity) { projectile.add(new PositionComponent(epc.position())); try { - projectile.add(new DrawComponent(pathToTexturesOfProjectile)); + DrawComponent dc = new DrawComponent(pathToTexturesOfProjectile); + dc.tintColor(tintColor()); + projectile.add(dc); } catch (IOException e) { LOGGER.warning( String.format("The DrawComponent for the projectile %s cant be created. ", entity) @@ -169,10 +230,11 @@ public void accept(final Entity entity) { // Create a collision handler for the projectile TriConsumer collide = (a, b, from) -> { - if (b != entity) { + if (b != entity && !ignoreEntities.contains(b)) { b.fetch(HealthComponent.class) .ifPresent( hc -> { + onEntityHit.accept(projectile, b); // Apply the projectile damage to the collided entity hc.receiveHit(new Damage(damageAmount, damageType, entity)); @@ -190,6 +252,44 @@ public void accept(final Entity entity) { playSound(); } + /** + * Adds an entity to the list of entities to be ignored by the projectile. Entities in this list + * will not be affected by the projectile's collision handler. + * + * @param entity The entity to be ignored by the projectile. + */ + public void ignoreEntity(Entity entity) { + ignoreEntities.add(entity); + } + + /** + * Removes an entity from the list of entities to be ignored by the projectile. Entities not in + * this list will be affected by the projectile's collision handler. + * + * @param entity The entity to be removed from the ignore list. + */ + public void removeIgnoredEntity(Entity entity) { + ignoreEntities.remove(entity); + } + /** Override this method to play a Sound-effect on spawning the projectile if you want. */ protected void playSound() {} + + /** + * Sets the tint color of the projectile. Set to -1 to remove the tint. + * + * @param tintColor The tint color of the projectile. + */ + public void tintColor(int tintColor) { + this.tintColor = tintColor; + } + + /** + * Returns the tint color of the projectile. + * + * @return The tint color of the projectile. -1 means no tint. + */ + public int tintColor() { + return tintColor; + } } diff --git a/dungeon/src/contrib/utils/components/skill/FireballSkill.java b/dungeon/src/contrib/utils/components/skill/FireballSkill.java index 6ec6104c20..6afc28ac90 100644 --- a/dungeon/src/contrib/utils/components/skill/FireballSkill.java +++ b/dungeon/src/contrib/utils/components/skill/FireballSkill.java @@ -21,13 +21,14 @@ */ public final class FireballSkill extends DamageProjectile { + private static final String SKILL_NAME = "fireball"; private static final IPath PROJECTILE_TEXTURES = new SimpleIPath("skills/fireball"); private static final IPath PROJECTILE_SOUND = new SimpleIPath("sounds/fireball.wav"); - private static final float PROJECTILE_SPEED = 15.0f; - private static final int DAMAGE_AMOUNT = 5; + private static final float DEFAULT_PROJECTILE_SPEED = 15.0f; + private static final int DEFAULT_DAMAGE_AMOUNT = 5; + private static final float DEFAULT_PROJECTILE_RANGE = 7f; private static final DamageType DAMAGE_TYPE = DamageType.FIRE; private static final Point HIT_BOX_SIZE = new Point(1, 1); - private static final float PROJECTILE_RANGE = 7f; /** * Create a {@link DamageProjectile} that looks like a fireball and will cause fire damage. @@ -36,14 +37,33 @@ public final class FireballSkill extends DamageProjectile { * @see DamageProjectile */ public FireballSkill(final Supplier targetSelection) { + this( + targetSelection, DEFAULT_PROJECTILE_RANGE, DEFAULT_PROJECTILE_SPEED, DEFAULT_DAMAGE_AMOUNT); + } + + /** + * Creates a new FireballSkill with the specified target selection, range, speed, and damage + * amount. The target selection is a function used to select the point where the projectile should + * fly to. The range is the maximum distance the projectile can travel. The speed is the speed at + * which the projectile travels. The damage amount is the amount of damage the projectile will + * deal upon impact. + * + * @param targetSelection A function used to select the point where the projectile should fly to. + * @param range The maximum distance the projectile can travel. + * @param speed The speed at which the projectile travels. + * @param damageAmount The amount of damage the projectile will deal upon impact. + */ + public FireballSkill( + final Supplier targetSelection, float range, float speed, int damageAmount) { super( + SKILL_NAME, PROJECTILE_TEXTURES, - PROJECTILE_SPEED, - DAMAGE_AMOUNT, + speed, + damageAmount, DAMAGE_TYPE, HIT_BOX_SIZE, targetSelection, - PROJECTILE_RANGE); + range); } @Override diff --git a/dungeon/src/contrib/utils/components/skill/Skill.java b/dungeon/src/contrib/utils/components/skill/Skill.java index 2529b56099..0d756418c3 100644 --- a/dungeon/src/contrib/utils/components/skill/Skill.java +++ b/dungeon/src/contrib/utils/components/skill/Skill.java @@ -21,7 +21,7 @@ public class Skill { private final Consumer skillFunction; - private final long coolDownInMilliSeconds; + private long coolDownInMilliSeconds; private Instant lastUsed; private Instant nextUsableAt = Instant.now(); @@ -64,6 +64,24 @@ public boolean canBeUsedAgain() { return !(Duration.between(Instant.now(), nextUsableAt).toMillis() > 0); } + /** + * Sets the cooldown of this skill. + * + * @param newCoolDown The new cooldown in milliseconds. + */ + public void cooldown(long newCoolDown) { + this.coolDownInMilliSeconds = newCoolDown; + } + + /** + * Returns the cooldown of this skill. + * + * @return int The cooldown in milliseconds. + */ + public long cooldown() { + return coolDownInMilliSeconds; + } + /** * Adds coolDownInMilliSeconds to the time the skill was last used and updates when this skill can * be used again. @@ -71,4 +89,14 @@ public boolean canBeUsedAgain() { private void activateCoolDown() { nextUsableAt = lastUsed.plusMillis(coolDownInMilliSeconds); } + + /** + * Sets the last used time to now. + * + *

This method is used to reset the cool down of the skill. + */ + public void setLastUsedToNow() { + this.lastUsed = Instant.now(); + activateCoolDown(); + } }