docs: Add javadoc

This commit is contained in:
2026-02-24 21:01:32 +01:00
parent f2b6200355
commit 6710426fad
195 changed files with 3162 additions and 3 deletions

View File

@@ -1,5 +1,10 @@
package cz.jzitnik.common;
/**
* Configuration constants for the common module.
*
* @author Jakub Žitník (jzitnik)
*/
public class Config {
public static final int WORLD_PASSWORD_LENGTH = 5;
}

View File

@@ -10,6 +10,11 @@ import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.util.List;
/**
* Represents coordinates in a room.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
@ToString
@Getter
@@ -17,6 +22,12 @@ public class RoomCords implements Cloneable, Serializable {
private int x;
private int y;
/**
* Calculates the center coordinate based on a texture's dimensions.
*
* @param texture The texture to calculate the center for
* @return A new RoomCords instance representing the center
*/
public RoomCords calculateCenter(BufferedImage texture) {
return new RoomCords(
x + texture.getWidth() / 2,
@@ -24,6 +35,12 @@ public class RoomCords implements Cloneable, Serializable {
);
}
/**
* Constructs RoomCords with specified x and y values.
*
* @param x The x coordinate
* @param y The y coordinate
*/
@JsonCreator
public RoomCords(
@JsonProperty("x") int x,
@@ -32,15 +49,34 @@ public class RoomCords implements Cloneable, Serializable {
updateCords(x, y);
}
/**
* Updates the coordinates with new x and y values.
*
* @param x The new x coordinate
* @param y The new y coordinate
*/
public void updateCords(int x, int y) {
this.x = x;
this.y = y;
}
/**
* Updates the coordinates using another RoomCords instance.
*
* @param roomCords The RoomCords instance to copy values from
*/
public void updateCords(RoomCords roomCords) {
updateCords(roomCords.getX(), roomCords.getY());
}
/**
* Updates the coordinates only if the new position does not collide with specified colliders.
*
* @param colliders The list of colliders in the room
* @param x The target x coordinate
* @param y The target y coordinate
* @param playerCollider The collider of the player
*/
public void updateCordsWithColliders(List<RoomPart> colliders, int x, int y, RoomPart playerCollider) {
var normalizedPlayerCollider = new RoomPart(
new RoomCords(playerCollider.getStart().getX() + x, playerCollider.getStart().getY() + y),
@@ -53,6 +89,11 @@ public class RoomCords implements Cloneable, Serializable {
updateCords(x, y);
}
/**
* Creates and returns a copy of this object.
*
* @return A clone of this instance
*/
@Override
public RoomCords clone() {
try {

View File

@@ -7,12 +7,23 @@ import lombok.ToString;
import java.io.Serializable;
/**
* Represents a rectangular part of a room, defined by start and end coordinates.
*
* @author Jakub Žitník (jzitnik)
*/
@Data
@ToString
public class RoomPart implements Serializable {
private RoomCords start;
private RoomCords end;
/**
* Constructs a RoomPart with specified start and end coordinates.
*
* @param start The start coordinates (top-left)
* @param end The end coordinates (bottom-right)
*/
@JsonCreator
public RoomPart(
@JsonProperty("start") RoomCords start,
@@ -22,6 +33,12 @@ public class RoomPart implements Serializable {
this.end = end;
}
/**
* Checks if the given coordinates are within this room part.
*
* @param cords The coordinates to check
* @return true if the coordinates are within this part, false otherwise
*/
public boolean isWithin(RoomCords cords) {
return cords.getX() >= start.getX() &&
cords.getX() <= end.getX() &&
@@ -30,7 +47,10 @@ public class RoomPart implements Serializable {
}
/**
* Checks if this GameRoomPart overlaps with another.
* Checks if this RoomPart overlaps with another.
*
* @param other The other RoomPart to check for overlap
* @return true if it overlaps, false otherwise
*/
public boolean isOverlapping(RoomPart other) {
return start.getX() <= other.getEnd().getX() &&

View File

@@ -9,6 +9,11 @@ import lombok.Setter;
import java.io.Serializable;
/**
* Data required for player creation.
*
* @author Jakub Žitník (jzitnik)
*/
@Getter
public final class PlayerCreation implements Serializable {
@Setter
@@ -16,6 +21,12 @@ public final class PlayerCreation implements Serializable {
private final RoomCords playerCords;
private final RoomPart collider;
/**
* Constructs a PlayerCreation instance.
*
* @param playerCords The player's initial coordinates
* @param collider The player's collider
*/
@JsonCreator
public PlayerCreation(
@JsonProperty("playerCords") RoomCords playerCords,

View File

@@ -2,5 +2,10 @@ package cz.jzitnik.common.socket;
import java.io.Serializable;
/**
* Base interface for all messages sent over the socket.
*
* @author Jakub Žitník (jzitnik)
*/
public interface SocketMessage extends Serializable {
}

View File

@@ -2,5 +2,10 @@ package cz.jzitnik.common.socket.messages;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Test message for socket communication.
*
* @author Jakub Žitník (jzitnik)
*/
public class Test implements SocketMessage {
}

View File

@@ -2,5 +2,10 @@ package cz.jzitnik.common.socket.messages.game;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Message indicating that the game has been won.
*
* @author Jakub Žitník (jzitnik)
*/
public record GameWin() implements SocketMessage {
}

View File

@@ -2,5 +2,11 @@ package cz.jzitnik.common.socket.messages.game;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Message indicating that a player has died.
*
* @param playerId The ID of the player who died.
* @author Jakub Žitník (jzitnik)
*/
public record PlayerDeath(int playerId) implements SocketMessage {
}

View File

@@ -2,5 +2,11 @@ package cz.jzitnik.common.socket.messages.game.connection;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Message sent to request connection to a game.
*
* @param gamePass The password of the game to connect to.
* @author Jakub Žitník (jzitnik)
*/
public record ConnectToAGame(String gamePass) implements SocketMessage {
}

View File

@@ -5,20 +5,45 @@ import cz.jzitnik.common.socket.SocketMessage;
import java.util.List;
/**
* Response message sent after a connection request to a game.
*
* @param responseType The type of response (SUCCESS or GAME_DOES_NOT_EXIST).
* @param playerCreation Information about the player being created.
* @param existingPlayers List of existing players in the game.
* @author Jakub Žitník (jzitnik)
*/
public record ConnectToAGameResponse(ResponseType responseType, PlayerCreation playerCreation, List<PlayerCreation> existingPlayers) implements SocketMessage {
/**
* Enum representing the possible response types for game connection.
*/
private enum ResponseType {
GAME_DOES_NOT_EXIST,
SUCCESS
}
/**
* Default constructor representing a failed connection (game does not exist).
*/
public ConnectToAGameResponse() {
this(ResponseType.GAME_DOES_NOT_EXIST, null, null);
}
/**
* Constructor for a successful connection.
*
* @param playerCreation Information about the player being created.
* @param existingPlayers List of existing players in the game.
*/
public ConnectToAGameResponse(PlayerCreation playerCreation, List<PlayerCreation> existingPlayers) {
this(ResponseType.SUCCESS, playerCreation, existingPlayers);
}
/**
* Checks if the connection was successful.
*
* @return true if successful, false otherwise.
*/
public boolean success() {
return responseType == ResponseType.SUCCESS;
}

View File

@@ -2,5 +2,10 @@ package cz.jzitnik.common.socket.messages.game.creation;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Message sent to request game creation.
*
* @author Jakub Žitník (jzitnik)
*/
public class CreateGame implements SocketMessage {
}

View File

@@ -5,6 +5,11 @@ import cz.jzitnik.common.socket.SocketMessage;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Response message sent after a game is created.
*
* @author Jakub Žitník (jzitnik)
*/
@Getter
@AllArgsConstructor
public class CreateGameResponse implements SocketMessage {

View File

@@ -2,6 +2,13 @@ package cz.jzitnik.common.socket.messages.items;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Message indicating that an item was taken from a chest.
*
* @param roomId The ID of the room where the chest is located.
* @param id The ID of the item taken.
* @author Jakub Žitník (jzitnik)
*/
public record ItemTookFromChest(
String roomId, // For faster lookup i guess
int id

View File

@@ -3,6 +3,16 @@ package cz.jzitnik.common.socket.messages.player;
import cz.jzitnik.common.models.coordinates.RoomCords;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Message sent when a player's arrival status in a room changes.
*
* @param id The ID of the player.
* @param playerCords The current coordinates of the player.
* @param playerRotation The current rotation of the player.
* @param arrived Whether the player has arrived or departed.
* @param rerender Whether a rerender is requested.
* @author Jakub Žitník (jzitnik)
*/
public record PlayerArrivalChange(int id, RoomCords playerCords, PlayerRotation playerRotation,
boolean arrived, boolean rerender) implements SocketMessage {
}

View File

@@ -2,5 +2,11 @@ package cz.jzitnik.common.socket.messages.player;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Message indicating that a player has disconnected.
*
* @param playerId The ID of the player who disconnected.
* @author Jakub Žitník (jzitnik)
*/
public record PlayerDisconnected(int playerId) implements SocketMessage {
}

View File

@@ -3,5 +3,11 @@ package cz.jzitnik.common.socket.messages.player;
import cz.jzitnik.common.models.player.PlayerCreation;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Message indicating that a new player has joined the game.
*
* @param playerCreation Information about the player who joined.
* @author Jakub Žitník (jzitnik)
*/
public record PlayerJoined(PlayerCreation playerCreation) implements SocketMessage {
}

View File

@@ -3,5 +3,12 @@ package cz.jzitnik.common.socket.messages.player;
import cz.jzitnik.common.models.coordinates.RoomCords;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Message sent when a player moves.
*
* @param newCords The new coordinates of the player.
* @param playerRotation The rotation of the player.
* @author Jakub Žitník (jzitnik)
*/
public record PlayerMove(RoomCords newCords, PlayerRotation playerRotation) implements SocketMessage {
}

View File

@@ -5,6 +5,11 @@ import cz.jzitnik.common.socket.SocketMessage;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Message sent when another player moves within the same room.
*
* @author Jakub Žitník (jzitnik)
*/
@Getter
@AllArgsConstructor
public class PlayerMovedInUrRoom implements SocketMessage {

View File

@@ -1,5 +1,10 @@
package cz.jzitnik.common.socket.messages.player;
/**
* Enum representing the possible rotations of a player.
*
* @author Jakub Žitník (jzitnik)
*/
public enum PlayerRotation {
FRONT, BACK, LEFT, RIGHT
}

View File

@@ -3,6 +3,14 @@ package cz.jzitnik.common.socket.messages.room;
import cz.jzitnik.common.models.coordinates.RoomCords;
import cz.jzitnik.common.socket.SocketMessage;
/**
* Message sent to request moving a player to a new room.
*
* @param newRoomId The ID of the room to move to.
* @param oldCords The coordinates in the old room.
* @param newCords The initial coordinates in the new room.
* @author Jakub Žitník (jzitnik)
*/
public record MovePlayerRoom(String newRoomId, RoomCords oldCords, RoomCords newCords) implements SocketMessage {
}

View File

@@ -9,13 +9,37 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Response message sent after a player moves to a different room.
*
* @param players Set of players currently in the new room.
* @author Jakub Žitník (jzitnik)
*/
public record MovePlayerRoomResponse(Set<Registry> players) implements SocketMessage {
/**
* Represents a registry of a player in a room.
*
* @param id The ID of the player.
* @param cords The coordinates of the player.
* @param playerRotation The rotation of the player.
*/
public record Registry(int id, RoomCords cords, PlayerRotation playerRotation) implements Serializable {}
/**
* Gets a player's registry by their ID.
*
* @param id The ID of the player to find.
* @return An Optional containing the registry if found, otherwise empty.
*/
public Optional<Registry> getById(int id) {
return players.stream().filter(registry -> registry.id == id).findFirst();
}
/**
* Gets the set of IDs of all players in the response.
*
* @return A Set of player IDs.
*/
public Set<Integer> getIds() {
return players.stream().map(Registry::id).collect(Collectors.toSet());
}

View File

@@ -17,6 +17,11 @@ import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
/**
* Command line interface handler using Lanterna.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
@Dependency
public class Cli implements Runnable {
@@ -29,6 +34,9 @@ public class Cli implements Runnable {
@InjectState
private RunningState runningState;
/**
* Runs the CLI thread, handling terminal input and events.
*/
@Override
public void run() {
// Start event manager thread

View File

@@ -14,6 +14,11 @@ import org.reflections.Reflections;
import java.io.IOException;
/**
* Main game class responsible for initialization and starting the game loop.
*
* @author Jakub Žitník (jzitnik)
*/
public class Game {
private final DependencyManager dependencyManager = new DependencyManager(new Reflections("cz.jzitnik.client"));
@@ -32,6 +37,11 @@ public class Game {
@InjectDependency
private GlobalIOHandlerRepository globalIOHandlerRepository;
/**
* Starts the game by injecting dependencies and initializing managers.
*
* @throws IOException If an I/O error occurs
*/
public void start() throws IOException {
dependencyManager.inject(this);

View File

@@ -4,7 +4,18 @@ package cz.jzitnik.client;
import java.io.IOException;
/**
* Main entry point for the client application.
*
* @author Jakub Žitník (jzitnik)
*/
public class Main {
/**
* Main method that starts the game.
*
* @param args Command line arguments
* @throws IOException If an I/O error occurs
*/
public static void main(String[] args) throws IOException {
new Game().start();
}

View File

@@ -5,8 +5,18 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Annotation to mark a class as a configuration component loaded from a YAML file.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Config {
/**
* The YAML file name.
*
* @return file name
*/
String value();
}

View File

@@ -5,9 +5,18 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Annotation to mark a class as a dependency for the DependencyManager.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Dependency {
/** Custom alias **/
/**
* Custom alias for the dependency.
*
* @return Alias class
*/
Class<?> value() default Object.class;
}

View File

@@ -7,8 +7,18 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Annotation to mark a class as an event handler for a specific Event type.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EventHandler {
/**
* The type of Event this handler handles.
*
* @return Event class
*/
Class<? extends Event> value();
}

View File

@@ -5,6 +5,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Annotation to mark a method to be called after dependency injection.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PostInit {

View File

@@ -6,9 +6,24 @@ import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.util.concurrent.TimeUnit;
/**
* Annotation to mark a task for periodic execution.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ScheduledTask {
/**
* Execution rate.
*
* @return rate
*/
long rate();
/**
* Time unit for the rate.
*
* @return rate unit
*/
TimeUnit rateUnit();
}

View File

@@ -7,8 +7,18 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to mark a class as a socket event handler for a specific SocketMessage type.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface SocketEventHandler {
/**
* The type of SocketMessage this handler handles.
*
* @return SocketMessage class
*/
Class<? extends SocketMessage> value();
}

View File

@@ -5,6 +5,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Annotation to mark a class as a state component.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface State {

View File

@@ -5,6 +5,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Annotation to mark a class for automatic thread registration.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ThreadRegistry {

View File

@@ -5,6 +5,11 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to inject a configuration component into a field.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface InjectConfig {

View File

@@ -5,6 +5,11 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to inject a dependency into a field.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface InjectDependency {

View File

@@ -5,6 +5,11 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to inject a state component into a field.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface InjectState {

View File

@@ -4,10 +4,25 @@ import com.googlecode.lanterna.input.KeyType;
import java.lang.annotation.*;
/**
* Annotation to mark a method as a keyboard press handler.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(KeyboardPressHandlers.class)
public @interface KeyboardPressHandler {
/**
* The key type to handle.
*
* @return key type
*/
KeyType keyType() default KeyType.Character;
/**
* The specific character to handle (if keyType is Character).
*
* @return character
*/
char character() default '\0';
}

View File

@@ -5,8 +5,18 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Container annotation for repeatable KeyboardPressHandler.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface KeyboardPressHandlers {
/**
* Array of KeyboardPressHandler annotations.
*
* @return handlers
*/
KeyboardPressHandler[] value();
}

View File

@@ -5,8 +5,18 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Annotation to mark a method as a mouse handler.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MouseHandler {
/**
* The type of mouse action to handle.
*
* @return handler type
*/
MouseHandlerType value();
}

View File

@@ -1,5 +1,10 @@
package cz.jzitnik.client.annotations.ui;
/**
* Enum representing types of mouse handlers.
*
* @author Jakub Žitník (jzitnik)
*/
public enum MouseHandlerType {
CLICK,
MOVE,

View File

@@ -5,6 +5,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Annotation to mark a method as a rendering method.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Render {

View File

@@ -5,6 +5,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Annotation to mark a class as a UI component.
*
* @author Jakub Žitník (jzitnik)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface UI {

View File

@@ -4,8 +4,19 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import cz.jzitnik.client.annotations.Config;
/**
* Configuration for core game logic.
*
* @param itemDropDisappearMinutes Minutes before a dropped item disappears
* @author Jakub Žitník (jzitnik)
*/
@Config("core_logic.yaml")
public record CoreLogic(int itemDropDisappearMinutes) {
/**
* Constructs a CoreLogic configuration instance.
*
* @param itemDropDisappearMinutes Disappear timeout in minutes
*/
@JsonCreator
public CoreLogic(
@JsonProperty("itemDropDisappearMinutes") int itemDropDisappearMinutes

View File

@@ -4,8 +4,23 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import cz.jzitnik.client.annotations.Config;
/**
* Configuration for debugging features.
*
* @param renderColliders Whether to render colliders
* @param renderPlayerCollider Whether to render the player's collider
* @param showPlayerCordsLogs Whether to show player coordinate logs
* @author Jakub Žitník (jzitnik)
*/
@Config("debugging.yaml")
public record Debugging(boolean renderColliders, boolean renderPlayerCollider, boolean showPlayerCordsLogs) {
/**
* Constructs a Debugging configuration instance.
*
* @param renderColliders Whether to render colliders
* @param renderPlayerCollider Whether to render the player's collider
* @param showPlayerCordsLogs Whether to show player coordinate logs
*/
@JsonCreator
public Debugging(
@JsonProperty("renderColliders") boolean renderColliders,

View File

@@ -4,8 +4,19 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import cz.jzitnik.client.annotations.Config;
/**
* Configuration for microphone input.
*
* @param volumeThreshold The volume threshold for activation
* @author Jakub Žitník (jzitnik)
*/
@Config("microphone.yaml")
public record MicrophoneConfig(float volumeThreshold) {
/**
* Constructs a MicrophoneConfig instance.
*
* @param volumeThreshold The volume threshold
*/
@JsonCreator
public MicrophoneConfig(
@JsonProperty("volumeThreshold") float volumeThreshold

View File

@@ -5,6 +5,18 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import cz.jzitnik.client.annotations.Config;
import cz.jzitnik.client.events.handlers.PlayerMoveEventHandler;
/**
* Configuration for player-related settings.
*
* @param playerReach The distance a player can reach
* @param playerMoveDistance The distance a player moves normally
* @param playerMoveDistanceSprinting The distance a player moves while sprinting
* @param sprintKey The key used for sprinting
* @param swingTimeMs Time in milliseconds for a weapon swing
* @param staminaIncreaseRateMs Rate at which stamina increases
* @param staminaDelayMs Delay before stamina starts increasing
* @author Jakub Žitník (jzitnik)
*/
@Config("player.yaml")
public record PlayerConfig(
double playerReach,
@@ -15,6 +27,17 @@ public record PlayerConfig(
int staminaIncreaseRateMs,
int staminaDelayMs
) {
/**
* Constructs a PlayerConfig instance.
*
* @param playerReach Player reach
* @param playerMoveDistance Move distance
* @param playerMoveDistanceSprinting Sprint move distance
* @param sprintKey Sprint key
* @param swingTimeMs Swing time
* @param staminaIncreaseRateMs Stamina increase rate
* @param staminaDelayMs Stamina delay
*/
@JsonCreator
public PlayerConfig(
@JsonProperty("playerReach") double playerReach,

View File

@@ -4,8 +4,21 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import cz.jzitnik.client.annotations.Config;
/**
* Configuration for thread pool sizes.
*
* @param eventThreadCount Number of threads for events
* @param taskThreadCount Number of threads for tasks
* @author Jakub Žitník (jzitnik)
*/
@Config("threads.yaml")
public record ThreadPoolConfig(int eventThreadCount, int taskThreadCount) {
/**
* Constructs a ThreadPoolConfig instance.
*
* @param eventThreadCount Event thread count
* @param taskThreadCount Task thread count
*/
@JsonCreator
public ThreadPoolConfig(
@JsonProperty("eventThreadCount") int eventThreadCount,

View File

@@ -2,6 +2,10 @@ package cz.jzitnik.client.events;
import cz.jzitnik.client.utils.events.Event;
/** Custom event without any handler **/
/**
* Event indicating that the application should exit.
*
* @author Jakub Žitník (jzitnik)
*/
public class ExitEvent implements Event {
}

View File

@@ -5,6 +5,11 @@ import cz.jzitnik.client.utils.events.Event;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Event triggered when a key is pressed.
*
* @author Jakub Žitník (jzitnik)
*/
@Getter
@AllArgsConstructor
public class KeyboardPressEvent implements Event {

View File

@@ -4,11 +4,28 @@ import com.googlecode.lanterna.TerminalPosition;
import com.googlecode.lanterna.input.MouseActionType;
import cz.jzitnik.client.utils.events.Event;
/**
* Event triggered by a mouse action.
*
* @author Jakub Žitník (jzitnik)
*/
public class MouseAction extends com.googlecode.lanterna.input.MouseAction implements Event {
/**
* Constructs a MouseAction.
*
* @param actionType The type of action
* @param button The button involved
* @param position The terminal position
*/
public MouseAction(MouseActionType actionType, int button, TerminalPosition position) {
super(actionType, button, position);
}
/**
* Constructs a MouseAction from an existing Lanterna MouseAction.
*
* @param mouseAction The Lanterna mouse action
*/
public MouseAction(com.googlecode.lanterna.input.MouseAction mouseAction) {
this(mouseAction.getActionType(), mouseAction.getButton(), mouseAction.getPosition());
}

View File

@@ -4,6 +4,11 @@ import cz.jzitnik.client.utils.events.Event;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Event triggered by a mouse movement.
*
* @author Jakub Žitník (jzitnik)
*/
@AllArgsConstructor
@Getter
public class MouseMoveEvent implements Event {

View File

@@ -5,6 +5,11 @@ import cz.jzitnik.client.utils.events.Event;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Event triggered when a player attempts to move.
*
* @author Jakub Žitník (jzitnik)
*/
@AllArgsConstructor
@Getter
public class PlayerMoveEvent implements Event {

View File

@@ -4,6 +4,11 @@ import cz.jzitnik.client.utils.events.Event;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Event requesting a rerender of a specific part of the screen.
*
* @author Jakub Žitník (jzitnik)
*/
@Getter
@AllArgsConstructor
public class RerenderPart implements Event {

View File

@@ -5,6 +5,11 @@ import cz.jzitnik.client.utils.events.Event;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Event triggered when the terminal is resized.
*
* @author Jakub Žitník (jzitnik)
*/
@AllArgsConstructor
@Getter
public class TerminalResizeEvent implements Event {

View File

@@ -2,5 +2,10 @@ package cz.jzitnik.client.events;
import cz.jzitnik.client.utils.events.Event;
/**
* Event triggered when the terminal window is too small to render the game.
*
* @author Jakub Žitník (jzitnik)
*/
public class TerminalTooSmallEvent implements Event {
}

View File

@@ -18,6 +18,11 @@ import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
/**
* Handler for the RerenderScreen event in the CLI.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
@EventHandler(RerenderScreen.class)
public class CliHandler extends AbstractEventHandler<RerenderScreen> {
@@ -30,6 +35,11 @@ public class CliHandler extends AbstractEventHandler<RerenderScreen> {
@InjectState
private RenderState renderState;
/**
* Handles the RerenderScreen event by drawing requested parts of the screen buffer to the terminal.
*
* @param event The RerenderScreen event
*/
@Override
public void handle(RerenderScreen event) {
if (renderState.isTerminalTooSmall()) {
@@ -79,6 +89,13 @@ public class CliHandler extends AbstractEventHandler<RerenderScreen> {
}
}
/**
* Resolves the final pixel color by blending with the global override buffer.
*
* @param buffer The base pixel from the rendered buffer
* @param globalOverride The pixel from the global override buffer
* @return The final pixel to draw
*/
private Pixel getPixel(Pixel buffer, AlphaPixel globalOverride) {
if (globalOverride instanceof Empty) {
return buffer;
@@ -97,6 +114,14 @@ public class CliHandler extends AbstractEventHandler<RerenderScreen> {
return new ColoredPixel(blended);
}
/**
* Blends two colors using an alpha value.
*
* @param base The base color
* @param overlay The overlay color
* @param alpha The alpha transparency of the overlay
* @return The blended color
*/
private TextColor blendColors(TextColor base, TextColor overlay, float alpha) {
int r = blend(base.getRed(), overlay.getRed(), alpha);
int g = blend(base.getGreen(), overlay.getGreen(), alpha);
@@ -105,10 +130,27 @@ public class CliHandler extends AbstractEventHandler<RerenderScreen> {
return new TextColor.RGB(r, g, b);
}
/**
* Internal helper to blend a single color channel.
*
* @param base Base channel value
* @param overlay Overlay channel value
* @param alpha Alpha transparency
* @return Blended channel value
*/
private int blend(int base, int overlay, float alpha) {
return Math.round(base * (1 - alpha) + overlay * alpha);
}
/**
* Draws a "half-pixel" using Unicode character '▄' to achieve higher vertical resolution.
*
* @param tg The TextGraphics context
* @param x X terminal position
* @param y Y terminal position
* @param topColor Color for the top half
* @param bottomColor Color for the bottom half
*/
private void drawHalfPixel(TextGraphics tg, int x, int y,
TextColor topColor,
TextColor bottomColor) {

View File

@@ -26,6 +26,11 @@ import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* Handler for the Dialog event.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
@EventHandler(Dialog.class)
public class DialogEventHandler extends AbstractEventHandler<Dialog> {
@@ -53,13 +58,23 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
private static final int WIDTH = 350;
private static final int MARGIN_BOTTOM = 15;
/** Padding for the dialog box. */
public static final int PADDING = 7;
private static final int BUTTON_TEXT_PADDING = 4;
private static final int QUESTION_ACTIONS_GAP = 10;
/** Height of a button in the dialog. */
public static final int BUTTON_HEIGHT = 15;
/** Padding for buttons in the dialog. */
public static final int BUTTON_PADDING = 5;
private static final float FONT_SIZE = 15f;
/**
* Calculates the total height required for buttons in a dialog.
*
* @param dialog The dialog
* @param gameState Current game state
* @return Calculated height
*/
public static int calculateButtonHeight(Dialog dialog, GameState gameState) {
if (dialog.getOnEnd() instanceof OnEnd.AskQuestion askQuestion) {
int count = askQuestion.answers(gameState).length;
@@ -68,6 +83,13 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
return 0;
}
/**
* Calculates the starting Y coordinate for buttons.
*
* @param textRenderer The text renderer
* @param dialog The dialog
* @return Starting Y coordinate
*/
public static int getYStartButtons(TextRenderer textRenderer, Dialog dialog) {
var textSize = textRenderer.measureText(
dialog.getText(),
@@ -78,6 +100,14 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
return PADDING + textSize.height + BUTTON_PADDING;
}
/**
* Calculates the overall size of the dialog box.
*
* @param textRenderer The text renderer
* @param dialog The dialog
* @param gameState Current game state
* @return The terminal size
*/
public static TerminalSize getSize(TextRenderer textRenderer, Dialog dialog, GameState gameState) {
var textSize = textRenderer.measureText(
dialog.getText(),
@@ -96,12 +126,24 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
);
}
/**
* Calculates the starting terminal position for the dialog box.
*
* @param terminalSize Current terminal size
* @param size Size of the dialog box
* @return Starting position
*/
public static TerminalPosition getStart(TerminalSize terminalSize, TerminalSize size) {
int startY = terminalSize.getRows() * 2 - MARGIN_BOTTOM - size.getRows();
int startX = (terminalSize.getColumns() / 2) - (size.getColumns() / 2);
return new TerminalPosition(startX, startY);
}
/**
* Handles the Dialog event by rendering it with typing animation.
*
* @param event The Dialog event
*/
@Override
public void handle(Dialog event) {
boolean onlyLast = dialogState.getCurrentDialog() == event;

View File

@@ -10,11 +10,21 @@ import cz.jzitnik.client.utils.events.EventManager;
import java.awt.image.BufferedImage;
/**
* Handler for the DroppedItemRerender event.
*
* @author Jakub Žitník (jzitnik)
*/
@EventHandler(DroppedItemRerender.class)
public class DroppedItemRerenderHandler extends AbstractEventHandler<DroppedItemRerender> {
@InjectDependency
private EventManager eventManager;
/**
* Handles the DroppedItemRerender event by emitting a RerenderPart event.
*
* @param event The DroppedItemRerender event
*/
@Override
public void handle(DroppedItemRerender event) {
RoomCords droppedItemCords = event.droppedItem().getCords();

View File

@@ -10,6 +10,11 @@ import cz.jzitnik.client.utils.ThreadManager;
import cz.jzitnik.client.utils.events.AbstractEventHandler;
import cz.jzitnik.client.utils.roomtasks.RoomTaskScheduler;
/**
* Handler for the ExitEvent.
*
* @author Jakub Žitník (jzitnik)
*/
@EventHandler(ExitEvent.class)
public class ExitEventHandler extends AbstractEventHandler<ExitEvent> {
@InjectDependency
@@ -24,6 +29,11 @@ public class ExitEventHandler extends AbstractEventHandler<ExitEvent> {
@InjectDependency
private ScheduledTaskManager scheduledTaskManager;
/**
* Handles the ExitEvent by shutting down all managers and setting the running state to false.
*
* @param event The ExitEvent
*/
@Override
public void handle(ExitEvent event) {
threadManager.shutdownAll();

View File

@@ -12,6 +12,11 @@ import cz.jzitnik.client.utils.events.EventManager;
import java.io.IOException;
/**
* Handler for the FullRedrawEvent.
*
* @author Jakub Žitník (jzitnik)
*/
@EventHandler(FullRedrawEvent.class)
public class FullRedrawEventHandler extends AbstractEventHandler<FullRedrawEvent> {
@InjectDependency
@@ -20,6 +25,11 @@ public class FullRedrawEventHandler extends AbstractEventHandler<FullRedrawEvent
@InjectState
private TerminalState terminalState;
/**
* Handles the FullRedrawEvent by clearing the terminal and emitting a FullRoomDraw event.
*
* @param event The FullRedrawEvent
*/
@Override
public void handle(FullRedrawEvent event) {
terminalState.getTerminalScreen().clear();

View File

@@ -32,6 +32,11 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Handler for the FullRoomDraw event.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
@EventHandler(FullRoomDraw.class)
public class FullRoomDrawHandler extends AbstractEventHandler<FullRoomDraw> {
@@ -55,6 +60,11 @@ public class FullRoomDrawHandler extends AbstractEventHandler<FullRoomDraw> {
@InjectDependency
private GlobalIOHandlerRepository globalIOHandlerRepository;
/**
* Handles the FullRoomDraw event by rendering the entire room and players.
*
* @param event The FullRoomDraw event
*/
@Override
public void handle(FullRoomDraw event) {
try {
@@ -103,6 +113,9 @@ public class FullRoomDrawHandler extends AbstractEventHandler<FullRoomDraw> {
}
}
/**
* Enum representing door positions in a room.
*/
public enum DoorPosition {
TOP,
LEFT,

View File

@@ -9,6 +9,11 @@ import cz.jzitnik.client.ui.Inventory;
import cz.jzitnik.client.utils.events.AbstractEventHandler;
import cz.jzitnik.client.utils.events.EventManager;
/**
* Handler for the InventoryRerender event.
*
* @author Jakub Žitník (jzitnik)
*/
@EventHandler(InventoryRerender.class)
public class InventoryRerenderHandler extends AbstractEventHandler<InventoryRerender> {
@InjectDependency
@@ -17,6 +22,11 @@ public class InventoryRerenderHandler extends AbstractEventHandler<InventoryRere
@InjectDependency
private Inventory inventory;
/**
* Handles the InventoryRerender event by rerendering the inventory UI component.
*
* @param event The InventoryRerender event
*/
@Override
public void handle(InventoryRerender event) {
inventory.renderInventoryRerender();

View File

@@ -8,6 +8,11 @@ import cz.jzitnik.client.game.GameState;
import cz.jzitnik.client.utils.GlobalIOHandlerRepository;
import cz.jzitnik.client.utils.events.AbstractEventHandler;
/**
* Handler for the KeyboardPressEvent.
*
* @author Jakub Žitník (jzitnik)
*/
@EventHandler(KeyboardPressEvent.class)
public class KeyboardPressEventHandler extends AbstractEventHandler<KeyboardPressEvent> {
@InjectState
@@ -16,6 +21,11 @@ public class KeyboardPressEventHandler extends AbstractEventHandler<KeyboardPres
@InjectDependency
private GlobalIOHandlerRepository globalIOHandlerRepository;
/**
* Handles the KeyboardPressEvent by delegating to the current screen or the global repository.
*
* @param event The KeyboardPressEvent
*/
@Override
public void handle(KeyboardPressEvent event) {
if (gameState.getScreen() != null) {

View File

@@ -18,6 +18,11 @@ import cz.jzitnik.client.utils.events.EventManager;
import java.util.Optional;
import java.util.stream.Stream;
/**
* Handler for the MouseAction event.
*
* @author Jakub Žitník (jzitnik)
*/
@EventHandler(MouseAction.class)
public class MouseActionEventHandler extends AbstractEventHandler<MouseAction> {
@InjectDependency
@@ -38,6 +43,11 @@ public class MouseActionEventHandler extends AbstractEventHandler<MouseAction> {
@InjectDependency
private DependencyManager dependencyManager;
/**
* Handles the MouseAction event by delegating to screens, repositories, or performing interactions.
*
* @param event The MouseAction event
*/
@Override
public void handle(MouseAction event) {
if (gameState.getScreen() != null) {

View File

@@ -32,6 +32,11 @@ import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Handler for the MouseMoveEvent.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
@EventHandler(MouseMoveEvent.class)
public class MouseMoveEventHandler extends AbstractEventHandler<MouseMoveEvent> {
@@ -58,6 +63,17 @@ public class MouseMoveEventHandler extends AbstractEventHandler<MouseMoveEvent>
@InjectConfig
private PlayerConfig playerConfig;
/**
* Calculates the distance from a point to a rectangle.
*
* @param px Point X
* @param py Point Y
* @param rectTopLeftX Rectangle top-left X
* @param rectTopLeftY Rectangle top-left Y
* @param rectBottomRightX Rectangle bottom-right X
* @param rectBottomRightY Rectangle bottom-right Y
* @return Distance as double
*/
private double distancePointToRect(
double px, double py,
double rectTopLeftX, double rectTopLeftY,
@@ -81,6 +97,11 @@ public class MouseMoveEventHandler extends AbstractEventHandler<MouseMoveEvent>
}
}
/**
* Handles the MouseMoveEvent by updating selectable object states based on hover and distance.
*
* @param event The MouseMoveEvent
*/
@Override
public void handle(MouseMoveEvent event) {
if (event.getMouseAction() != null) {

View File

@@ -26,6 +26,11 @@ import lombok.extern.slf4j.Slf4j;
import java.awt.image.BufferedImage;
/**
* Handler for the PlayerMoveEvent.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
@EventHandler(PlayerMoveEvent.class)
public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent> {
@@ -50,6 +55,11 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
@InjectDependency
private Stats stats;
/**
* Handles the PlayerMoveEvent by updating player position and triggering rerenders.
*
* @param event The PlayerMoveEvent
*/
@Override
public void handle(PlayerMoveEvent event) {
if (renderState.isTerminalTooSmall()) {
@@ -159,6 +169,9 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
});
}
/**
* Enum representing keys that can be used for sprinting.
*/
public static enum SprintKey {
CTRL,
SHIFT,

View File

@@ -9,6 +9,11 @@ import cz.jzitnik.client.ui.Stats;
import cz.jzitnik.client.utils.events.AbstractEventHandler;
import cz.jzitnik.client.utils.events.EventManager;
/**
* Handler for the RenderStats event.
*
* @author Jakub Žitník (jzitnik)
*/
@EventHandler(RenderStats.class)
public class RenderStatsHandler extends AbstractEventHandler<RenderStats> {
@InjectDependency
@@ -17,6 +22,11 @@ public class RenderStatsHandler extends AbstractEventHandler<RenderStats> {
@InjectDependency
private Stats stats;
/**
* Handles the RenderStats event by rerendering the stats UI component.
*
* @param event The RenderStats event
*/
@Override
public void handle(RenderStats event) {
stats.rerender();

View File

@@ -20,6 +20,11 @@ import cz.jzitnik.client.utils.events.EventManager;
import java.awt.image.BufferedImage;
/**
* Handler for the RerenderPart event.
*
* @author Jakub Žitník (jzitnik)
*/
@EventHandler(RerenderPart.class)
public class RerenderPartHandler extends AbstractEventHandler<RerenderPart> {
@InjectState
@@ -40,6 +45,11 @@ public class RerenderPartHandler extends AbstractEventHandler<RerenderPart> {
@InjectDependency
private EventManager eventManager;
/**
* Handles the RerenderPart event by rerendering a portion of the screen.
*
* @param event The RerenderPart event
*/
@Override
public void handle(RerenderPart event) {
int forStartX = event.getForStartX();

View File

@@ -21,6 +21,11 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Handler for the RoomChangeEvent.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
@EventHandler(RoomChangeEvent.class)
public class RoomChangeEventHandler extends AbstractEventHandler<RoomChangeEvent> {
@@ -32,6 +37,11 @@ public class RoomChangeEventHandler extends AbstractEventHandler<RoomChangeEvent
@InjectDependency
private RoomTaskScheduler roomTaskScheduler;
/**
* Handles the RoomChangeEvent by changing the current room and moving the player.
*
* @param event The RoomChangeEvent
*/
@Override
public void handle(RoomChangeEvent event) {
RoomCords playerCords = gameState.getPlayer().getPlayerCords();

View File

@@ -8,11 +8,21 @@ import cz.jzitnik.client.utils.events.AbstractEventHandler;
import java.io.IOException;
/**
* Handler for the SendSocketMessageEvent.
*
* @author Jakub Žitník (jzitnik)
*/
@EventHandler(SendSocketMessageEvent.class)
public class SendSocketMessageEventHandler extends AbstractEventHandler<SendSocketMessageEvent> {
@InjectDependency
private Client client;
/**
* Handles the SendSocketMessageEvent by sending the message through the client.
*
* @param event The SendSocketMessageEvent
*/
@Override
public void handle(SendSocketMessageEvent event) {
try {

View File

@@ -15,6 +15,11 @@ import cz.jzitnik.client.utils.events.AbstractEventHandler;
import cz.jzitnik.client.utils.events.EventManager;
import lombok.extern.slf4j.Slf4j;
/**
* Handler for the TerminalResizeEvent.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
@EventHandler(TerminalResizeEvent.class)
public class TerminalResizeEventHandler extends AbstractEventHandler<TerminalResizeEvent> {
@@ -29,6 +34,11 @@ public class TerminalResizeEventHandler extends AbstractEventHandler<TerminalRes
private boolean screenRerendering = false;
/**
* Handles the TerminalResizeEvent by reinitializing buffers and triggering a full redraw.
*
* @param event The TerminalResizeEvent
*/
@Override
public void handle(TerminalResizeEvent event) {
TerminalSize size = event.getNewSize();

View File

@@ -14,11 +14,21 @@ import cz.jzitnik.client.utils.events.AbstractEventHandler;
import java.io.IOException;
import java.util.EnumSet;
/**
* Handler for the TerminalTooSmallEvent.
*
* @author Jakub Žitník (jzitnik)
*/
@EventHandler(TerminalTooSmallEvent.class)
public class TerminalTooSmallEventHandler extends AbstractEventHandler<TerminalTooSmallEvent> {
@InjectState
private TerminalState terminalState;
/**
* Handles the TerminalTooSmallEvent by rendering a warning message directly to the terminal.
*
* @param event The TerminalTooSmallEvent
*/
@Override
public void handle(TerminalTooSmallEvent event) {
// Directly render the message for the user

View File

@@ -2,6 +2,12 @@ package cz.jzitnik.client.game;
import com.googlecode.lanterna.TextColor;
/**
* Global game constants.
*
* @author Jakub Žitník (jzitnik)
*/
public class Constants {
/** The default background color for the game. */
public static final TextColor BACKGROUND_COLOR = new TextColor.RGB(4, 4, 16);
}

View File

@@ -4,7 +4,24 @@ import cz.jzitnik.common.models.coordinates.RoomCords;
import java.awt.image.BufferedImage;
/**
* Interface representing a player-like entity in the game.
*
* @author Jakub Žitník (jzitnik)
*/
public interface GamePlayer {
/**
* Gets the player's coordinates.
*
* @return RoomCords instance
*/
RoomCords getPlayerCords();
/**
* Gets the player's current texture.
*
* @param resourceManager The resource manager to load texture
* @return BufferedImage texture
*/
BufferedImage getTexture(ResourceManager resourceManager);
}

View File

@@ -14,6 +14,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Represents a room in the game.
*
* @author Jakub Žitník (jzitnik)
*/
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
@@ -45,6 +50,15 @@ public class GameRoom {
private GameRoom up;
private GameRoom down;
/**
* Constructs a GameRoom.
*
* @param id Room ID
* @param objects List of objects in the room
* @param colliders List of colliders
* @param mobs List of mobs
* @param texture Texture resource
*/
@JsonCreator
public GameRoom(
@JsonProperty("id") String id,
@@ -72,21 +86,41 @@ public class GameRoom {
this.overrideBuffer = overrideBuffer;
}
/**
* Sets the room to the west (left).
*
* @param west West room
*/
@JsonSetter("west")
public void setWest(GameRoom west) {
if (west != null) this.left = west;
}
/**
* Sets the room to the east (right).
*
* @param east East room
*/
@JsonSetter("east")
public void setEast(GameRoom east) {
if (east != null) this.right = east;
}
/**
* Sets the room to the north (up).
*
* @param north North room
*/
@JsonSetter("north")
public void setNorth(GameRoom north) {
if (north != null) this.up = north;
}
/**
* Sets the room to the south (down).
*
* @param south South room
*/
@JsonSetter("south")
public void setSouth(GameRoom south) {
if (south != null) this.down = south;

View File

@@ -11,6 +11,11 @@ import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
/**
* Holds the current state of the game.
*
* @author Jakub Žitník (jzitnik)
*/
@RequiredArgsConstructor
@State
public class GameState {
@@ -30,10 +35,20 @@ public class GameState {
private final List<OtherPlayer> otherPlayers = new ArrayList<>();
/**
* Gets a list of visible other players.
*
* @return List of visible other players
*/
public List<OtherPlayer> getOtherPlayers() {
return otherPlayers.stream().filter(OtherPlayer::isVisible).toList();
}
/**
* Gets a list of all other players.
*
* @return List of all other players
*/
public List<OtherPlayer> getAllOtherPlayers() {
return otherPlayers;
}
@@ -45,6 +60,11 @@ public class GameState {
@Getter
private Screen screen;
/**
* Sets the current screen and injects its dependencies.
*
* @param screen The screen to set
*/
public void setScreen(Screen screen) {
if (screen != null) {
dependencyManager.inject(screen);

View File

@@ -9,6 +9,11 @@ import lombok.Setter;
import java.awt.image.BufferedImage;
/**
* Represents another player connected to the same game.
*
* @author Jakub Žitník (jzitnik)
*/
@Getter
public class OtherPlayer implements GamePlayer {
private final int id;
@@ -19,11 +24,20 @@ public class OtherPlayer implements GamePlayer {
@Setter
private boolean visible;
/**
* Constructs an OtherPlayer.
*
* @param playerCreation Player creation data
*/
public OtherPlayer(PlayerCreation playerCreation) {
this.id = playerCreation.getId();
this.playerCords = playerCreation.getPlayerCords();
}
/**
* {@inheritDoc}
*/
@Override
public BufferedImage getTexture(ResourceManager resourceManager) {
BufferedImage resource = resourceManager.getResource(switch (playerRotation) {
case FRONT -> ResourceManager.Resource.PLAYER_FRONT;

View File

@@ -22,11 +22,18 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Represents the local player.
*
* @author Jakub Žitník (jzitnik)
*/
@Getter
@Slf4j
public class Player implements GamePlayer {
private final int id;
/** Maximum stamina value. */
public static final int MAX_STAMINA = 20;
/** Maximum health value. */
public static final int MAX_HEALTH = 30;
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
@@ -43,24 +50,47 @@ public class Player implements GamePlayer {
private boolean hitAnimationOn = false;
private ScheduledFuture<?> currentTimeoutHitAnimation = null;
/**
* Constructs a Player.
*
* @param playerCreation Player creation data
*/
public Player(PlayerCreation playerCreation) {
this.playerCords = playerCreation.getPlayerCords();
this.collider = playerCreation.getCollider();
this.id = playerCreation.getId();
}
/**
* Increases player stamina.
*/
public void increaseStamina() {
stamina++;
}
/**
* Decreases player stamina.
*/
public void decreaseStamina() {
stamina--;
}
/**
* Restores player health.
*
* @param amount Amount to restore
*/
public void addHealth(int amount) {
health = Math.min(MAX_HEALTH, health + amount);
}
/**
* Deals damage to the player.
*
* @param amount Damage amount
* @param dependencyManager Dependency manager
* @return true if player died
*/
public boolean dealDamage(int amount, DependencyManager dependencyManager) {
if (health - amount <= 0) {
health = 0;
@@ -88,6 +118,11 @@ public class Player implements GamePlayer {
return false;
}
/**
* Triggers a rerender of the player.
*
* @param dependencyManager Dependency manager
*/
private void rerender(DependencyManager dependencyManager) {
ResourceManager resourceManager = dependencyManager.getDependencyOrThrow(ResourceManager.class);
EventManager eventManager = dependencyManager.getDependencyOrThrow(EventManager.class);
@@ -104,6 +139,10 @@ public class Player implements GamePlayer {
});
}
/**
* {@inheritDoc}
*/
@Override
public BufferedImage getTexture(ResourceManager resourceManager) {
BufferedImage resource = resourceManager.getResource(switch (playerRotation) {
case FRONT -> ResourceManager.Resource.PLAYER_FRONT;
@@ -119,6 +158,11 @@ public class Player implements GamePlayer {
return resource;
}
/**
* Gets the damage dealt by the player with their current weapon.
*
* @return Damage value
*/
public int getDamageDeal() {
int damage = 1;
@@ -131,6 +175,12 @@ public class Player implements GamePlayer {
return damage;
}
/**
* Adds an item to the player's inventory.
*
* @param item Item to add
* @return true if item was added, false if inventory is full
*/
public boolean addItem(GameItem item) {
boolean added = false;
for (int i = 0; i < inventory.length; i++) {
@@ -144,6 +194,11 @@ public class Player implements GamePlayer {
return added;
}
/**
* Triggers a weapon swing animation.
*
* @param delayMs Duration of the swing
*/
public void swing(int delayMs) {
if (swinging) {
return;

View File

@@ -3,7 +3,18 @@ package cz.jzitnik.client.game;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Represents a requirement (e.g. an item) needed to enter a room.
*
* @param itemType The type of item required
* @author Jakub Žitník (jzitnik)
*/
public record Requirement(String itemType) {
/**
* Constructs a Requirement.
*
* @param itemType The type of item required
*/
@JsonCreator
public Requirement(
@JsonProperty("item") String itemType

View File

@@ -11,11 +11,19 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
/**
* Manages loading and caching of game resources (textures, audio).
*
* @author Jakub Žitník (jzitnik)
*/
@Dependency
public class ResourceManager {
@InjectDependency
private ClassLoader classLoader;
/**
* Enum representing available game resources.
*/
@AllArgsConstructor
@Getter
public enum Resource {
@@ -69,6 +77,12 @@ public class ResourceManager {
private final HashMap<Resource, BufferedImage> resourceCache = new HashMap<>();
/**
* Retrieves a texture resource by its enum key.
*
* @param resource The resource key
* @return The loaded BufferedImage
*/
public BufferedImage getResource(Resource resource) {
if (resourceCache.containsKey(resource)) {
return resourceCache.get(resource);
@@ -88,6 +102,12 @@ public class ResourceManager {
}
}
/**
* Retrieves a texture resource by its path.
*
* @param path The resource path
* @return The loaded BufferedImage
*/
public BufferedImage getResource(String path) {
InputStream is = classLoader.getResourceAsStream(path);
if (is == null) {
@@ -101,6 +121,12 @@ public class ResourceManager {
}
}
/**
* Gets a resource input stream by path.
*
* @param path The resource path
* @return InputStream for the resource
*/
public InputStream getResourceAsStream(String path) {
return classLoader.getResourceAsStream(path);
}

View File

@@ -5,6 +5,11 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import cz.jzitnik.client.utils.events.Event;
import lombok.Getter;
/**
* Represents a dialog sequence in the game.
*
* @author Jakub Žitník (jzitnik)
*/
@Getter
public class Dialog implements Event {
/**
@@ -14,6 +19,12 @@ public class Dialog implements Event {
private final String text;
private final OnEnd onEnd;
/**
* Constructs a Dialog.
*
* @param text The dialog text
* @param onEnd Action to perform when dialog ends
*/
@JsonCreator
public Dialog(
@JsonProperty("text") String text,

View File

@@ -20,6 +20,11 @@ import lombok.RequiredArgsConstructor;
import java.util.Arrays;
import java.util.Optional;
/**
* Interface for actions to perform at the end of a dialog.
*
* @author Jakub Žitník (jzitnik)
*/
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type"
@@ -31,10 +36,18 @@ import java.util.Optional;
@JsonSubTypes.Type(value = OnEnd.GiveItem.class, name = "give_item")
})
public interface OnEnd {
/** Terminal dialog action. */
record End() implements OnEnd {
}
/** Action that gives an item to the player. */
class GiveItem extends RunCode {
/**
* Constructs a GiveItem action.
*
* @param item Item to give
* @param onEnd Next action
*/
@JsonCreator
public GiveItem(
@JsonProperty("item") GameItem item,
@@ -43,6 +56,7 @@ public interface OnEnd {
super(new Run(item), onEnd);
}
/** Internal runnable to give the item. */
@RequiredArgsConstructor
private static class Run implements Runnable {
private final GameItem item;
@@ -56,6 +70,9 @@ public interface OnEnd {
@InjectDependency
private ResourceManager resourceManager;
/**
* {@inheritDoc}
*/
@Override
public void run() {
Player player = gameState.getPlayer();
@@ -72,6 +89,7 @@ public interface OnEnd {
}
}
/** Action that runs arbitrary code. */
@Getter
@RequiredArgsConstructor
class RunCode implements OnEnd {
@@ -79,24 +97,44 @@ public interface OnEnd {
private final OnEnd onEnd;
}
/** Action that continues to another dialog. */
record Continue(Dialog nextDialog) implements OnEnd {
/**
* Constructs a Continue action.
*
* @param nextDialog The next dialog
*/
@JsonCreator
public Continue(@JsonProperty("nextDialog") Dialog nextDialog) {
this.nextDialog = nextDialog;
}
}
/** Action that asks the player a question with multiple answers. */
record AskQuestion(Answer[] answers) implements OnEnd {
/**
* Constructs an AskQuestion action.
*
* @param answers Possible answers
*/
@JsonCreator
public AskQuestion(@JsonProperty("answers") Answer[] answers) {
this.answers = answers;
}
/** Represents a single answer to a question. */
public record Answer(
String answer,
Dialog dialog,
Optional<Requirement> requirement
) {
/**
* Constructs an Answer.
*
* @param answer Answer text
* @param dialog Resulting dialog
* @param requirement Requirement to see this answer
*/
@JsonCreator
public Answer(
@JsonProperty("answer") String answer,
@@ -106,6 +144,9 @@ public interface OnEnd {
this(answer, dialog, Optional.ofNullable(requirement));
}
/**
* Checks if the answer is valid for the current state.
*/
private boolean isValid(GameState gameState) {
if (requirement.isPresent()) {
Requirement requirement = requirement().get();
@@ -126,6 +167,12 @@ public interface OnEnd {
}
}
/**
* Gets valid answers for the current game state.
*
* @param gameState Current game state
* @return Array of valid answers
*/
public Answer[] answers(GameState gameState) {
return Arrays.stream(answers)
.filter(answer -> answer.isValid(gameState))

View File

@@ -1,10 +1,23 @@
package cz.jzitnik.client.game.exceptions;
/**
* Exception thrown when coordinates are invalid.
*
* @author Jakub Žitník (jzitnik)
*/
public class InvalidCoordinatesException extends RuntimeException {
/**
* Constructs an InvalidCoordinatesException with message.
*
* @param message The error message
*/
public InvalidCoordinatesException(String message) {
super(message);
}
/**
* Constructs an InvalidCoordinatesException.
*/
public InvalidCoordinatesException() {
super();
}

View File

@@ -8,6 +8,11 @@ import lombok.Getter;
import java.awt.image.BufferedImage;
/**
* Represents an item in the game.
*
* @author Jakub Žitník (jzitnik)
*/
@Getter
public class GameItem implements Renderable {
private final ItemType<?> type;
@@ -16,6 +21,15 @@ public class GameItem implements Renderable {
private final String name;
private final int id;
/**
* Constructs a GameItem.
*
* @param id Item ID
* @param name Item name
* @param type Item type
* @param resource Texture resource
* @param resourceManager Resource manager
*/
@JsonCreator
public GameItem(
@JsonProperty("id") int id,

View File

@@ -1,6 +1,14 @@
package cz.jzitnik.client.game.items.types;
/**
* Represents a beast skin item type.
*
* @author Jakub Žitník (jzitnik)
*/
public class BeastSkin implements ItemType<BeastSkin> {
/**
* {@inheritDoc}
*/
@Override
public Class<BeastSkin> getItemType() {
return BeastSkin.class;

View File

@@ -3,10 +3,26 @@ package cz.jzitnik.client.game.items.types;
import cz.jzitnik.client.utils.DependencyManager;
import cz.jzitnik.client.utils.StateManager;
/**
* Interface for items that can be interacted with.
*
* @author Jakub Žitník (jzitnik)
*/
public interface InteractableItem {
/**
* Performs interaction with the item.
*
* @param dependencyManager The dependency manager
* @param stateManager The state manager
* @return Result of the interaction
*/
InteractableItemResponse interact(DependencyManager dependencyManager, StateManager stateManager);
/**
* Response types for item interaction.
*/
enum InteractableItemResponse {
/** Clear the item from inventory. */
CLEAR_ITEM,
}
}

View File

@@ -5,6 +5,12 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
import cz.jzitnik.client.game.items.types.food.Food;
import cz.jzitnik.client.game.items.types.weapons.Sword;
/**
* Interface representing a type of game item.
*
* @param <T> The class type of the item
* @author Jakub Žitník (jzitnik)
*/
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "name"
@@ -17,5 +23,10 @@ import cz.jzitnik.client.game.items.types.weapons.Sword;
@JsonSubTypes.Type(value = BeastSkin.class, name = "beast_skin"),
})
public interface ItemType<T> {
/**
* Gets the class representing this item type.
*
* @return The item type class
*/
Class<T> getItemType();
}

View File

@@ -1,6 +1,14 @@
package cz.jzitnik.client.game.items.types;
/**
* Represents a junk item type.
*
* @author Jakub Žitník (jzitnik)
*/
public class Junk implements ItemType<Junk> {
/**
* {@inheritDoc}
*/
@Override
public Class<Junk> getItemType() {
return Junk.class;

View File

@@ -1,6 +1,14 @@
package cz.jzitnik.client.game.items.types;
/**
* Represents a key item type.
*
* @author Jakub Žitník (jzitnik)
*/
public class Key implements ItemType<Key> {
/**
* {@inheritDoc}
*/
@Override
public Class<Key> getItemType() {
return Key.class;

View File

@@ -10,9 +10,19 @@ import cz.jzitnik.client.utils.DependencyManager;
import cz.jzitnik.client.utils.StateManager;
import cz.jzitnik.client.utils.events.EventManager;
/**
* Represents a food item that can be consumed to restore health.
*
* @author Jakub Žitník (jzitnik)
*/
public class Food implements InteractableItem, ItemType<Food> {
private final int addHealth;
/**
* Constructs a Food item with specified health restoration value.
*
* @param addHealth Health to add when consumed
*/
@JsonCreator
public Food(
@JsonProperty("addHealth") int addHealth
@@ -20,6 +30,13 @@ public class Food implements InteractableItem, ItemType<Food> {
this.addHealth = addHealth;
}
/**
* Interacts with the food item (consumes it).
*
* @param dependencyManager The dependency manager
* @param stateManager The state manager
* @return Response indicating the item should be cleared
*/
@Override
public InteractableItemResponse interact(DependencyManager dependencyManager, StateManager stateManager) {
GameState gameState = stateManager.getOrThrow(GameState.class);
@@ -31,6 +48,9 @@ public class Food implements InteractableItem, ItemType<Food> {
return InteractableItemResponse.CLEAR_ITEM;
}
/**
* {@inheritDoc}
*/
@Override
public Class<Food> getItemType() {
return Food.class;

View File

@@ -1,5 +1,15 @@
package cz.jzitnik.client.game.items.types.interfaces;
/**
* Interface for game items that can deal damage.
*
* @author Jakub Žitník (jzitnik)
*/
public interface WeaponInterface {
/**
* Gets the damage dealt by the weapon.
*
* @return Damage value
*/
int getDamageDeal();
}

View File

@@ -3,7 +3,17 @@ package cz.jzitnik.client.game.items.types.weapons;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Represents a sword weapon.
*
* @author Jakub Žitník (jzitnik)
*/
public class Sword extends Weapon {
/**
* Constructs a Sword with specified damage.
*
* @param dealDamage Damage dealt by the sword
*/
@JsonCreator
public Sword(
@JsonProperty("dealDamage") int dealDamage

View File

@@ -4,15 +4,28 @@ import cz.jzitnik.client.game.items.types.ItemType;
import cz.jzitnik.client.game.items.types.interfaces.WeaponInterface;
import lombok.AllArgsConstructor;
/**
* Base class for all weapon items.
*
* @author Jakub Žitník (jzitnik)
*/
@AllArgsConstructor
public abstract class Weapon implements ItemType<Weapon>, WeaponInterface {
private final int dealDamage;
/**
* {@inheritDoc}
*/
@Override
public final Class<Weapon> getItemType() {
return Weapon.class;
}
/**
* Gets the damage dealt by this weapon.
*
* @return Damage value
*/
@Override
public int getDamageDeal() {
return dealDamage;

View File

@@ -14,10 +14,25 @@ import cz.jzitnik.client.states.DialogState;
import cz.jzitnik.client.utils.events.EventManager;
import lombok.extern.slf4j.Slf4j;
/**
* A mob that triggers a dialog when interacted with.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
public class DialogMob extends Mob {
protected Dialog dialog;
/**
* Constructs a DialogMob.
*
* @param texture Texture resource
* @param tasks Tasks
* @param cords Coordinates
* @param collider Collider
* @param dialog Dialog to trigger
* @param resourceManager Resource manager
*/
@JsonCreator
public DialogMob(
@JsonProperty("texture") ResourceManager.Resource texture,
@@ -37,6 +52,9 @@ public class DialogMob extends Mob {
@InjectState
private DialogState dialogState;
/**
* {@inheritDoc}
*/
@Override
public void interact() {
log.debug("Interacting with dialog mob!");

View File

@@ -20,8 +20,16 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Abstract base class for mobs that can be hit and killed.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
public abstract class HittableMob extends Mob {
/**
* Called when the mob is killed.
*/
public abstract void onKilled();
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
@@ -31,6 +39,9 @@ public abstract class HittableMob extends Mob {
private boolean hitAnimationOn = false;
/**
* {@inheritDoc}
*/
@Override
public BufferedImage getTexture() {
if (hitAnimationOn) {
@@ -40,6 +51,12 @@ public abstract class HittableMob extends Mob {
return texture;
}
/**
* Applies a red factor to an image, used for hit animation.
*
* @param src The source image
* @return The red-tinted image
*/
public static BufferedImage applyRedFactor(BufferedImage src) {
final float redFactor = 2f;
int width = src.getWidth();
@@ -68,11 +85,23 @@ public abstract class HittableMob extends Mob {
@InjectDependency
private RoomTaskScheduler roomTaskScheduler;
/**
* Constructs a HittableMob.
*
* @param texture Texture
* @param tasks Tasks
* @param cords Coordinates
* @param collider Collider
* @param health Initial health
*/
public HittableMob(BufferedImage texture, MobRoomTask[] tasks, RoomCords cords, RoomPart collider, int health) {
super(texture, tasks, cords, collider);
this.health = health;
}
/**
* {@inheritDoc}
*/
@Override
public final void interact() {
health -= gameState.getPlayer().getDamageDeal();
@@ -106,6 +135,9 @@ public abstract class HittableMob extends Mob {
}, 250, TimeUnit.MILLISECONDS);
}
/**
* Triggers a rerender of the mob's position.
*/
private void rerender() {
int forStartX = cords.getX();
int forStartY = cords.getY();

View File

@@ -21,6 +21,11 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
/**
* A hittable mob that drops items when killed.
*
* @author Jakub Žitník (jzitnik)
*/
public class HittableMobDrops extends HittableMob {
private static final int DROP_ITEM_ON_GROUND_RADIUS = 30;
private final GameItem[] itemsDrops;
@@ -29,6 +34,17 @@ public class HittableMobDrops extends HittableMob {
@InjectDependency
private EventManager eventManager;
/**
* Constructs a HittableMobDrops instance.
*
* @param texture Texture resource
* @param tasks Tasks
* @param cords Coordinates
* @param collider Collider
* @param health Initial health
* @param itemsDrops Items to drop on death
* @param resourceManager Resource manager
*/
@JsonCreator
public HittableMobDrops(
@JsonProperty("texture") ResourceManager.Resource texture,
@@ -49,6 +65,9 @@ public class HittableMobDrops extends HittableMob {
public void afterKill() {
}
/**
* {@inheritDoc}
*/
@Override
public final void onKilled() {
boolean addedIntoInventory = false;
@@ -77,6 +96,15 @@ public class HittableMobDrops extends HittableMob {
eventManager.emitEvent(events, this::afterKill);
}
/**
* Drops an item at a random position near specified coordinates.
*
* @param x Center X
* @param y Center Y
* @param currentRoom The current room
* @param item The item to drop
* @return A DroppedItemRerender event
*/
public static Event dropItem(int x, int y, GameRoom currentRoom, GameItem item) {
double angle = ThreadLocalRandom.current().nextDouble(0, Math.PI * 2);
double radius = ThreadLocalRandom.current().nextDouble(0, DROP_ITEM_ON_GROUND_RADIUS);

View File

@@ -8,7 +8,22 @@ import cz.jzitnik.client.game.ResourceManager;
import cz.jzitnik.client.game.mobs.tasks.MobRoomTask;
import cz.jzitnik.common.models.coordinates.RoomCords;
/**
* A hittable mob that does not drop any items when killed.
*
* @author Jakub Žitník (jzitnik)
*/
public class HittableMobNoDrops extends HittableMob {
/**
* Constructs a HittableMobNoDrops instance.
*
* @param texture Texture resource
* @param tasks Tasks
* @param cords Coordinates
* @param collider Collider
* @param health Initial health
* @param resourceManager Resource manager
*/
@JsonCreator
public HittableMobNoDrops(
@JsonProperty("texture") ResourceManager.Resource texture,
@@ -21,6 +36,9 @@ public class HittableMobNoDrops extends HittableMob {
super(resourceManager.getResource(texture), tasks, cords, collider, health);
}
/**
* {@inheritDoc}
*/
@Override
public void onKilled() {

View File

@@ -15,6 +15,11 @@ import lombok.Setter;
import java.awt.image.BufferedImage;
/**
* Abstract base class for all mobs in the game.
*
* @author Jakub Žitník (jzitnik)
*/
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type"
@@ -39,6 +44,11 @@ public abstract class Mob implements Renderable, Selectable {
@InjectDependency
private RoomTaskScheduler roomTaskScheduler;
/**
* Updates the tasks associated with this mob and registers them.
*
* @param tasks The new tasks
*/
protected void updateTasks(MobRoomTask[] tasks) {
var oldTasks = this.tasks;
this.tasks = tasks;
@@ -46,6 +56,14 @@ public abstract class Mob implements Renderable, Selectable {
roomTaskScheduler.registerNewMob(this, oldTasks);
}
/**
* Constructs a Mob.
*
* @param texture The mob's texture
* @param tasks Tasks associated with the mob
* @param cords Initial coordinates
* @param collider The mob's collider
*/
public Mob(BufferedImage texture, MobRoomTask[] tasks, RoomCords cords, RoomPart collider) {
this.texture = texture;
this.tasks = tasks == null ? new MobRoomTask[] {} : tasks;

View File

@@ -20,9 +20,20 @@ import lombok.Setter;
import java.util.concurrent.TimeUnit;
/**
* Task that makes a mob follow the player only when they make noise.
*
* @author Jakub Žitník (jzitnik)
*/
public class BlindMobFollowingPlayerTask extends MobRoomTask {
private final Task task;
/**
* Constructs a BlindMobFollowingPlayerTask.
*
* @param speed Mob movement speed
* @param updateRateMs Execution rate in milliseconds
*/
@JsonCreator
public BlindMobFollowingPlayerTask(
@JsonProperty("speed") int speed,
@@ -33,11 +44,17 @@ public class BlindMobFollowingPlayerTask extends MobRoomTask {
this.task = task;
}
/**
* {@inheritDoc}
*/
@Override
public void setOwner(Mob mob) {
task.setMob(mob);
}
/**
* Internal task runnable logic.
*/
@RequiredArgsConstructor
private static class Task implements Runnable {
@Setter
@@ -68,6 +85,9 @@ public class BlindMobFollowingPlayerTask extends MobRoomTask {
@InjectConfig
private MicrophoneConfig microphoneConfig;
/**
* {@inheritDoc}
*/
@Override
public void run() {
if (playerCords == null || (microphoneState.isMicrophoneSetup() && microphoneState.getMicrophoneVolume() > microphoneConfig.volumeThreshold())) {

View File

@@ -16,10 +16,22 @@ import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
/**
* Task that makes a mob attack the player if within reach.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
public class EnemyPlayerAttackingTask extends MobRoomTask {
private final Task task;
/**
* Constructs an EnemyPlayerAttackingTask.
*
* @param updateRateMs Execution rate in milliseconds
* @param reach Attack reach
* @param damage Attack damage
*/
@JsonCreator
public EnemyPlayerAttackingTask(
@JsonProperty("updateRateMs") long updateRateMs,
@@ -31,11 +43,17 @@ public class EnemyPlayerAttackingTask extends MobRoomTask {
this.task = task;
}
/**
* {@inheritDoc}
*/
@Override
public void setOwner(Mob mob) {
task.setMob(mob);
}
/**
* Internal task runnable logic.
*/
@RequiredArgsConstructor
private static class Task implements Runnable {
private final double reach;
@@ -52,6 +70,9 @@ public class EnemyPlayerAttackingTask extends MobRoomTask {
@InjectDependency
private DependencyManager dependencyManager;
/**
* {@inheritDoc}
*/
@Override
public void run() {
RoomCords playerCords = gameState.getPlayer().getPlayerCords();

View File

@@ -29,10 +29,21 @@ import java.awt.image.BufferedImage;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Task that makes a mob follow the player using A* pathfinding.
*
* @author Jakub Žitník (jzitnik)
*/
@Slf4j
public class MobFollowingPlayerTask extends MobRoomTask {
private final Task task;
/**
* Constructs a MobFollowingPlayerTask.
*
* @param speed Mob movement speed
* @param updateRateMs Execution rate in milliseconds
*/
@JsonCreator
public MobFollowingPlayerTask(
@JsonProperty("speed") int speed,
@@ -43,11 +54,17 @@ public class MobFollowingPlayerTask extends MobRoomTask {
this.task = task;
}
/**
* {@inheritDoc}
*/
@Override
public void setOwner(Mob mob) {
task.setMob(mob);
}
/**
* Internal task runnable logic.
*/
@RequiredArgsConstructor
static class Task implements Runnable {
private final int speed;
@@ -71,6 +88,19 @@ public class MobFollowingPlayerTask extends MobRoomTask {
@InjectConfig
private Debugging debugging;
/**
* Core logic to move a mob towards player coordinates.
*
* @param playerCords Target player coordinates
* @param mob Mob instance to move
* @param gameState Current game state
* @param speed Movement speed
* @param resourceManager Resource manager
* @param terminalState Terminal state
* @param screenBuffer Screen buffer
* @param debugging Debugging config
* @param eventManager Event manager
*/
protected static void moveMob(RoomCords playerCords, Mob mob, GameState gameState, int speed, ResourceManager resourceManager, TerminalState terminalState, ScreenBuffer screenBuffer, Debugging debugging, EventManager eventManager) {
RoomCords mobCords = mob.getCords();
List<RoomPart> solidParts = gameState.getCurrentRoom().getColliders();
@@ -112,6 +142,9 @@ public class MobFollowingPlayerTask extends MobRoomTask {
}
}
/**
* {@inheritDoc}
*/
@Override
public void run() {
moveMob(gameState.getPlayer().getPlayerCords(), mob, gameState, speed, resourceManager, terminalState, screenBuffer, debugging, eventManager);

Some files were not shown because too many files have changed in this diff Show More