Compare commits
11 Commits
5366162f43
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
f2b6200355
|
|||
|
e15d4ec874
|
|||
|
dac6d666b2
|
|||
|
3dd2c389b8
|
|||
|
f7d878f430
|
|||
|
32f8521951
|
|||
|
f8f150cdf0
|
|||
|
8935349f92
|
|||
|
a8ce7b8ed1
|
|||
|
6559cbe4c7
|
|||
|
35918ac0ad
|
1
.idea/compiler.xml
generated
@@ -34,6 +34,7 @@
|
||||
<entry name="$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.18.38/lombok-1.18.38.jar" />
|
||||
</processorPath>
|
||||
<module name="game (1)" />
|
||||
<module name="game" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
|
||||
37
README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Terminal Game
|
||||
|
||||
A multiplayer terminal-based game built with Java, utilizing WebSockets for communication and Lanterna for the text-based user interface.
|
||||
|
||||
## Project Structure
|
||||
|
||||
* **game**: Client application (TUI).
|
||||
* **server**: WebSocket server.
|
||||
* **common**: Shared libraries and logic.
|
||||
|
||||
## Requirements
|
||||
|
||||
* Java 25
|
||||
* Maven
|
||||
|
||||
## How to Run
|
||||
|
||||
1. Build the project:
|
||||
```bash
|
||||
mvn clean install
|
||||
```
|
||||
|
||||
2. Start the server:
|
||||
```bash
|
||||
mvn compile exec:java -pl server -am
|
||||
```
|
||||
|
||||
3. Start the client (in a new terminal):
|
||||
```bash
|
||||
mvn compile exec:java -pl game -am
|
||||
```
|
||||
|
||||
## Controls
|
||||
|
||||
* **Left Click**: Interact with objects and fight.
|
||||
* **WASD**: Move the character.
|
||||
* **CTRL**: Hold to run (sprint).
|
||||
@@ -6,6 +6,7 @@ import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@@ -16,6 +17,13 @@ public class RoomCords implements Cloneable, Serializable {
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public RoomCords calculateCenter(BufferedImage texture) {
|
||||
return new RoomCords(
|
||||
x + texture.getWidth() / 2,
|
||||
y + texture.getHeight() / 2
|
||||
);
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public RoomCords(
|
||||
@JsonProperty("x") int x,
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package cz.jzitnik.common.socket.messages.game;
|
||||
|
||||
import cz.jzitnik.common.socket.SocketMessage;
|
||||
|
||||
public record GameWin() implements SocketMessage {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package cz.jzitnik.common.socket.messages.game;
|
||||
|
||||
import cz.jzitnik.common.socket.SocketMessage;
|
||||
|
||||
public record PlayerDeath(int playerId) implements SocketMessage {
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import cz.jzitnik.client.annotations.EventHandler;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.client.events.RerenderScreen;
|
||||
import cz.jzitnik.client.game.GameState;
|
||||
import cz.jzitnik.client.game.dialog.Dialog;
|
||||
import cz.jzitnik.client.game.dialog.OnEnd;
|
||||
import cz.jzitnik.client.states.DialogState;
|
||||
@@ -22,8 +23,8 @@ import cz.jzitnik.client.utils.events.EventManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@EventHandler(Dialog.class)
|
||||
@@ -38,6 +39,9 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
||||
@InjectState
|
||||
private ScreenBuffer screenBuffer;
|
||||
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
|
||||
@InjectDependency
|
||||
private EventManager eventManager;
|
||||
|
||||
@@ -56,32 +60,45 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
||||
public static final int BUTTON_PADDING = 5;
|
||||
private static final float FONT_SIZE = 15f;
|
||||
|
||||
public static int calculateButtonHeight(Dialog dialog) {
|
||||
if (dialog.getOnEnd() instanceof OnEnd.AskQuestion(OnEnd.AskQuestion.Answer[] answers)) {
|
||||
return answers.length * BUTTON_HEIGHT + (answers.length - 1) * BUTTON_PADDING;
|
||||
} else {
|
||||
return 0;
|
||||
public static int calculateButtonHeight(Dialog dialog, GameState gameState) {
|
||||
if (dialog.getOnEnd() instanceof OnEnd.AskQuestion askQuestion) {
|
||||
int count = askQuestion.answers(gameState).length;
|
||||
return count * BUTTON_HEIGHT + Math.max(0, count - 1) * BUTTON_PADDING;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getYStartButtons(TextRenderer textRenderer, Dialog dialog) {
|
||||
var textSize = textRenderer.measureText(dialog.getText(), WIDTH - PADDING * 2, FONT_SIZE);
|
||||
var textSize = textRenderer.measureText(
|
||||
dialog.getText(),
|
||||
WIDTH - PADDING * 2,
|
||||
FONT_SIZE
|
||||
);
|
||||
|
||||
return PADDING + textSize.height + BUTTON_PADDING;
|
||||
}
|
||||
|
||||
public static TerminalSize getSize(TextRenderer textRenderer, Dialog dialog) {
|
||||
var textSize = textRenderer.measureText(dialog.getText(), WIDTH - PADDING * 2, FONT_SIZE);
|
||||
public static TerminalSize getSize(TextRenderer textRenderer, Dialog dialog, GameState gameState) {
|
||||
var textSize = textRenderer.measureText(
|
||||
dialog.getText(),
|
||||
WIDTH - PADDING * 2,
|
||||
FONT_SIZE
|
||||
);
|
||||
|
||||
return new TerminalSize(300, PADDING + textSize.height + (
|
||||
dialog.getOnEnd() instanceof OnEnd.AskQuestion ? BUTTON_PADDING + calculateButtonHeight(dialog) : 0
|
||||
) + PADDING);
|
||||
int buttonsHeight = 0;
|
||||
if (dialog.getOnEnd() instanceof OnEnd.AskQuestion) {
|
||||
buttonsHeight = BUTTON_PADDING + calculateButtonHeight(dialog, gameState);
|
||||
}
|
||||
|
||||
return new TerminalSize(
|
||||
300,
|
||||
PADDING + textSize.height + buttonsHeight + PADDING
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -89,58 +106,114 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
||||
public void handle(Dialog event) {
|
||||
boolean onlyLast = dialogState.getCurrentDialog() == event;
|
||||
dialogState.setCurrentDialog(event);
|
||||
|
||||
TerminalSize terminalSize = terminalState.getTerminalScreen().getTerminalSize();
|
||||
var overrideBuffer = screenBuffer.getGlobalOverrideBuffer();
|
||||
var size = getSize(textRenderer, event);
|
||||
|
||||
var size = getSize(textRenderer, event, gameState);
|
||||
var start = getStart(terminalSize, size);
|
||||
|
||||
var animation = textRenderer.renderTypingAnimation(event.getText(), size.getColumns() - PADDING * 2, size.getRows() - PADDING * 2, Color.WHITE, FONT_SIZE);
|
||||
var textSize = textRenderer.measureText(event.getText(), size.getColumns() - PADDING * 2, FONT_SIZE);
|
||||
var animation = textRenderer.renderTypingAnimation(
|
||||
event.getText(),
|
||||
size.getColumns() - PADDING * 2,
|
||||
size.getRows() - PADDING * 2,
|
||||
Color.WHITE,
|
||||
FONT_SIZE
|
||||
);
|
||||
|
||||
var textSize = textRenderer.measureText(
|
||||
event.getText(),
|
||||
size.getColumns() - PADDING * 2,
|
||||
FONT_SIZE
|
||||
);
|
||||
|
||||
OnEnd onEnd = event.getOnEnd();
|
||||
|
||||
List<AlphaPixel[][]> answersBuf = new ArrayList<>();
|
||||
OnEnd.AskQuestion askQuestion = null;
|
||||
|
||||
if (onEnd instanceof OnEnd.AskQuestion(
|
||||
OnEnd.AskQuestion.Answer[] answers
|
||||
)) {
|
||||
for (OnEnd.AskQuestion.Answer answer : answers) {
|
||||
answersBuf.add(textRenderer.renderText(answer.answer(), size.getColumns() - PADDING * 2, BUTTON_HEIGHT, Color.BLACK, FONT_SIZE, false));
|
||||
if (onEnd instanceof OnEnd.AskQuestion aq) {
|
||||
askQuestion = aq;
|
||||
for (OnEnd.AskQuestion.Answer answer : aq.answers(gameState)) {
|
||||
answersBuf.add(
|
||||
textRenderer.renderText(
|
||||
answer.answer(),
|
||||
size.getColumns() - PADDING * 2,
|
||||
BUTTON_HEIGHT,
|
||||
Color.BLACK,
|
||||
FONT_SIZE,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
dialogState.setRenderInProgress(true);
|
||||
|
||||
try {
|
||||
for (int i = onlyLast ? animation.length : 0; i <= animation.length; i++) {
|
||||
var buf = animation[Math.min(i, animation.length - 1)];
|
||||
|
||||
for (int y = 0; y < size.getRows(); y++) {
|
||||
for (int x = 0; x < size.getColumns(); x++) {
|
||||
var textPixel = buf[Math.min(Math.max(0, y - PADDING), buf.length - 1)][Math.min(Math.max(0, x - PADDING), buf[0].length - 1)];
|
||||
if (textPixel instanceof Empty || y < PADDING || x < PADDING || x >= size.getColumns() - PADDING || y >= size.getRows() - PADDING) {
|
||||
if (i == animation.length && y - 2 > textSize.height + QUESTION_ACTIONS_GAP && onEnd instanceof OnEnd.AskQuestion(
|
||||
OnEnd.AskQuestion.Answer[] answers
|
||||
)) {
|
||||
|
||||
var textPixel = buf[
|
||||
Math.min(Math.max(0, y - PADDING), buf.length - 1)
|
||||
][
|
||||
Math.min(Math.max(0, x - PADDING), buf[0].length - 1)
|
||||
];
|
||||
|
||||
if (textPixel instanceof Empty
|
||||
|| y < PADDING
|
||||
|| x < PADDING
|
||||
|| x >= size.getColumns() - PADDING
|
||||
|| y >= size.getRows() - PADDING) {
|
||||
|
||||
if (i == animation.length
|
||||
&& askQuestion != null
|
||||
&& y - 2 > textSize.height + QUESTION_ACTIONS_GAP) {
|
||||
|
||||
var answers = askQuestion.answers(gameState);
|
||||
|
||||
int buttonsY = y - textSize.height - QUESTION_ACTIONS_GAP - 2;
|
||||
int buttonIndex = buttonsY / (BUTTON_HEIGHT + BUTTON_PADDING);
|
||||
int rest = buttonsY % (BUTTON_HEIGHT + BUTTON_PADDING);
|
||||
|
||||
if (buttonIndex < answers.length && rest < BUTTON_HEIGHT && x >= PADDING && x < size.getColumns() - PADDING) {
|
||||
if (buttonIndex < answers.length
|
||||
&& rest < BUTTON_HEIGHT
|
||||
&& x >= PADDING
|
||||
&& x < size.getColumns() - PADDING) {
|
||||
|
||||
int localY = rest - BUTTON_TEXT_PADDING;
|
||||
int localX = x - PADDING - BUTTON_TEXT_PADDING;
|
||||
|
||||
var buttonBuf = answersBuf.get(buttonIndex);
|
||||
var buttonTextPixel = buttonBuf[Math.min(Math.max(0, localY), buttonBuf.length - 1)][Math.min(Math.max(0, localX), buttonBuf[0].length - 1)];
|
||||
var buttonTextPixel = buttonBuf[
|
||||
Math.min(Math.max(0, localY), buttonBuf.length - 1)
|
||||
][
|
||||
Math.min(Math.max(0, localX), buttonBuf[0].length - 1)
|
||||
];
|
||||
|
||||
if (buttonTextPixel instanceof Empty || localY < 0 || localX < 0 || localY >= buttonBuf.length || localX >= buttonBuf[0].length) {
|
||||
overrideBuffer[start.getRow() + y][start.getColumn() + x] = new ColoredPixel(new TextColor.RGB(255, 255, 255), dialogState.getHoveredButtonIndex() == buttonIndex ? 0.8f : 0.6f);
|
||||
if (buttonTextPixel instanceof Empty
|
||||
|| localY < 0
|
||||
|| localX < 0
|
||||
|| localY >= buttonBuf.length
|
||||
|| localX >= buttonBuf[0].length) {
|
||||
|
||||
overrideBuffer[start.getRow() + y][start.getColumn() + x] =
|
||||
new ColoredPixel(
|
||||
new TextColor.RGB(255, 255, 255),
|
||||
dialogState.getHoveredButtonIndex() == buttonIndex ? 0.8f : 0.6f
|
||||
);
|
||||
} else {
|
||||
overrideBuffer[start.getRow() + y][start.getColumn() + x] = buttonTextPixel;
|
||||
overrideBuffer[start.getRow() + y][start.getColumn() + x] =
|
||||
buttonTextPixel;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
overrideBuffer[start.getRow() + y][start.getColumn() + x] = new ColoredPixel(new TextColor.RGB(0, 0, 0), 0.6f);
|
||||
overrideBuffer[start.getRow() + y][start.getColumn() + x] =
|
||||
new ColoredPixel(new TextColor.RGB(0, 0, 0), 0.6f);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -152,7 +225,10 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
||||
new RerenderScreen(
|
||||
new RerenderScreen.ScreenPart(
|
||||
start,
|
||||
new TerminalPosition(start.getColumn() + size.getColumns(), start.getRow() + size.getRows())
|
||||
new TerminalPosition(
|
||||
start.getColumn() + size.getColumns(),
|
||||
start.getRow() + size.getRows()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -161,7 +237,6 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
||||
}
|
||||
|
||||
dialogState.setRenderInProgress(false);
|
||||
|
||||
next(onEnd, start, size);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
@@ -170,31 +245,39 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
||||
}
|
||||
|
||||
private void next(OnEnd onEnd, TerminalPosition start, TerminalSize size) throws InterruptedException {
|
||||
if (onEnd instanceof OnEnd.Continue(Dialog nextDialog)) {
|
||||
Thread.sleep(1000);
|
||||
for (int y = start.getRow(); y < start.getRow() + size.getRows(); y++) {
|
||||
for (int x = start.getColumn(); x < start.getColumn() + size.getColumns(); x++) {
|
||||
screenBuffer.getGlobalOverrideBuffer()[y][x] = new Empty();
|
||||
}
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
|
||||
if (nextDialog == null) {
|
||||
dialogState.setCurrentDialog(null);
|
||||
eventManager.emitEvent(
|
||||
new RerenderScreen(
|
||||
new RerenderScreen.ScreenPart(
|
||||
start,
|
||||
new TerminalPosition(start.getColumn() + size.getColumns(), start.getRow() + size.getRows())
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
eventManager.emitEvent(nextDialog);
|
||||
}
|
||||
} else if (onEnd instanceof OnEnd.RunCode(Runnable runnable, OnEnd end)) {
|
||||
if (onEnd instanceof OnEnd.Continue(Dialog nextDialog)) {
|
||||
clear(start, size);
|
||||
eventManager.emitEvent(nextDialog);
|
||||
|
||||
} else if (onEnd instanceof OnEnd.RunCode runCode) {
|
||||
Runnable runnable = runCode.getRunnable();
|
||||
dependencyManager.inject(runnable);
|
||||
runnable.run();
|
||||
next(end, start, size);
|
||||
next(runCode.getOnEnd(), start, size);
|
||||
} else if (onEnd instanceof OnEnd.End) {
|
||||
clear(start, size);
|
||||
dialogState.setCurrentDialog(null);
|
||||
eventManager.emitEvent(
|
||||
new RerenderScreen(
|
||||
new RerenderScreen.ScreenPart(
|
||||
start,
|
||||
new TerminalPosition(
|
||||
start.getColumn() + size.getColumns(),
|
||||
start.getRow() + size.getRows()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void clear(TerminalPosition start, TerminalSize size) {
|
||||
for (int y = start.getRow(); y < start.getRow() + size.getRows(); y++) {
|
||||
for (int x = start.getColumn(); x < start.getColumn() + size.getColumns(); x++) {
|
||||
screenBuffer.getGlobalOverrideBuffer()[y][x] = new Empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,16 @@ import cz.jzitnik.client.events.RoomChangeEvent;
|
||||
import cz.jzitnik.client.events.SendSocketMessageEvent;
|
||||
import cz.jzitnik.client.game.GameRoom;
|
||||
import cz.jzitnik.client.game.GameState;
|
||||
import cz.jzitnik.client.game.Requirement;
|
||||
import cz.jzitnik.common.models.coordinates.RoomCords;
|
||||
import cz.jzitnik.client.utils.events.AbstractEventHandler;
|
||||
import cz.jzitnik.client.utils.events.EventManager;
|
||||
import cz.jzitnik.client.utils.roomtasks.RoomTaskScheduler;
|
||||
import cz.jzitnik.common.socket.messages.game.GameWin;
|
||||
import cz.jzitnik.common.socket.messages.room.MovePlayerRoom;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -45,6 +48,20 @@ public class RoomChangeEventHandler extends AbstractEventHandler<RoomChangeEvent
|
||||
return;
|
||||
}
|
||||
|
||||
if (newRoom.getRequirement() != null) {
|
||||
Requirement requirement = newRoom.getRequirement();
|
||||
String itemType = requirement.itemType();
|
||||
if (Arrays.stream(gameState.getPlayer().getInventory()).noneMatch(item -> {
|
||||
if (item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.getType().getItemType().getSimpleName().equals(itemType);
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (event.door()) {
|
||||
case LEFT -> playerCords.updateCords(155, playerCords.getY());
|
||||
case RIGHT -> playerCords.updateCords(30, playerCords.getY());
|
||||
@@ -55,6 +72,10 @@ public class RoomChangeEventHandler extends AbstractEventHandler<RoomChangeEvent
|
||||
eventManager.emitEvent(new SendSocketMessageEvent(new MovePlayerRoom(newRoom.getId(), oldCords, playerCords)));
|
||||
|
||||
gameState.setCurrentRoom(newRoom);
|
||||
scheduler.schedule(() -> roomTaskScheduler.setupNewSchedulers(newRoom), 200, TimeUnit.MILLISECONDS);
|
||||
if (newRoom.isEnd()) {
|
||||
eventManager.emitEvent(new SendSocketMessageEvent(new GameWin()));
|
||||
} else {
|
||||
scheduler.schedule(() -> roomTaskScheduler.setupNewSchedulers(newRoom), 200, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,12 @@ public class GameRoom {
|
||||
@JsonIgnore
|
||||
private final List<RoomPart> colliders = new ArrayList<>();
|
||||
|
||||
@JsonProperty("requirement")
|
||||
private Requirement requirement;
|
||||
|
||||
@JsonProperty("end")
|
||||
private boolean end;
|
||||
|
||||
private GameRoom left;
|
||||
private GameRoom right;
|
||||
private GameRoom up;
|
||||
|
||||
@@ -28,7 +28,7 @@ public class Player implements GamePlayer {
|
||||
private final int id;
|
||||
public static final int MAX_STAMINA = 20;
|
||||
public static final int MAX_HEALTH = 30;
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
private final RoomCords playerCords;
|
||||
private final RoomPart collider;
|
||||
@@ -64,6 +64,8 @@ public class Player implements GamePlayer {
|
||||
public boolean dealDamage(int amount, DependencyManager dependencyManager) {
|
||||
if (health - amount <= 0) {
|
||||
health = 0;
|
||||
EventManager eventManager = dependencyManager.getDependencyOrThrow(EventManager.class);
|
||||
eventManager.emitEvent(new cz.jzitnik.client.events.SendSocketMessageEvent(new cz.jzitnik.common.socket.messages.game.PlayerDeath(id)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
13
game/src/main/java/cz/jzitnik/client/game/Requirement.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package cz.jzitnik.client.game;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public record Requirement(String itemType) {
|
||||
@JsonCreator
|
||||
public Requirement(
|
||||
@JsonProperty("item") String itemType
|
||||
) {
|
||||
this.itemType = itemType;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,14 @@ public class ResourceManager {
|
||||
ROOM2("rooms/2.png"),
|
||||
ROOM3("rooms/3.png"),
|
||||
ROOM4("rooms/4.png"),
|
||||
ROOM5("rooms/5.png"),
|
||||
ROOM6("rooms/6.png"),
|
||||
ROOM7("rooms/7.png"),
|
||||
ROOM8("rooms/8.png"),
|
||||
ROOM9("rooms/9.png"),
|
||||
ROOM10("rooms/10.png"),
|
||||
ROOM11("rooms/11.png"),
|
||||
ROOM12("rooms/12.png"),
|
||||
ROOM_FROZEN("rooms/frozen.png"),
|
||||
|
||||
PLAYER_FRONT("player/front.png"),
|
||||
@@ -36,8 +44,23 @@ public class ResourceManager {
|
||||
|
||||
APPLE("food/apple.png"),
|
||||
|
||||
DOORS("rooms/doors.png"),
|
||||
// TEMP TEXTURES JUST TO GET THE GAME WORKING
|
||||
OLD_MAN("player/front.png"),
|
||||
KEY_KEEPER("player/front.png"),
|
||||
CAVE_BEAST("player/front.png"),
|
||||
BLIND_HUNTER("player/front.png"),
|
||||
ZOMBIE("player/front.png"),
|
||||
|
||||
RUSTY_SWORD("tools/wooden_sword.png"),
|
||||
AXE("tools/wooden_sword.png"),
|
||||
DAGGER("tools/wooden_sword.png"),
|
||||
BREAD("food/apple.png"),
|
||||
ROCK("food/apple.png"),
|
||||
KEY("food/apple.png"),
|
||||
BOSS_SKIN("tools/wooden_sword.png"),
|
||||
|
||||
// UI
|
||||
DOORS("rooms/doors.png"),
|
||||
STAMINA("ui/stamina.png"),
|
||||
HEART("ui/heart.png");
|
||||
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
package cz.jzitnik.client.game.dialog;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import cz.jzitnik.client.utils.events.Event;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public class Dialog implements Event {
|
||||
/**
|
||||
* Characters per second
|
||||
*/
|
||||
private int typingSpeed = 10;
|
||||
private final int typingSpeed = 10;
|
||||
private final String text;
|
||||
private final OnEnd onEnd;
|
||||
|
||||
@JsonCreator
|
||||
public Dialog(
|
||||
@JsonProperty("text") String text,
|
||||
@JsonProperty("onEnd") OnEnd onEnd
|
||||
) {
|
||||
this.text = text;
|
||||
this.onEnd = onEnd;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,135 @@
|
||||
package cz.jzitnik.client.game.dialog;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.client.events.InventoryRerender;
|
||||
import cz.jzitnik.client.game.GameState;
|
||||
import cz.jzitnik.client.game.Player;
|
||||
import cz.jzitnik.client.game.Requirement;
|
||||
import cz.jzitnik.client.game.ResourceManager;
|
||||
import cz.jzitnik.client.game.items.GameItem;
|
||||
import cz.jzitnik.client.game.mobs.HittableMobDrops;
|
||||
import cz.jzitnik.client.utils.events.EventManager;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
property = "type"
|
||||
)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = OnEnd.Continue.class, name = "continue"),
|
||||
@JsonSubTypes.Type(value = OnEnd.AskQuestion.class, name = "ask_question"),
|
||||
@JsonSubTypes.Type(value = OnEnd.End.class, name = "end"),
|
||||
@JsonSubTypes.Type(value = OnEnd.GiveItem.class, name = "give_item")
|
||||
})
|
||||
public interface OnEnd {
|
||||
record RunCode(Runnable runnable, OnEnd onEnd) implements OnEnd {}
|
||||
record End() implements OnEnd {
|
||||
}
|
||||
|
||||
class GiveItem extends RunCode {
|
||||
@JsonCreator
|
||||
public GiveItem(
|
||||
@JsonProperty("item") GameItem item,
|
||||
@JsonProperty("then") OnEnd onEnd
|
||||
) {
|
||||
super(new Run(item), onEnd);
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class Run implements Runnable {
|
||||
private final GameItem item;
|
||||
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
|
||||
@InjectDependency
|
||||
private EventManager eventManager;
|
||||
|
||||
@InjectDependency
|
||||
private ResourceManager resourceManager;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Player player = gameState.getPlayer();
|
||||
var playerCords = player.getPlayerCords().calculateCenter(player.getTexture(resourceManager));
|
||||
|
||||
boolean addedIntoInventory = player.addItem(item);
|
||||
|
||||
if (!addedIntoInventory) {
|
||||
eventManager.emitEvent(HittableMobDrops.dropItem(playerCords.getX(), playerCords.getY(), gameState.getCurrentRoom(), item));
|
||||
} else {
|
||||
eventManager.emitEvent(new InventoryRerender());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
class RunCode implements OnEnd {
|
||||
private final Runnable runnable;
|
||||
private final OnEnd onEnd;
|
||||
}
|
||||
|
||||
record Continue(Dialog nextDialog) implements OnEnd {
|
||||
@JsonCreator
|
||||
public Continue(@JsonProperty("nextDialog") Dialog nextDialog) {
|
||||
this.nextDialog = nextDialog;
|
||||
}
|
||||
}
|
||||
|
||||
record AskQuestion(Answer[] answers) implements OnEnd {
|
||||
public record Answer(String answer, Dialog dialog) {
|
||||
@JsonCreator
|
||||
public AskQuestion(@JsonProperty("answers") Answer[] answers) {
|
||||
this.answers = answers;
|
||||
}
|
||||
|
||||
public record Answer(
|
||||
String answer,
|
||||
Dialog dialog,
|
||||
Optional<Requirement> requirement
|
||||
) {
|
||||
@JsonCreator
|
||||
public Answer(
|
||||
@JsonProperty("answer") String answer,
|
||||
@JsonProperty("dialog") Dialog dialog,
|
||||
@JsonProperty("requirement") Requirement requirement
|
||||
) {
|
||||
this(answer, dialog, Optional.ofNullable(requirement));
|
||||
}
|
||||
|
||||
private boolean isValid(GameState gameState) {
|
||||
if (requirement.isPresent()) {
|
||||
Requirement requirement = requirement().get();
|
||||
if (requirement.itemType() != null) {
|
||||
return Arrays.stream(gameState.getPlayer().getInventory()).anyMatch(item -> {
|
||||
if (item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.getType().getItemType().getSimpleName().equals(requirement.itemType());
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public Answer[] answers(GameState gameState) {
|
||||
return Arrays.stream(answers)
|
||||
.filter(answer -> answer.isValid(gameState))
|
||||
.toArray(Answer[]::new);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package cz.jzitnik.client.game.items.types;
|
||||
|
||||
public class BeastSkin implements ItemType<BeastSkin> {
|
||||
@Override
|
||||
public Class<BeastSkin> getItemType() {
|
||||
return BeastSkin.class;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,10 @@ import cz.jzitnik.client.game.items.types.weapons.Sword;
|
||||
)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = Food.class, name = "food"),
|
||||
@JsonSubTypes.Type(value = Sword.class, name = "weapon_sword")
|
||||
@JsonSubTypes.Type(value = Sword.class, name = "weapon_sword"),
|
||||
@JsonSubTypes.Type(value = Junk.class, name = "junk"),
|
||||
@JsonSubTypes.Type(value = Key.class, name = "key"),
|
||||
@JsonSubTypes.Type(value = BeastSkin.class, name = "beast_skin"),
|
||||
})
|
||||
public interface ItemType<T> {
|
||||
Class<T> getItemType();
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package cz.jzitnik.client.game.items.types;
|
||||
|
||||
public class Junk implements ItemType<Junk> {
|
||||
@Override
|
||||
public Class<Junk> getItemType() {
|
||||
return Junk.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package cz.jzitnik.client.game.items.types;
|
||||
|
||||
public class Key implements ItemType<Key> {
|
||||
@Override
|
||||
public Class<Key> getItemType() {
|
||||
return Key.class;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
package cz.jzitnik.client.game.mobs;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonInject;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.client.game.ResourceManager;
|
||||
import cz.jzitnik.common.models.coordinates.RoomPart;
|
||||
import cz.jzitnik.client.game.dialog.Dialog;
|
||||
import cz.jzitnik.client.game.mobs.tasks.MobRoomTask;
|
||||
@@ -10,14 +14,20 @@ import cz.jzitnik.client.states.DialogState;
|
||||
import cz.jzitnik.client.utils.events.EventManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
@Slf4j
|
||||
public abstract class DialogMob extends Mob {
|
||||
public class DialogMob extends Mob {
|
||||
protected Dialog dialog;
|
||||
|
||||
public DialogMob(BufferedImage texture, MobRoomTask[] tasks, RoomCords cords, RoomPart collider, Dialog dialog) {
|
||||
super(texture, tasks, cords, collider);
|
||||
@JsonCreator
|
||||
public DialogMob(
|
||||
@JsonProperty("texture") ResourceManager.Resource texture,
|
||||
@JsonProperty("tasks") MobRoomTask[] tasks,
|
||||
@JsonProperty("cords") RoomCords cords,
|
||||
@JsonProperty("collider") RoomPart collider,
|
||||
@JsonProperty("dialog") Dialog dialog,
|
||||
@JacksonInject ResourceManager resourceManager
|
||||
) {
|
||||
super(resourceManager.getResource(texture), tasks, cords, collider);
|
||||
this.dialog = dialog;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,10 +55,9 @@ public class HittableMobDrops extends HittableMob {
|
||||
Player player = gameState.getPlayer();
|
||||
RoomCords enemyCords = getCords();
|
||||
BufferedImage enemyTexture = getTexture();
|
||||
GameRoom currentRoom = gameState.getCurrentRoom();
|
||||
|
||||
int roomX = enemyCords.getX() + enemyTexture.getWidth() / 2;
|
||||
int roomY = enemyCords.getY() + enemyTexture.getHeight() / 2;
|
||||
GameRoom currentRoom = gameState.getCurrentRoom();
|
||||
|
||||
List<Event> events = new ArrayList<>();
|
||||
|
||||
@@ -71,17 +70,21 @@ public class HittableMobDrops extends HittableMob {
|
||||
events.add(new InventoryRerender());
|
||||
}
|
||||
} else {
|
||||
double angle = ThreadLocalRandom.current().nextDouble(0, Math.PI * 2);
|
||||
double radius = ThreadLocalRandom.current().nextDouble(0, DROP_ITEM_ON_GROUND_RADIUS);
|
||||
int randomX = roomX + (int) (Math.cos(angle) * radius);
|
||||
int randomY = roomY + (int) (Math.sin(angle) * radius);
|
||||
RoomCords itemCords = new RoomCords(randomX, randomY);
|
||||
DroppedItem droppedItem = new DroppedItem(currentRoom, itemCords, item);
|
||||
currentRoom.getDroppedItems().add(droppedItem);
|
||||
events.add(new DroppedItemRerender(droppedItem));
|
||||
events.add(dropItem(roomX, roomY, currentRoom, item));
|
||||
}
|
||||
}
|
||||
|
||||
eventManager.emitEvent(events, this::afterKill);
|
||||
}
|
||||
|
||||
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);
|
||||
int randomX = x + (int) (Math.cos(angle) * radius);
|
||||
int randomY = y + (int) (Math.sin(angle) * radius);
|
||||
RoomCords itemCords = new RoomCords(randomX, randomY);
|
||||
DroppedItem droppedItem = new DroppedItem(currentRoom, itemCords, item);
|
||||
currentRoom.getDroppedItems().add(droppedItem);
|
||||
return new DroppedItemRerender(droppedItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package cz.jzitnik.client.game.setup.scenes;
|
||||
|
||||
import cz.jzitnik.client.screens.DeathScreen;
|
||||
import cz.jzitnik.client.screens.Screen;
|
||||
import cz.jzitnik.client.screens.scenes.Scene;
|
||||
|
||||
public class DeathScene extends Scene {
|
||||
public DeathScene() {
|
||||
super(new Screen[]{new DeathScreen()}, new OnEndAction.Repeat());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cz.jzitnik.client.game.setup.scenes;
|
||||
|
||||
import cz.jzitnik.client.screens.WinScreen;
|
||||
import cz.jzitnik.client.screens.Screen;
|
||||
import cz.jzitnik.client.screens.scenes.Scene;
|
||||
|
||||
public class WinScene extends Scene {
|
||||
public WinScene() {
|
||||
super(new Screen[]{new WinScreen()}, new OnEndAction.Repeat());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package cz.jzitnik.client.screens;
|
||||
|
||||
import com.googlecode.lanterna.SGR;
|
||||
import com.googlecode.lanterna.TextColor;
|
||||
import com.googlecode.lanterna.graphics.TextGraphics;
|
||||
import com.googlecode.lanterna.screen.TerminalScreen;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.client.events.KeyboardPressEvent;
|
||||
import cz.jzitnik.client.events.MouseAction;
|
||||
import cz.jzitnik.client.states.TerminalState;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DeathScreen extends Screen {
|
||||
@InjectState
|
||||
private TerminalState terminalState;
|
||||
|
||||
@Override
|
||||
public void fullRender() {
|
||||
TerminalScreen screen = terminalState.getTerminalScreen();
|
||||
screen.clear();
|
||||
TextGraphics tg = terminalState.getTextGraphics();
|
||||
|
||||
int termWidth = screen.getTerminalSize().getColumns();
|
||||
int termHeight = screen.getTerminalSize().getRows();
|
||||
|
||||
String message = "GAME OVER";
|
||||
tg.setForegroundColor(TextColor.ANSI.RED);
|
||||
tg.enableModifiers(SGR.BOLD);
|
||||
tg.putString((termWidth - message.length()) / 2, termHeight / 2, message);
|
||||
|
||||
try {
|
||||
screen.refresh(com.googlecode.lanterna.screen.Screen.RefreshType.COMPLETE);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMouseAction(MouseAction event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleKeyboardAction(KeyboardPressEvent event) {
|
||||
}
|
||||
}
|
||||
46
game/src/main/java/cz/jzitnik/client/screens/WinScreen.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package cz.jzitnik.client.screens;
|
||||
|
||||
import com.googlecode.lanterna.SGR;
|
||||
import com.googlecode.lanterna.TextColor;
|
||||
import com.googlecode.lanterna.graphics.TextGraphics;
|
||||
import com.googlecode.lanterna.screen.TerminalScreen;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.client.events.KeyboardPressEvent;
|
||||
import cz.jzitnik.client.events.MouseAction;
|
||||
import cz.jzitnik.client.states.TerminalState;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class WinScreen extends Screen {
|
||||
@InjectState
|
||||
private TerminalState terminalState;
|
||||
|
||||
@Override
|
||||
public void fullRender() {
|
||||
TerminalScreen screen = terminalState.getTerminalScreen();
|
||||
screen.clear();
|
||||
TextGraphics tg = terminalState.getTextGraphics();
|
||||
|
||||
int termWidth = screen.getTerminalSize().getColumns();
|
||||
int termHeight = screen.getTerminalSize().getRows();
|
||||
|
||||
String message = "YOU WON!";
|
||||
tg.setForegroundColor(TextColor.ANSI.GREEN);
|
||||
tg.enableModifiers(SGR.BOLD);
|
||||
tg.putString((termWidth - message.length()) / 2, termHeight / 2, message);
|
||||
|
||||
try {
|
||||
screen.refresh(com.googlecode.lanterna.screen.Screen.RefreshType.COMPLETE);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMouseAction(MouseAction event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleKeyboardAction(KeyboardPressEvent event) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cz.jzitnik.client.socket.events;
|
||||
|
||||
import cz.jzitnik.client.annotations.SocketEventHandler;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.client.game.GameState;
|
||||
import cz.jzitnik.client.game.setup.scenes.WinScene;
|
||||
import cz.jzitnik.client.socket.AbstractSocketEventHandler;
|
||||
import cz.jzitnik.common.socket.messages.game.GameWin;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@SocketEventHandler(GameWin.class)
|
||||
public class GameWinHandler extends AbstractSocketEventHandler<GameWin> {
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
|
||||
@InjectDependency
|
||||
private cz.jzitnik.client.utils.roomtasks.RoomTaskScheduler roomTaskScheduler;
|
||||
|
||||
@Override
|
||||
public void handle(GameWin event) {
|
||||
log.debug("Game won!");
|
||||
roomTaskScheduler.finalShutdown();
|
||||
WinScene winScene = new WinScene();
|
||||
gameState.setScreen(winScene);
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
winScene.fullRender();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cz.jzitnik.client.socket.events;
|
||||
|
||||
import cz.jzitnik.client.annotations.SocketEventHandler;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
||||
import cz.jzitnik.client.annotations.injectors.InjectState;
|
||||
import cz.jzitnik.client.game.GameState;
|
||||
import cz.jzitnik.client.game.setup.scenes.DeathScene;
|
||||
import cz.jzitnik.client.socket.AbstractSocketEventHandler;
|
||||
import cz.jzitnik.client.utils.DependencyManager;
|
||||
import cz.jzitnik.common.socket.messages.game.PlayerDeath;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@SocketEventHandler(PlayerDeath.class)
|
||||
public class PlayerDeathHandler extends AbstractSocketEventHandler<PlayerDeath> {
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
|
||||
@InjectDependency
|
||||
private DependencyManager dependencyManager;
|
||||
|
||||
@InjectDependency
|
||||
private cz.jzitnik.client.utils.roomtasks.RoomTaskScheduler roomTaskScheduler;
|
||||
|
||||
@Override
|
||||
public void handle(PlayerDeath event) {
|
||||
log.debug("Player death: {}", event.playerId());
|
||||
roomTaskScheduler.finalShutdown();
|
||||
DeathScene deathScene = new DeathScene();
|
||||
dependencyManager.inject(deathScene);
|
||||
gameState.setScreen(deathScene);
|
||||
deathScene.fullRender();
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import cz.jzitnik.client.annotations.ui.UI;
|
||||
import cz.jzitnik.client.events.MouseAction;
|
||||
import cz.jzitnik.client.events.RerenderScreen;
|
||||
import cz.jzitnik.client.events.handlers.DialogEventHandler;
|
||||
import cz.jzitnik.client.game.GameState;
|
||||
import cz.jzitnik.client.game.dialog.OnEnd;
|
||||
import cz.jzitnik.client.states.DialogState;
|
||||
import cz.jzitnik.client.states.ScreenBuffer;
|
||||
@@ -27,42 +28,57 @@ import static cz.jzitnik.client.events.handlers.DialogEventHandler.*;
|
||||
@UI
|
||||
@Dependency
|
||||
public class DialogUI {
|
||||
|
||||
@InjectState
|
||||
private DialogState dialogState;
|
||||
|
||||
@InjectState
|
||||
private TerminalState terminalState;
|
||||
|
||||
@InjectState
|
||||
private ScreenBuffer screenBuffer;
|
||||
|
||||
@InjectState
|
||||
private GameState gameState;
|
||||
|
||||
@InjectDependency
|
||||
private TextRenderer textRenderer;
|
||||
|
||||
@InjectDependency
|
||||
private EventManager eventManager;
|
||||
|
||||
@InjectState
|
||||
private ScreenBuffer screenBuffer;
|
||||
|
||||
@MouseHandler(MouseHandlerType.CLICK)
|
||||
public boolean handleClick(MouseAction mouseAction) {
|
||||
if (dialogState.getCurrentDialog() == null || dialogState.isRenderInProgress()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TerminalSize size = DialogEventHandler.getSize(textRenderer, dialogState.getCurrentDialog());
|
||||
TerminalPosition start = DialogEventHandler.getStart(terminalState.getTerminalScreen().getTerminalSize(), size);
|
||||
var dialog = dialogState.getCurrentDialog();
|
||||
TerminalSize size = DialogEventHandler.getSize(textRenderer, dialog, gameState);
|
||||
TerminalPosition start = DialogEventHandler.getStart(
|
||||
terminalState.getTerminalScreen().getTerminalSize(),
|
||||
size
|
||||
);
|
||||
|
||||
if (!(dialogState.getCurrentDialog().getOnEnd() instanceof OnEnd.AskQuestion(
|
||||
OnEnd.AskQuestion.Answer[] answers
|
||||
))) {
|
||||
if (!(dialog.getOnEnd() instanceof OnEnd.AskQuestion askQuestion)) {
|
||||
setHoveredButtonIndex(-1);
|
||||
return false;
|
||||
}
|
||||
|
||||
var answers = askQuestion.answers(gameState);
|
||||
|
||||
TerminalPosition mouse = mouseAction.getPosition();
|
||||
TerminalPosition mouseNormalized = new TerminalPosition(mouse.getColumn(), mouse.getRow() * 2);
|
||||
TerminalPosition mouseNormalized = new TerminalPosition(
|
||||
mouse.getColumn(),
|
||||
mouse.getRow() * 2
|
||||
);
|
||||
|
||||
RerenderScreen.ScreenPart part = new RerenderScreen.ScreenPart(
|
||||
start,
|
||||
new TerminalPosition(start.getColumn() + size.getColumns(), start.getRow() + size.getRows())
|
||||
new TerminalPosition(
|
||||
start.getColumn() + size.getColumns(),
|
||||
start.getRow() + size.getRows()
|
||||
)
|
||||
);
|
||||
|
||||
if (!part.isWithin(mouseNormalized)) {
|
||||
@@ -70,9 +86,13 @@ public class DialogUI {
|
||||
return false;
|
||||
}
|
||||
|
||||
int buttonsStartY = DialogEventHandler.getYStartButtons(textRenderer, dialogState.getCurrentDialog());
|
||||
TerminalPosition localPosition = new TerminalPosition(mouseNormalized.getColumn() - start.getColumn(), mouseNormalized.getRow() - start.getRow() - buttonsStartY);
|
||||
int buttonsHeight = DialogEventHandler.calculateButtonHeight(dialogState.getCurrentDialog());
|
||||
int buttonsStartY = DialogEventHandler.getYStartButtons(textRenderer, dialog);
|
||||
TerminalPosition localPosition = new TerminalPosition(
|
||||
mouseNormalized.getColumn() - start.getColumn(),
|
||||
mouseNormalized.getRow() - start.getRow() - buttonsStartY
|
||||
);
|
||||
|
||||
int buttonsHeight = DialogEventHandler.calculateButtonHeight(dialog, gameState);
|
||||
|
||||
if (localPosition.getRow() < 0 || localPosition.getRow() >= buttonsHeight) {
|
||||
setHoveredButtonIndex(-1);
|
||||
@@ -82,23 +102,27 @@ public class DialogUI {
|
||||
int buttonIndex = localPosition.getRow() / (BUTTON_HEIGHT + BUTTON_PADDING);
|
||||
int rest = localPosition.getRow() % (BUTTON_HEIGHT + BUTTON_PADDING);
|
||||
|
||||
if (buttonIndex < answers.length && rest < BUTTON_HEIGHT && localPosition.getColumn() >= PADDING && localPosition.getColumn() < size.getColumns() - PADDING) {
|
||||
for (int y = start.getRow(); y < start.getRow() + size.getRows(); y++) {
|
||||
for (int x = start.getColumn(); x < start.getColumn() + size.getColumns(); x++) {
|
||||
screenBuffer.getGlobalOverrideBuffer()[y][x] = new Empty();
|
||||
}
|
||||
}
|
||||
if (buttonIndex < answers.length
|
||||
&& rest < BUTTON_HEIGHT
|
||||
&& localPosition.getColumn() >= PADDING
|
||||
&& localPosition.getColumn() < size.getColumns() - PADDING) {
|
||||
|
||||
clearDialog(start, size);
|
||||
|
||||
eventManager.emitEvent(
|
||||
new Event[]{
|
||||
new RerenderScreen(
|
||||
new RerenderScreen.ScreenPart(
|
||||
start,
|
||||
new TerminalPosition(start.getColumn() + size.getColumns(), start.getRow() + size.getRows())
|
||||
new TerminalPosition(
|
||||
start.getColumn() + size.getColumns(),
|
||||
start.getRow() + size.getRows()
|
||||
)
|
||||
)
|
||||
),
|
||||
answers[buttonIndex].dialog(),
|
||||
});
|
||||
answers[buttonIndex].dialog()
|
||||
}
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -112,21 +136,32 @@ public class DialogUI {
|
||||
return false;
|
||||
}
|
||||
|
||||
TerminalSize size = DialogEventHandler.getSize(textRenderer, dialogState.getCurrentDialog());
|
||||
TerminalPosition start = DialogEventHandler.getStart(terminalState.getTerminalScreen().getTerminalSize(), size);
|
||||
var dialog = dialogState.getCurrentDialog();
|
||||
TerminalSize size = DialogEventHandler.getSize(textRenderer, dialog, gameState);
|
||||
TerminalPosition start = DialogEventHandler.getStart(
|
||||
terminalState.getTerminalScreen().getTerminalSize(),
|
||||
size
|
||||
);
|
||||
|
||||
if (!(dialogState.getCurrentDialog().getOnEnd() instanceof OnEnd.AskQuestion(
|
||||
OnEnd.AskQuestion.Answer[] answers
|
||||
))) {
|
||||
if (!(dialog.getOnEnd() instanceof OnEnd.AskQuestion askQuestion)) {
|
||||
setHoveredButtonIndex(-1);
|
||||
return false;
|
||||
}
|
||||
|
||||
var answers = askQuestion.answers(gameState);
|
||||
|
||||
TerminalPosition mouse = mouseAction.getPosition();
|
||||
TerminalPosition mouseNormalized = new TerminalPosition(mouse.getColumn(), mouse.getRow() * 2);
|
||||
TerminalPosition mouseNormalized = new TerminalPosition(
|
||||
mouse.getColumn(),
|
||||
mouse.getRow() * 2
|
||||
);
|
||||
|
||||
RerenderScreen.ScreenPart part = new RerenderScreen.ScreenPart(
|
||||
start,
|
||||
new TerminalPosition(start.getColumn() + size.getColumns(), start.getRow() + size.getRows())
|
||||
new TerminalPosition(
|
||||
start.getColumn() + size.getColumns(),
|
||||
start.getRow() + size.getRows()
|
||||
)
|
||||
);
|
||||
|
||||
if (!part.isWithin(mouseNormalized)) {
|
||||
@@ -134,9 +169,13 @@ public class DialogUI {
|
||||
return false;
|
||||
}
|
||||
|
||||
int buttonsStartY = DialogEventHandler.getYStartButtons(textRenderer, dialogState.getCurrentDialog());
|
||||
TerminalPosition localPosition = new TerminalPosition(mouseNormalized.getColumn() - start.getColumn(), mouseNormalized.getRow() - start.getRow() - buttonsStartY);
|
||||
int buttonsHeight = DialogEventHandler.calculateButtonHeight(dialogState.getCurrentDialog());
|
||||
int buttonsStartY = DialogEventHandler.getYStartButtons(textRenderer, dialog);
|
||||
TerminalPosition localPosition = new TerminalPosition(
|
||||
mouseNormalized.getColumn() - start.getColumn(),
|
||||
mouseNormalized.getRow() - start.getRow() - buttonsStartY
|
||||
);
|
||||
|
||||
int buttonsHeight = DialogEventHandler.calculateButtonHeight(dialog, gameState);
|
||||
|
||||
if (localPosition.getRow() < 0 || localPosition.getRow() >= buttonsHeight) {
|
||||
setHoveredButtonIndex(-1);
|
||||
@@ -146,7 +185,11 @@ public class DialogUI {
|
||||
int buttonIndex = localPosition.getRow() / (BUTTON_HEIGHT + BUTTON_PADDING);
|
||||
int rest = localPosition.getRow() % (BUTTON_HEIGHT + BUTTON_PADDING);
|
||||
|
||||
if (buttonIndex < answers.length && rest < BUTTON_HEIGHT && localPosition.getColumn() >= PADDING && localPosition.getColumn() < size.getColumns() - PADDING) {
|
||||
if (buttonIndex < answers.length
|
||||
&& rest < BUTTON_HEIGHT
|
||||
&& localPosition.getColumn() >= PADDING
|
||||
&& localPosition.getColumn() < size.getColumns() - PADDING) {
|
||||
|
||||
setHoveredButtonIndex(buttonIndex);
|
||||
return true;
|
||||
}
|
||||
@@ -161,4 +204,12 @@ public class DialogUI {
|
||||
eventManager.emitEvent(dialogState.getCurrentDialog());
|
||||
}
|
||||
}
|
||||
|
||||
private void clearDialog(TerminalPosition start, TerminalSize size) {
|
||||
for (int y = start.getRow(); y < start.getRow() + size.getRows(); y++) {
|
||||
for (int x = start.getColumn(); x < start.getColumn() + size.getColumns(); x++) {
|
||||
screenBuffer.getGlobalOverrideBuffer()[y][x] = new Empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import tools.jackson.databind.*;
|
||||
import tools.jackson.dataformat.yaml.YAMLFactory;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -48,7 +49,7 @@ public class DependencyManager extends InjectableValues {
|
||||
|
||||
// Construct all classes
|
||||
for (Class<?> clazz : classes) {
|
||||
for (var constructor : clazz.getDeclaredConstructors()) {
|
||||
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
|
||||
var paramTypes = constructor.getParameterTypes();
|
||||
var params = new Object[paramTypes.length];
|
||||
boolean suitable = true;
|
||||
|
||||
@@ -64,7 +64,6 @@ public class EventManager extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EventManager(Reflections reflections, DependencyManager dependencyManager) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
setDaemon(true);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
renderColliders: false
|
||||
renderPlayerCollider: false
|
||||
showPlayerCordsLogs: false
|
||||
renderColliders: true
|
||||
renderPlayerCollider: true
|
||||
showPlayerCordsLogs: true
|
||||
@@ -1,216 +1,331 @@
|
||||
# =========================
|
||||
# START ROOM
|
||||
# Intro NPC explains the goal + starter chest
|
||||
# =========================
|
||||
- id: "spawn"
|
||||
texture: "ROOM1"
|
||||
#mobs:
|
||||
# - type: "hittable_drops"
|
||||
# texture: "PLAYER_FRONT"
|
||||
# cords:
|
||||
# x: 100
|
||||
# y: 100
|
||||
# collider:
|
||||
# start:
|
||||
# x: 0
|
||||
# y: 52
|
||||
# end:
|
||||
# x: 44
|
||||
# y: 78
|
||||
# health: 10
|
||||
# itemsDrops:
|
||||
# - name: "Apple"
|
||||
# type:
|
||||
# name: "food"
|
||||
# addHealth: 1
|
||||
# texture: "APPLE"
|
||||
# tasks:
|
||||
# - type: "blind_following_player"
|
||||
# speed: 1
|
||||
# updateRateMs: 100
|
||||
# - type: "attacking_player"
|
||||
# damage: 5
|
||||
# reach: 15
|
||||
# updateRateMs: 500
|
||||
west: "empty"
|
||||
texture: "ROOM11"
|
||||
colliders:
|
||||
- start: { x: 76, y: 45 }
|
||||
end: { x: 155, y: 67 }
|
||||
- start: { x: 40, y: 160 }
|
||||
end: { x: 70, y: 190 }
|
||||
- start: { x: 150, y: 160 }
|
||||
end: { x: 185, y: 190 }
|
||||
|
||||
mobs:
|
||||
- type: "dialog"
|
||||
texture: "OLD_MAN"
|
||||
cords: { x: 90, y: 90 }
|
||||
collider:
|
||||
start: { x: 0, y: 52 }
|
||||
end: { x: 44, y: 78 }
|
||||
dialog:
|
||||
text: "You fell down here too? This cave is cursed..."
|
||||
onEnd:
|
||||
type: continue
|
||||
nextDialog:
|
||||
text: "The only way out is guarded by a beast deep inside."
|
||||
onEnd:
|
||||
type: continue
|
||||
nextDialog:
|
||||
text: "Kill it. Bring its skin to the Key Keeper."
|
||||
onEnd:
|
||||
type: continue
|
||||
nextDialog:
|
||||
text: "He will give you the key to the final gate."
|
||||
onEnd: { type: end }
|
||||
|
||||
west: "empty_a"
|
||||
east: "truhlaright"
|
||||
north: null
|
||||
south: null
|
||||
|
||||
|
||||
|
||||
# =========================
|
||||
# LOOT ROOM 1
|
||||
# =========================
|
||||
- id: "truhlaright"
|
||||
texture: "ROOM1"
|
||||
objects:
|
||||
- objectType: "chest"
|
||||
cords:
|
||||
x: 100
|
||||
y: 45
|
||||
items:
|
||||
- id: 1
|
||||
name: "Wooden sword"
|
||||
type:
|
||||
name: "weapon_sword"
|
||||
dealDamage: 1
|
||||
texture: "WOODEN_SWORD"
|
||||
- id: 2
|
||||
name: "Apple"
|
||||
type:
|
||||
name: "food"
|
||||
addHealth: 1
|
||||
texture: "APPLE"
|
||||
texture: "ROOM5"
|
||||
colliders:
|
||||
- start:
|
||||
x: 100
|
||||
y: 45
|
||||
end:
|
||||
x: 140
|
||||
y: 67
|
||||
- start: { x: 90, y: 100 }
|
||||
end: { x: 140, y: 145 }
|
||||
- start: { x: 40, y: 70 }
|
||||
end: { x: 80, y: 100 }
|
||||
west: "spawn"
|
||||
east: null
|
||||
east: "filler_1"
|
||||
north: "klicnik"
|
||||
south: null
|
||||
south: "filler_south_1"
|
||||
|
||||
- id: "empty"
|
||||
texture: "ROOM1"
|
||||
west: null
|
||||
east: "spawn"
|
||||
north: "truhlatop"
|
||||
south: null
|
||||
# =========================
|
||||
# KEY KEEPER (QUEST NPC)
|
||||
# =========================
|
||||
- id: "klicnik"
|
||||
texture: "ROOM10"
|
||||
mobs:
|
||||
- type: "dialog"
|
||||
texture: "KEY_KEEPER"
|
||||
cords: { x: 90, y: 60 }
|
||||
collider:
|
||||
start: { x: 0, y: 52 }
|
||||
end: { x: 44, y: 78 }
|
||||
dialog:
|
||||
text: "Want to leave? Bring me the beast's skin."
|
||||
onEnd:
|
||||
type: ask_question
|
||||
answers:
|
||||
- answer: "I have it"
|
||||
requirement:
|
||||
item: "BeastSkin"
|
||||
dialog:
|
||||
text: "Well done. Here is the key."
|
||||
onEnd:
|
||||
type: "give_item"
|
||||
item:
|
||||
id: 800
|
||||
name: "Key"
|
||||
type: { name: "key" }
|
||||
texture: "APPLE"
|
||||
then: { type: end }
|
||||
- answer: "Not yet"
|
||||
dialog:
|
||||
text: "Then go back before it finds you."
|
||||
onEnd: { type: end }
|
||||
|
||||
- id: "truhlatop"
|
||||
texture: "ROOM1"
|
||||
objects:
|
||||
- objectType: "chest"
|
||||
cords:
|
||||
x: 100
|
||||
y: 45
|
||||
items:
|
||||
- id: 3
|
||||
name: "Wooden sword"
|
||||
type:
|
||||
name: "weapon_sword"
|
||||
dealDamage: 1
|
||||
texture: "WOODEN_SWORD"
|
||||
- id: 4
|
||||
name: "Apple"
|
||||
type:
|
||||
name: "food"
|
||||
addHealth: 1
|
||||
texture: "APPLE"
|
||||
colliders:
|
||||
- start:
|
||||
x: 100
|
||||
y: 45
|
||||
end:
|
||||
x: 140
|
||||
y: 67
|
||||
west: "empty2"
|
||||
east: null
|
||||
north: null
|
||||
south: "empty"
|
||||
west: "filler_k_west"
|
||||
east: "truhlarightright"
|
||||
north: "final_room"
|
||||
south: "truhlaright"
|
||||
|
||||
- id: "empty2"
|
||||
texture: "ROOM1"
|
||||
west: null
|
||||
east: "truhlatop"
|
||||
north: "boss"
|
||||
south: null
|
||||
|
||||
|
||||
# =========================
|
||||
# BOSS ROOM
|
||||
# =========================
|
||||
- id: "boss"
|
||||
texture: "ROOM1"
|
||||
texture: "ROOM3"
|
||||
mobs:
|
||||
- type: "hittable_drops"
|
||||
texture: "PLAYER_FRONT"
|
||||
cords:
|
||||
x: 100
|
||||
y: 100
|
||||
texture: "CAVE_BEAST"
|
||||
cords: { x: 100, y: 100 }
|
||||
collider:
|
||||
start:
|
||||
x: 0
|
||||
y: 52
|
||||
end:
|
||||
x: 44
|
||||
y: 78
|
||||
health: 10
|
||||
start: { x: 0, y: 52 }
|
||||
end: { x: 44, y: 78 }
|
||||
health: 40
|
||||
itemsDrops:
|
||||
- id: 5
|
||||
name: "Apple"
|
||||
type:
|
||||
name: "food"
|
||||
addHealth: 1
|
||||
texture: "APPLE"
|
||||
- id: 200
|
||||
name: "Beast Skin"
|
||||
type: { name: "beast_skin" }
|
||||
texture: "BOSS_SKIN"
|
||||
tasks:
|
||||
- type: "following_player"
|
||||
speed: 2
|
||||
updateRateMs: 80
|
||||
- type: "attacking_player"
|
||||
damage: 8
|
||||
reach: 18
|
||||
updateRateMs: 400
|
||||
west: "filler_boss_west"
|
||||
east: null
|
||||
north: null
|
||||
south: "empty_c"
|
||||
|
||||
|
||||
|
||||
# =========================
|
||||
# FINAL ROOM / EXIT
|
||||
# =========================
|
||||
- id: "final_room"
|
||||
texture: "ROOM6"
|
||||
requirement:
|
||||
item: "Key"
|
||||
end: true
|
||||
west: null
|
||||
east: null
|
||||
north: null
|
||||
south: "klicnik"
|
||||
|
||||
|
||||
|
||||
# =========================
|
||||
# COMBAT FILLER A (zombie)
|
||||
# =========================
|
||||
- id: "empty_a"
|
||||
texture: "ROOM7"
|
||||
mobs:
|
||||
- type: "hittable_drops"
|
||||
texture: "ZOMBIE"
|
||||
cords: { x: 110, y: 100 }
|
||||
collider:
|
||||
start: { x: 0, y: 52 }
|
||||
end: { x: 44, y: 78 }
|
||||
health: 6
|
||||
tasks:
|
||||
- type: "following_player"
|
||||
speed: 1
|
||||
updateRateMs: 100
|
||||
updateRateMs: 120
|
||||
- type: "attacking_player"
|
||||
damage: 20
|
||||
damage: 2
|
||||
reach: 15
|
||||
updateRateMs: 500
|
||||
west: null
|
||||
east: null
|
||||
north: null
|
||||
south: "empty2"
|
||||
updateRateMs: 700
|
||||
west: "filler_2"
|
||||
east: "spawn"
|
||||
north: "empty_c"
|
||||
south: "filler_deadend_1"
|
||||
|
||||
- id: "klicnik"
|
||||
|
||||
|
||||
# =========================
|
||||
# COMBAT FILLER B (blind hunter)
|
||||
# =========================
|
||||
- id: "empty_c"
|
||||
texture: "ROOM1"
|
||||
mobs:
|
||||
- type: "hittable_drops"
|
||||
texture: "PLAYER_FRONT"
|
||||
cords:
|
||||
x: 100
|
||||
y: 100
|
||||
texture: "BLIND_HUNTER"
|
||||
cords: { x: 100, y: 100 }
|
||||
collider:
|
||||
start:
|
||||
x: 0
|
||||
y: 52
|
||||
end:
|
||||
x: 44
|
||||
y: 78
|
||||
health: 10
|
||||
itemsDrops:
|
||||
- id: 6
|
||||
name: "Apple"
|
||||
type:
|
||||
name: "food"
|
||||
addHealth: 1
|
||||
texture: "APPLE"
|
||||
start: { x: 0, y: 52 }
|
||||
end: { x: 44, y: 78 }
|
||||
health: 20
|
||||
tasks:
|
||||
- type: "blind_following_player"
|
||||
speed: 1
|
||||
updateRateMs: 100
|
||||
- type: "attacking_player"
|
||||
damage: 5
|
||||
damage: 6
|
||||
reach: 15
|
||||
updateRateMs: 500
|
||||
west: null
|
||||
east: "truhlarightright"
|
||||
north: null
|
||||
south: "truhlaright"
|
||||
west: "filler_c_west"
|
||||
east: null
|
||||
north: "boss"
|
||||
south: "empty_a"
|
||||
|
||||
|
||||
|
||||
# =========================
|
||||
# LOOT ROOM 2
|
||||
# =========================
|
||||
- id: "truhlarightright"
|
||||
texture: "ROOM1"
|
||||
texture: "ROOM2"
|
||||
objects:
|
||||
- objectType: "chest"
|
||||
cords: { x: 100, y: 45 }
|
||||
items:
|
||||
- id: 7
|
||||
name: "Axe"
|
||||
type: { name: "weapon_sword", dealDamage: 4, attackCooldownMs: 800 } # TODO: Make it an axe
|
||||
texture: "AXE"
|
||||
- id: 8
|
||||
name: "Apple"
|
||||
type: { name: "food", addHealth: 2 }
|
||||
texture: "APPLE"
|
||||
colliders:
|
||||
- start: { x: 100, y: 45 }
|
||||
end: { x: 140, y: 67 }
|
||||
west: "klicnik"
|
||||
east: "filler_rr_east"
|
||||
north: null
|
||||
south: null
|
||||
|
||||
|
||||
|
||||
# =========================
|
||||
# EXTRA FILLER ROOMS (maze / dead ends)
|
||||
# =========================
|
||||
- id: "filler_1"
|
||||
texture: "ROOM3"
|
||||
west: "truhlaright"
|
||||
east: "filler_1b"
|
||||
north: null
|
||||
south: null
|
||||
|
||||
- id: "filler_1b"
|
||||
texture: "ROOM1"
|
||||
west: "filler_1"
|
||||
east: null
|
||||
north: null
|
||||
south: null
|
||||
objects:
|
||||
- objectType: "chest"
|
||||
cords:
|
||||
x: 100
|
||||
y: 45
|
||||
items:
|
||||
- id: 7
|
||||
name: "Wooden sword"
|
||||
type:
|
||||
name: "weapon_sword"
|
||||
dealDamage: 1
|
||||
texture: "WOODEN_SWORD"
|
||||
- id: 8
|
||||
name: "Apple"
|
||||
type:
|
||||
name: "food"
|
||||
addHealth: 1
|
||||
texture: "APPLE"
|
||||
colliders:
|
||||
- start:
|
||||
x: 100
|
||||
y: 45
|
||||
end:
|
||||
x: 140
|
||||
y: 67
|
||||
|
||||
- id: "filler_2"
|
||||
texture: "ROOM7"
|
||||
west: null
|
||||
east: "empty_a"
|
||||
north: "filler_loop_1"
|
||||
south: null
|
||||
|
||||
- id: "filler_loop_1"
|
||||
texture: "ROOM4"
|
||||
west: null
|
||||
east: null
|
||||
north: "filler_loop_2"
|
||||
south: "filler_2"
|
||||
|
||||
- id: "filler_loop_2"
|
||||
texture: "ROOM3"
|
||||
west: "filler_loop_3"
|
||||
east: null
|
||||
north: null
|
||||
south: "filler_loop_1"
|
||||
|
||||
- id: "filler_loop_3"
|
||||
texture: "ROOM2"
|
||||
west: null
|
||||
east: "filler_loop_2"
|
||||
north: null
|
||||
south: null
|
||||
|
||||
- id: "filler_deadend_1"
|
||||
texture: "ROOM1"
|
||||
west: null
|
||||
east: null
|
||||
north: "empty_a"
|
||||
south: null
|
||||
|
||||
- id: "filler_k_west"
|
||||
texture: "ROOM4"
|
||||
west: "filler_k_west_2"
|
||||
east: "klicnik"
|
||||
north: null
|
||||
south: null
|
||||
|
||||
- id: "filler_k_west_2"
|
||||
texture: "ROOM3"
|
||||
west: null
|
||||
east: "filler_k_west"
|
||||
north: null
|
||||
south: null
|
||||
|
||||
- id: "filler_boss_west"
|
||||
texture: "ROOM2"
|
||||
west: null
|
||||
east: "boss"
|
||||
north: null
|
||||
south: null
|
||||
|
||||
- id: "filler_c_west"
|
||||
texture: "ROOM1"
|
||||
west: null
|
||||
east: "empty_c"
|
||||
north: null
|
||||
south: null
|
||||
|
||||
- id: "filler_rr_east"
|
||||
texture: "ROOM4"
|
||||
west: "truhlarightright"
|
||||
east: null
|
||||
north: null
|
||||
south: null
|
||||
|
||||
- id: "filler_south_1"
|
||||
texture: "ROOM3"
|
||||
west: null
|
||||
east: null
|
||||
north: "truhlaright"
|
||||
south: "filler_south_2"
|
||||
|
||||
- id: "filler_south_2"
|
||||
texture: "ROOM2"
|
||||
west: null
|
||||
east: null
|
||||
north: "filler_south_1"
|
||||
south: null
|
||||
BIN
game/src/main/resources/textures/rooms/10.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
game/src/main/resources/textures/rooms/11.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
game/src/main/resources/textures/rooms/12.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
game/src/main/resources/textures/rooms/5.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
game/src/main/resources/textures/rooms/6.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
game/src/main/resources/textures/rooms/7.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
game/src/main/resources/textures/rooms/8.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
game/src/main/resources/textures/rooms/9.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
@@ -0,0 +1,21 @@
|
||||
package cz.jzitnik.server.events.handlers;
|
||||
|
||||
import cz.jzitnik.common.socket.messages.game.GameWin;
|
||||
import cz.jzitnik.server.annotations.EventHandler;
|
||||
import cz.jzitnik.server.context.GlobalContext;
|
||||
import cz.jzitnik.server.events.AbstractEventHandler;
|
||||
import cz.jzitnik.server.game.Client;
|
||||
|
||||
@EventHandler(GameWin.class)
|
||||
public class GameWinHandler extends AbstractEventHandler<GameWin> {
|
||||
public GameWinHandler(GlobalContext globalContext) {
|
||||
super(globalContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(GameWin event, Client client) {
|
||||
for (Client player : client.getGame().getPlayers()) {
|
||||
player.getSession().sendMessage(new GameWin());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cz.jzitnik.server.events.handlers;
|
||||
|
||||
import cz.jzitnik.common.socket.messages.game.PlayerDeath;
|
||||
import cz.jzitnik.server.annotations.EventHandler;
|
||||
import cz.jzitnik.server.context.GlobalContext;
|
||||
import cz.jzitnik.server.events.AbstractEventHandler;
|
||||
import cz.jzitnik.server.game.Client;
|
||||
|
||||
@EventHandler(PlayerDeath.class)
|
||||
public class PlayerDeathHandler extends AbstractEventHandler<PlayerDeath> {
|
||||
public PlayerDeathHandler(GlobalContext globalContext) {
|
||||
super(globalContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(PlayerDeath event, Client client) {
|
||||
for (Client player : client.getGame().getPlayers()) {
|
||||
player.getSession().sendMessage(new PlayerDeath(event.playerId()));
|
||||
}
|
||||
}
|
||||
}
|
||||