diff --git a/src/main/java/cz/jzitnik/game/mobs/HittableMob.java b/src/main/java/cz/jzitnik/game/mobs/HittableMob.java index 9ce6226..0cc4cf2 100644 --- a/src/main/java/cz/jzitnik/game/mobs/HittableMob.java +++ b/src/main/java/cz/jzitnik/game/mobs/HittableMob.java @@ -1,15 +1,54 @@ package cz.jzitnik.game.mobs; +import com.googlecode.lanterna.TerminalPosition; +import cz.jzitnik.annotations.injectors.InjectConfig; +import cz.jzitnik.annotations.injectors.InjectDependency; +import cz.jzitnik.annotations.injectors.InjectState; +import cz.jzitnik.config.Debugging; +import cz.jzitnik.events.FullRoomDraw; +import cz.jzitnik.events.RerenderScreen; +import cz.jzitnik.game.GameRoom; +import cz.jzitnik.game.GameState; +import cz.jzitnik.game.Player; +import cz.jzitnik.game.ResourceManager; import cz.jzitnik.game.utils.RoomCords; +import cz.jzitnik.states.ScreenBuffer; +import cz.jzitnik.states.TerminalState; import cz.jzitnik.utils.DependencyManager; +import cz.jzitnik.utils.RerenderUtils; +import cz.jzitnik.utils.events.EventManager; import cz.jzitnik.utils.roomtasks.RoomTask; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import java.awt.image.BufferedImage; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; @Slf4j public abstract class HittableMob extends Mob { + public abstract void onKilled(); + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); protected int health; + private ScheduledFuture currentTimeoutHitAnimation = null; + + @Getter + private boolean hitAnimationOn = false; + + @InjectDependency + private EventManager eventManager; + @InjectState + private GameState gameState; + @InjectDependency + private ResourceManager resourceManager; + @InjectState + private TerminalState terminalState; + @InjectState + private ScreenBuffer screenBuffer; + @InjectConfig + private Debugging debugging; public HittableMob(BufferedImage texture, RoomTask task, RoomCords cords, int initialHealth) { super(texture, task, cords); @@ -18,16 +57,71 @@ public abstract class HittableMob extends Mob { @Override public void interact(DependencyManager dm) { + dm.inject(this); + // TODO: Swords in hand will deal more damage, for now deal always one health--; log.debug("Health: {}", health); if (health <= 0) { + onKilled(); + gameState.getCurrentRoom().getMobs().remove(this); + rerender(); return; } - // play animation + if (hitAnimationOn) { + if (currentTimeoutHitAnimation != null && !currentTimeoutHitAnimation.isDone()) { + currentTimeoutHitAnimation.cancel(false); + } + } else { + hitAnimationOn = true; + log.debug("Hitting start"); + rerender(); + } + currentTimeoutHitAnimation = scheduler.schedule(() -> { + hitAnimationOn = false; + log.debug("Hitting end"); + rerender(); + }, 250, TimeUnit.MILLISECONDS); + } + + private void rerender() { + int forStartX = cords.getX(); + int forStartY = cords.getY(); + int forEndX = cords.getX() + texture.getWidth() - 1; + int forEndY = cords.getY() + texture.getHeight(); + + GameRoom currentRoom = gameState.getCurrentRoom(); + BufferedImage room = resourceManager.getResource(currentRoom.getTexture()); + Player player = gameState.getPlayer(); + BufferedImage playerTexture = RerenderUtils.getPlayer(resourceManager, player); + + var start = RerenderUtils.getStart(room, terminalState.getTerminalScreen().getTerminalSize()); + int startX = start.getX(); + int startY = start.getY(); + + RerenderUtils.rerenderPart( + forStartX, + forEndX, + forStartY, + forEndY, + startX, + startY, + currentRoom, + room, + player, + playerTexture, + screenBuffer, + resourceManager, + debugging + ); + + eventManager.emitEvent(new RerenderScreen(new RerenderScreen.ScreenPart( + new TerminalPosition(forStartX, forStartY), + new TerminalPosition(forEndX * 2 + 1 + startX, forEndY + startY) + ))); } } diff --git a/src/main/java/cz/jzitnik/game/mobs/Mob.java b/src/main/java/cz/jzitnik/game/mobs/Mob.java index 64445ab..e9c184f 100644 --- a/src/main/java/cz/jzitnik/game/mobs/Mob.java +++ b/src/main/java/cz/jzitnik/game/mobs/Mob.java @@ -13,9 +13,9 @@ import java.awt.image.BufferedImage; @Getter @RequiredArgsConstructor public abstract class Mob implements Renderable, Selectable { - private final BufferedImage texture; + protected final BufferedImage texture; private final RoomTask task; - private final RoomCords cords; + protected final RoomCords cords; @Setter private boolean selected = false; diff --git a/src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java b/src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java index 3bace8f..7dbab49 100644 --- a/src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java +++ b/src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java @@ -3,10 +3,17 @@ package cz.jzitnik.game.setup.mobs; import cz.jzitnik.game.ResourceManager; import cz.jzitnik.game.mobs.HittableMob; import cz.jzitnik.game.utils.RoomCords; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class Zombie extends HittableMob { public Zombie(ResourceManager resourceManager, RoomCords cords) { super(resourceManager.getResource(ResourceManager.Resource.CHEST), null, cords, 10); } + + @Override + public void onKilled() { + log.debug("Zombie killed"); + } } diff --git a/src/main/java/cz/jzitnik/utils/RerenderUtils.java b/src/main/java/cz/jzitnik/utils/RerenderUtils.java index 7d9ca04..7e4326a 100644 --- a/src/main/java/cz/jzitnik/utils/RerenderUtils.java +++ b/src/main/java/cz/jzitnik/utils/RerenderUtils.java @@ -7,6 +7,7 @@ import cz.jzitnik.events.handlers.FullRoomDrawHandler; import cz.jzitnik.game.GameRoom; import cz.jzitnik.game.Player; import cz.jzitnik.game.ResourceManager; +import cz.jzitnik.game.mobs.HittableMob; import cz.jzitnik.game.mobs.Mob; import cz.jzitnik.game.objects.GameObject; import cz.jzitnik.game.utils.RoomCords; @@ -21,6 +22,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +@Slf4j public class RerenderUtils { public static RoomCords getStart(BufferedImage room, TerminalSize terminalSize) { int width = room.getWidth(); @@ -96,9 +98,13 @@ public class RerenderUtils { int g = (pixel >> 8) & 0xff; int b = pixel & 0xff; float factor = 1.5f; // brightness multiplier + float redFactor = 2f; if (alpha != 0) { - if (isSelected) { + if (object instanceof HittableMob mob && mob.isHitAnimationOn()) { + r = Math.min(255, (int)(r * redFactor)); + pixel = (alpha << 24) | (r << 16) | (g << 8) | b; + } else if (isSelected) { r = Math.min(255, (int)(r * factor)); g = Math.min(255, (int)(g * factor)); b = Math.min(255, (int)(b * factor));