Compare commits
2 Commits
a8ce7b8ed1
...
f8f150cdf0
| Author | SHA1 | Date | |
|---|---|---|---|
|
f8f150cdf0
|
|||
|
8935349f92
|
1
.idea/compiler.xml
generated
1
.idea/compiler.xml
generated
@@ -34,6 +34,7 @@
|
|||||||
<entry name="$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.18.38/lombok-1.18.38.jar" />
|
<entry name="$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.18.38/lombok-1.18.38.jar" />
|
||||||
</processorPath>
|
</processorPath>
|
||||||
<module name="game (1)" />
|
<module name="game (1)" />
|
||||||
|
<module name="game" />
|
||||||
</profile>
|
</profile>
|
||||||
</annotationProcessing>
|
</annotationProcessing>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import lombok.Getter;
|
|||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -16,6 +17,13 @@ public class RoomCords implements Cloneable, Serializable {
|
|||||||
private int x;
|
private int x;
|
||||||
private int y;
|
private int y;
|
||||||
|
|
||||||
|
public RoomCords calculateCenter(BufferedImage texture) {
|
||||||
|
return new RoomCords(
|
||||||
|
x + texture.getWidth() / 2,
|
||||||
|
y + texture.getHeight() / 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public RoomCords(
|
public RoomCords(
|
||||||
@JsonProperty("x") int x,
|
@JsonProperty("x") int x,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import cz.jzitnik.client.annotations.EventHandler;
|
|||||||
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
import cz.jzitnik.client.annotations.injectors.InjectDependency;
|
||||||
import cz.jzitnik.client.annotations.injectors.InjectState;
|
import cz.jzitnik.client.annotations.injectors.InjectState;
|
||||||
import cz.jzitnik.client.events.RerenderScreen;
|
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.Dialog;
|
||||||
import cz.jzitnik.client.game.dialog.OnEnd;
|
import cz.jzitnik.client.game.dialog.OnEnd;
|
||||||
import cz.jzitnik.client.states.DialogState;
|
import cz.jzitnik.client.states.DialogState;
|
||||||
@@ -22,8 +23,8 @@ import cz.jzitnik.client.utils.events.EventManager;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@EventHandler(Dialog.class)
|
@EventHandler(Dialog.class)
|
||||||
@@ -38,6 +39,9 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
|||||||
@InjectState
|
@InjectState
|
||||||
private ScreenBuffer screenBuffer;
|
private ScreenBuffer screenBuffer;
|
||||||
|
|
||||||
|
@InjectState
|
||||||
|
private GameState gameState;
|
||||||
|
|
||||||
@InjectDependency
|
@InjectDependency
|
||||||
private EventManager eventManager;
|
private EventManager eventManager;
|
||||||
|
|
||||||
@@ -56,32 +60,45 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
|||||||
public static final int BUTTON_PADDING = 5;
|
public static final int BUTTON_PADDING = 5;
|
||||||
private static final float FONT_SIZE = 15f;
|
private static final float FONT_SIZE = 15f;
|
||||||
|
|
||||||
public static int calculateButtonHeight(Dialog dialog) {
|
public static int calculateButtonHeight(Dialog dialog, GameState gameState) {
|
||||||
if (dialog.getOnEnd() instanceof OnEnd.AskQuestion(OnEnd.AskQuestion.Answer[] answers)) {
|
if (dialog.getOnEnd() instanceof OnEnd.AskQuestion askQuestion) {
|
||||||
return answers.length * BUTTON_HEIGHT + (answers.length - 1) * BUTTON_PADDING;
|
int count = askQuestion.answers(gameState).length;
|
||||||
} else {
|
return count * BUTTON_HEIGHT + Math.max(0, count - 1) * BUTTON_PADDING;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getYStartButtons(TextRenderer textRenderer, Dialog dialog) {
|
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;
|
return PADDING + textSize.height + BUTTON_PADDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TerminalSize getSize(TextRenderer textRenderer, Dialog dialog) {
|
public static TerminalSize getSize(TextRenderer textRenderer, Dialog dialog, GameState gameState) {
|
||||||
var textSize = textRenderer.measureText(dialog.getText(), WIDTH - PADDING * 2, FONT_SIZE);
|
var textSize = textRenderer.measureText(
|
||||||
|
dialog.getText(),
|
||||||
|
WIDTH - PADDING * 2,
|
||||||
|
FONT_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
return new TerminalSize(300, PADDING + textSize.height + (
|
int buttonsHeight = 0;
|
||||||
dialog.getOnEnd() instanceof OnEnd.AskQuestion ? BUTTON_PADDING + calculateButtonHeight(dialog) : 0
|
if (dialog.getOnEnd() instanceof OnEnd.AskQuestion) {
|
||||||
) + PADDING);
|
buttonsHeight = BUTTON_PADDING + calculateButtonHeight(dialog, gameState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TerminalSize(
|
||||||
|
300,
|
||||||
|
PADDING + textSize.height + buttonsHeight + PADDING
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TerminalPosition getStart(TerminalSize terminalSize, TerminalSize size) {
|
public static TerminalPosition getStart(TerminalSize terminalSize, TerminalSize size) {
|
||||||
int startY = terminalSize.getRows() * 2 - MARGIN_BOTTOM - size.getRows();
|
int startY = terminalSize.getRows() * 2 - MARGIN_BOTTOM - size.getRows();
|
||||||
int startX = (terminalSize.getColumns() / 2) - (size.getColumns() / 2);
|
int startX = (terminalSize.getColumns() / 2) - (size.getColumns() / 2);
|
||||||
|
|
||||||
return new TerminalPosition(startX, startY);
|
return new TerminalPosition(startX, startY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,58 +106,114 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
|||||||
public void handle(Dialog event) {
|
public void handle(Dialog event) {
|
||||||
boolean onlyLast = dialogState.getCurrentDialog() == event;
|
boolean onlyLast = dialogState.getCurrentDialog() == event;
|
||||||
dialogState.setCurrentDialog(event);
|
dialogState.setCurrentDialog(event);
|
||||||
|
|
||||||
TerminalSize terminalSize = terminalState.getTerminalScreen().getTerminalSize();
|
TerminalSize terminalSize = terminalState.getTerminalScreen().getTerminalSize();
|
||||||
var overrideBuffer = screenBuffer.getGlobalOverrideBuffer();
|
var overrideBuffer = screenBuffer.getGlobalOverrideBuffer();
|
||||||
var size = getSize(textRenderer, event);
|
var size = getSize(textRenderer, event, gameState);
|
||||||
|
|
||||||
var start = getStart(terminalSize, size);
|
var start = getStart(terminalSize, size);
|
||||||
|
|
||||||
var animation = textRenderer.renderTypingAnimation(event.getText(), size.getColumns() - PADDING * 2, size.getRows() - PADDING * 2, Color.WHITE, FONT_SIZE);
|
var animation = textRenderer.renderTypingAnimation(
|
||||||
var textSize = textRenderer.measureText(event.getText(), size.getColumns() - PADDING * 2, FONT_SIZE);
|
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();
|
OnEnd onEnd = event.getOnEnd();
|
||||||
|
|
||||||
List<AlphaPixel[][]> answersBuf = new ArrayList<>();
|
List<AlphaPixel[][]> answersBuf = new ArrayList<>();
|
||||||
|
OnEnd.AskQuestion askQuestion = null;
|
||||||
|
|
||||||
if (onEnd instanceof OnEnd.AskQuestion(
|
if (onEnd instanceof OnEnd.AskQuestion aq) {
|
||||||
OnEnd.AskQuestion.Answer[] answers
|
askQuestion = aq;
|
||||||
)) {
|
for (OnEnd.AskQuestion.Answer answer : aq.answers(gameState)) {
|
||||||
for (OnEnd.AskQuestion.Answer answer : answers) {
|
answersBuf.add(
|
||||||
answersBuf.add(textRenderer.renderText(answer.answer(), size.getColumns() - PADDING * 2, BUTTON_HEIGHT, Color.BLACK, FONT_SIZE, false));
|
textRenderer.renderText(
|
||||||
|
answer.answer(),
|
||||||
|
size.getColumns() - PADDING * 2,
|
||||||
|
BUTTON_HEIGHT,
|
||||||
|
Color.BLACK,
|
||||||
|
FONT_SIZE,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogState.setRenderInProgress(true);
|
dialogState.setRenderInProgress(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (int i = onlyLast ? animation.length : 0; i <= animation.length; i++) {
|
for (int i = onlyLast ? animation.length : 0; i <= animation.length; i++) {
|
||||||
var buf = animation[Math.min(i, animation.length - 1)];
|
var buf = animation[Math.min(i, animation.length - 1)];
|
||||||
|
|
||||||
for (int y = 0; y < size.getRows(); y++) {
|
for (int y = 0; y < size.getRows(); y++) {
|
||||||
for (int x = 0; x < size.getColumns(); x++) {
|
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) {
|
var textPixel = buf[
|
||||||
if (i == animation.length && y - 2 > textSize.height + QUESTION_ACTIONS_GAP && onEnd instanceof OnEnd.AskQuestion(
|
Math.min(Math.max(0, y - PADDING), buf.length - 1)
|
||||||
OnEnd.AskQuestion.Answer[] answers
|
][
|
||||||
)) {
|
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 buttonsY = y - textSize.height - QUESTION_ACTIONS_GAP - 2;
|
||||||
int buttonIndex = buttonsY / (BUTTON_HEIGHT + BUTTON_PADDING);
|
int buttonIndex = buttonsY / (BUTTON_HEIGHT + BUTTON_PADDING);
|
||||||
int rest = 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 localY = rest - BUTTON_TEXT_PADDING;
|
||||||
int localX = x - PADDING - BUTTON_TEXT_PADDING;
|
int localX = x - PADDING - BUTTON_TEXT_PADDING;
|
||||||
|
|
||||||
var buttonBuf = answersBuf.get(buttonIndex);
|
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) {
|
if (buttonTextPixel instanceof Empty
|
||||||
overrideBuffer[start.getRow() + y][start.getColumn() + x] = new ColoredPixel(new TextColor.RGB(255, 255, 255), dialogState.getHoveredButtonIndex() == buttonIndex ? 0.8f : 0.6f);
|
|| 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 {
|
} else {
|
||||||
overrideBuffer[start.getRow() + y][start.getColumn() + x] = buttonTextPixel;
|
overrideBuffer[start.getRow() + y][start.getColumn() + x] =
|
||||||
|
buttonTextPixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +225,10 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
|||||||
new RerenderScreen(
|
new RerenderScreen(
|
||||||
new RerenderScreen.ScreenPart(
|
new RerenderScreen.ScreenPart(
|
||||||
start,
|
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);
|
dialogState.setRenderInProgress(false);
|
||||||
|
|
||||||
next(onEnd, start, size);
|
next(onEnd, start, size);
|
||||||
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -171,34 +246,38 @@ public class DialogEventHandler extends AbstractEventHandler<Dialog> {
|
|||||||
|
|
||||||
private void next(OnEnd onEnd, TerminalPosition start, TerminalSize size) throws InterruptedException {
|
private void next(OnEnd onEnd, TerminalPosition start, TerminalSize size) throws InterruptedException {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
if (onEnd instanceof OnEnd.Continue(Dialog nextDialog)) {
|
|
||||||
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 (onEnd instanceof OnEnd.Continue(Dialog nextDialog)) {
|
||||||
|
clear(start, size);
|
||||||
eventManager.emitEvent(nextDialog);
|
eventManager.emitEvent(nextDialog);
|
||||||
} else if (onEnd instanceof OnEnd.RunCode(Runnable runnable, OnEnd end)) {
|
|
||||||
|
} else if (onEnd instanceof OnEnd.RunCode runCode) {
|
||||||
|
Runnable runnable = runCode.getRunnable();
|
||||||
dependencyManager.inject(runnable);
|
dependencyManager.inject(runnable);
|
||||||
runnable.run();
|
runnable.run();
|
||||||
next(end, start, size);
|
next(runCode.getOnEnd(), start, size);
|
||||||
} else if (onEnd instanceof OnEnd.End) {
|
} else if (onEnd instanceof OnEnd.End) {
|
||||||
for (int y = start.getRow(); y < start.getRow() + size.getRows(); y++) {
|
clear(start, size);
|
||||||
for (int x = start.getColumn(); x < start.getColumn() + size.getColumns(); x++) {
|
|
||||||
screenBuffer.getGlobalOverrideBuffer()[y][x] = new Empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dialogState.setCurrentDialog(null);
|
dialogState.setCurrentDialog(null);
|
||||||
eventManager.emitEvent(
|
eventManager.emitEvent(
|
||||||
new RerenderScreen(
|
new RerenderScreen(
|
||||||
new RerenderScreen.ScreenPart(
|
new RerenderScreen.ScreenPart(
|
||||||
start,
|
start,
|
||||||
new TerminalPosition(start.getColumn() + size.getColumns(), start.getRow() + size.getRows())
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class Player implements GamePlayer {
|
|||||||
private final int id;
|
private final int id;
|
||||||
public static final int MAX_STAMINA = 20;
|
public static final int MAX_STAMINA = 20;
|
||||||
public static final int MAX_HEALTH = 30;
|
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 RoomCords playerCords;
|
||||||
private final RoomPart collider;
|
private final RoomPart collider;
|
||||||
|
|||||||
@@ -4,6 +4,21 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
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(
|
@JsonTypeInfo(
|
||||||
use = JsonTypeInfo.Id.NAME,
|
use = JsonTypeInfo.Id.NAME,
|
||||||
@@ -13,11 +28,56 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|||||||
@JsonSubTypes.Type(value = OnEnd.Continue.class, name = "continue"),
|
@JsonSubTypes.Type(value = OnEnd.Continue.class, name = "continue"),
|
||||||
@JsonSubTypes.Type(value = OnEnd.AskQuestion.class, name = "ask_question"),
|
@JsonSubTypes.Type(value = OnEnd.AskQuestion.class, name = "ask_question"),
|
||||||
@JsonSubTypes.Type(value = OnEnd.End.class, name = "end"),
|
@JsonSubTypes.Type(value = OnEnd.End.class, name = "end"),
|
||||||
|
@JsonSubTypes.Type(value = OnEnd.GiveItem.class, name = "give_item")
|
||||||
})
|
})
|
||||||
public interface OnEnd {
|
public interface OnEnd {
|
||||||
record End() implements OnEnd {}
|
record End() implements OnEnd {
|
||||||
|
}
|
||||||
|
|
||||||
record RunCode(Runnable runnable, OnEnd onEnd) implements OnEnd {} // TODO: Serialize
|
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 {
|
record Continue(Dialog nextDialog) implements OnEnd {
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
@@ -32,15 +92,44 @@ public interface OnEnd {
|
|||||||
this.answers = answers;
|
this.answers = answers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Answer(String answer, Dialog dialog) {
|
public record Answer(
|
||||||
|
String answer,
|
||||||
|
Dialog dialog,
|
||||||
|
Optional<Requirement> requirement
|
||||||
|
) {
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public Answer(
|
public Answer(
|
||||||
@JsonProperty("answer") String answer,
|
@JsonProperty("answer") String answer,
|
||||||
@JsonProperty("dialog") Dialog dialog
|
@JsonProperty("dialog") Dialog dialog,
|
||||||
|
@JsonProperty("requirement") Requirement requirement
|
||||||
) {
|
) {
|
||||||
this.answer = answer;
|
this(answer, dialog, Optional.ofNullable(requirement));
|
||||||
this.dialog = dialog;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,10 +55,9 @@ public class HittableMobDrops extends HittableMob {
|
|||||||
Player player = gameState.getPlayer();
|
Player player = gameState.getPlayer();
|
||||||
RoomCords enemyCords = getCords();
|
RoomCords enemyCords = getCords();
|
||||||
BufferedImage enemyTexture = getTexture();
|
BufferedImage enemyTexture = getTexture();
|
||||||
GameRoom currentRoom = gameState.getCurrentRoom();
|
|
||||||
|
|
||||||
int roomX = enemyCords.getX() + enemyTexture.getWidth() / 2;
|
int roomX = enemyCords.getX() + enemyTexture.getWidth() / 2;
|
||||||
int roomY = enemyCords.getY() + enemyTexture.getHeight() / 2;
|
int roomY = enemyCords.getY() + enemyTexture.getHeight() / 2;
|
||||||
|
GameRoom currentRoom = gameState.getCurrentRoom();
|
||||||
|
|
||||||
List<Event> events = new ArrayList<>();
|
List<Event> events = new ArrayList<>();
|
||||||
|
|
||||||
@@ -71,17 +70,21 @@ public class HittableMobDrops extends HittableMob {
|
|||||||
events.add(new InventoryRerender());
|
events.add(new InventoryRerender());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
double angle = ThreadLocalRandom.current().nextDouble(0, Math.PI * 2);
|
events.add(dropItem(roomX, roomY, currentRoom, item));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eventManager.emitEvent(events, this::afterKill);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import cz.jzitnik.client.annotations.ui.UI;
|
|||||||
import cz.jzitnik.client.events.MouseAction;
|
import cz.jzitnik.client.events.MouseAction;
|
||||||
import cz.jzitnik.client.events.RerenderScreen;
|
import cz.jzitnik.client.events.RerenderScreen;
|
||||||
import cz.jzitnik.client.events.handlers.DialogEventHandler;
|
import cz.jzitnik.client.events.handlers.DialogEventHandler;
|
||||||
|
import cz.jzitnik.client.game.GameState;
|
||||||
import cz.jzitnik.client.game.dialog.OnEnd;
|
import cz.jzitnik.client.game.dialog.OnEnd;
|
||||||
import cz.jzitnik.client.states.DialogState;
|
import cz.jzitnik.client.states.DialogState;
|
||||||
import cz.jzitnik.client.states.ScreenBuffer;
|
import cz.jzitnik.client.states.ScreenBuffer;
|
||||||
@@ -27,42 +28,57 @@ import static cz.jzitnik.client.events.handlers.DialogEventHandler.*;
|
|||||||
@UI
|
@UI
|
||||||
@Dependency
|
@Dependency
|
||||||
public class DialogUI {
|
public class DialogUI {
|
||||||
|
|
||||||
@InjectState
|
@InjectState
|
||||||
private DialogState dialogState;
|
private DialogState dialogState;
|
||||||
|
|
||||||
@InjectState
|
@InjectState
|
||||||
private TerminalState terminalState;
|
private TerminalState terminalState;
|
||||||
|
|
||||||
|
@InjectState
|
||||||
|
private ScreenBuffer screenBuffer;
|
||||||
|
|
||||||
|
@InjectState
|
||||||
|
private GameState gameState;
|
||||||
|
|
||||||
@InjectDependency
|
@InjectDependency
|
||||||
private TextRenderer textRenderer;
|
private TextRenderer textRenderer;
|
||||||
|
|
||||||
@InjectDependency
|
@InjectDependency
|
||||||
private EventManager eventManager;
|
private EventManager eventManager;
|
||||||
|
|
||||||
@InjectState
|
|
||||||
private ScreenBuffer screenBuffer;
|
|
||||||
|
|
||||||
@MouseHandler(MouseHandlerType.CLICK)
|
@MouseHandler(MouseHandlerType.CLICK)
|
||||||
public boolean handleClick(MouseAction mouseAction) {
|
public boolean handleClick(MouseAction mouseAction) {
|
||||||
if (dialogState.getCurrentDialog() == null || dialogState.isRenderInProgress()) {
|
if (dialogState.getCurrentDialog() == null || dialogState.isRenderInProgress()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminalSize size = DialogEventHandler.getSize(textRenderer, dialogState.getCurrentDialog());
|
var dialog = dialogState.getCurrentDialog();
|
||||||
TerminalPosition start = DialogEventHandler.getStart(terminalState.getTerminalScreen().getTerminalSize(), size);
|
TerminalSize size = DialogEventHandler.getSize(textRenderer, dialog, gameState);
|
||||||
|
TerminalPosition start = DialogEventHandler.getStart(
|
||||||
|
terminalState.getTerminalScreen().getTerminalSize(),
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
if (!(dialogState.getCurrentDialog().getOnEnd() instanceof OnEnd.AskQuestion(
|
if (!(dialog.getOnEnd() instanceof OnEnd.AskQuestion askQuestion)) {
|
||||||
OnEnd.AskQuestion.Answer[] answers
|
|
||||||
))) {
|
|
||||||
setHoveredButtonIndex(-1);
|
setHoveredButtonIndex(-1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var answers = askQuestion.answers(gameState);
|
||||||
|
|
||||||
TerminalPosition mouse = mouseAction.getPosition();
|
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(
|
RerenderScreen.ScreenPart part = new RerenderScreen.ScreenPart(
|
||||||
start,
|
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)) {
|
if (!part.isWithin(mouseNormalized)) {
|
||||||
@@ -70,9 +86,13 @@ public class DialogUI {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int buttonsStartY = DialogEventHandler.getYStartButtons(textRenderer, dialogState.getCurrentDialog());
|
int buttonsStartY = DialogEventHandler.getYStartButtons(textRenderer, dialog);
|
||||||
TerminalPosition localPosition = new TerminalPosition(mouseNormalized.getColumn() - start.getColumn(), mouseNormalized.getRow() - start.getRow() - buttonsStartY);
|
TerminalPosition localPosition = new TerminalPosition(
|
||||||
int buttonsHeight = DialogEventHandler.calculateButtonHeight(dialogState.getCurrentDialog());
|
mouseNormalized.getColumn() - start.getColumn(),
|
||||||
|
mouseNormalized.getRow() - start.getRow() - buttonsStartY
|
||||||
|
);
|
||||||
|
|
||||||
|
int buttonsHeight = DialogEventHandler.calculateButtonHeight(dialog, gameState);
|
||||||
|
|
||||||
if (localPosition.getRow() < 0 || localPosition.getRow() >= buttonsHeight) {
|
if (localPosition.getRow() < 0 || localPosition.getRow() >= buttonsHeight) {
|
||||||
setHoveredButtonIndex(-1);
|
setHoveredButtonIndex(-1);
|
||||||
@@ -82,23 +102,27 @@ public class DialogUI {
|
|||||||
int buttonIndex = localPosition.getRow() / (BUTTON_HEIGHT + BUTTON_PADDING);
|
int buttonIndex = localPosition.getRow() / (BUTTON_HEIGHT + BUTTON_PADDING);
|
||||||
int rest = 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
|
||||||
for (int y = start.getRow(); y < start.getRow() + size.getRows(); y++) {
|
&& rest < BUTTON_HEIGHT
|
||||||
for (int x = start.getColumn(); x < start.getColumn() + size.getColumns(); x++) {
|
&& localPosition.getColumn() >= PADDING
|
||||||
screenBuffer.getGlobalOverrideBuffer()[y][x] = new Empty();
|
&& localPosition.getColumn() < size.getColumns() - PADDING) {
|
||||||
}
|
|
||||||
}
|
clearDialog(start, size);
|
||||||
|
|
||||||
eventManager.emitEvent(
|
eventManager.emitEvent(
|
||||||
new Event[]{
|
new Event[]{
|
||||||
new RerenderScreen(
|
new RerenderScreen(
|
||||||
new RerenderScreen.ScreenPart(
|
new RerenderScreen.ScreenPart(
|
||||||
start,
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -112,21 +136,32 @@ public class DialogUI {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminalSize size = DialogEventHandler.getSize(textRenderer, dialogState.getCurrentDialog());
|
var dialog = dialogState.getCurrentDialog();
|
||||||
TerminalPosition start = DialogEventHandler.getStart(terminalState.getTerminalScreen().getTerminalSize(), size);
|
TerminalSize size = DialogEventHandler.getSize(textRenderer, dialog, gameState);
|
||||||
|
TerminalPosition start = DialogEventHandler.getStart(
|
||||||
|
terminalState.getTerminalScreen().getTerminalSize(),
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
if (!(dialogState.getCurrentDialog().getOnEnd() instanceof OnEnd.AskQuestion(
|
if (!(dialog.getOnEnd() instanceof OnEnd.AskQuestion askQuestion)) {
|
||||||
OnEnd.AskQuestion.Answer[] answers
|
|
||||||
))) {
|
|
||||||
setHoveredButtonIndex(-1);
|
setHoveredButtonIndex(-1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var answers = askQuestion.answers(gameState);
|
||||||
|
|
||||||
TerminalPosition mouse = mouseAction.getPosition();
|
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(
|
RerenderScreen.ScreenPart part = new RerenderScreen.ScreenPart(
|
||||||
start,
|
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)) {
|
if (!part.isWithin(mouseNormalized)) {
|
||||||
@@ -134,9 +169,13 @@ public class DialogUI {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int buttonsStartY = DialogEventHandler.getYStartButtons(textRenderer, dialogState.getCurrentDialog());
|
int buttonsStartY = DialogEventHandler.getYStartButtons(textRenderer, dialog);
|
||||||
TerminalPosition localPosition = new TerminalPosition(mouseNormalized.getColumn() - start.getColumn(), mouseNormalized.getRow() - start.getRow() - buttonsStartY);
|
TerminalPosition localPosition = new TerminalPosition(
|
||||||
int buttonsHeight = DialogEventHandler.calculateButtonHeight(dialogState.getCurrentDialog());
|
mouseNormalized.getColumn() - start.getColumn(),
|
||||||
|
mouseNormalized.getRow() - start.getRow() - buttonsStartY
|
||||||
|
);
|
||||||
|
|
||||||
|
int buttonsHeight = DialogEventHandler.calculateButtonHeight(dialog, gameState);
|
||||||
|
|
||||||
if (localPosition.getRow() < 0 || localPosition.getRow() >= buttonsHeight) {
|
if (localPosition.getRow() < 0 || localPosition.getRow() >= buttonsHeight) {
|
||||||
setHoveredButtonIndex(-1);
|
setHoveredButtonIndex(-1);
|
||||||
@@ -146,7 +185,11 @@ public class DialogUI {
|
|||||||
int buttonIndex = localPosition.getRow() / (BUTTON_HEIGHT + BUTTON_PADDING);
|
int buttonIndex = localPosition.getRow() / (BUTTON_HEIGHT + BUTTON_PADDING);
|
||||||
int rest = 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);
|
setHoveredButtonIndex(buttonIndex);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -161,4 +204,12 @@ public class DialogUI {
|
|||||||
eventManager.emitEvent(dialogState.getCurrentDialog());
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ public class EventManager extends Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public EventManager(Reflections reflections, DependencyManager dependencyManager) {
|
public EventManager(Reflections reflections, DependencyManager dependencyManager) {
|
||||||
this.dependencyManager = dependencyManager;
|
this.dependencyManager = dependencyManager;
|
||||||
setDaemon(true);
|
setDaemon(true);
|
||||||
|
|||||||
@@ -78,12 +78,14 @@
|
|||||||
item: "quest_item_boss_skin"
|
item: "quest_item_boss_skin"
|
||||||
dialog:
|
dialog:
|
||||||
text: "Well done. Here is the key."
|
text: "Well done. Here is the key."
|
||||||
giveItem:
|
onEnd:
|
||||||
id: 300
|
type: "give_item"
|
||||||
name: "Cave Exit Key"
|
item:
|
||||||
type: { name: "quest_item_final_key" }
|
id: 800
|
||||||
texture: "KEY"
|
name: "Something"
|
||||||
onEnd: { type: end }
|
type: { name: "junk" }
|
||||||
|
texture: "APPLE"
|
||||||
|
then: { type: end }
|
||||||
- answer: "Not yet"
|
- answer: "Not yet"
|
||||||
dialog:
|
dialog:
|
||||||
text: "Then go back before it finds you."
|
text: "Then go back before it finds you."
|
||||||
|
|||||||
Reference in New Issue
Block a user