Implement some sample dialogs | apply BASE engine updates

This commit is contained in:
2023-11-02 13:57:51 +01:00
parent 3b99bc561a
commit eaa5f5d547
19 changed files with 288 additions and 39 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -163,5 +163,19 @@ INSERT INTO "PUBLIC"."ENEMY" VALUES
('eagle', 'Eagle', 'Eagle', 'Corpse', '2d4+2', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'), ('eagle', 'Eagle', 'Eagle', 'Corpse', '2d4+2', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'),
('skeleton', 'Skeleton', 'Skeleton', 'Corpse', '2d6+2', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'), ('skeleton', 'Skeleton', 'Skeleton', 'Corpse', '2d6+2', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'),
('skeleton_archer', 'Skeleton Archer', 'Skeleton', 'Corpse', '2d6+2', '10d2', TRUE, 'wooden_dagger', 'wooden_bow,wooden_arrow,2d4+3', NULL, 'Poof', 'Deku death'); ('skeleton_archer', 'Skeleton Archer', 'Skeleton', 'Corpse', '2d6+2', '10d2', TRUE, 'wooden_dagger', 'wooden_bow,wooden_arrow,2d4+3', NULL, 'Poof', 'Deku death');
CREATE MEMORY TABLE "PUBLIC"."FRIEND"(
"ID" VARCHAR NOT NULL,
"NAME" VARCHAR NOT NULL,
"CHARSET" VARCHAR NOT NULL,
"SPEED" VARCHAR NOT NULL,
"BLOCKING" BOOLEAN DEFAULT FALSE NOT NULL,
"DIALOG_COLOR" VARCHAR DEFAULT '0xFFFFFF' NOT NULL
);
ALTER TABLE "PUBLIC"."FRIEND" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_7C" PRIMARY KEY("ID");
-- 3 +/- SELECT COUNT(*) FROM PUBLIC.FRIEND;
INSERT INTO "PUBLIC"."FRIEND" VALUES
('turtle', 'Turtle', 'Turtle', '10d2', TRUE, 'AA00DD'),
('neko', 'Neko', 'Neko', '14', TRUE, 'AA00DD'),
('grandma', 'Grandma', 'Grandma', '7', TRUE, 'DD00AA');
ALTER TABLE "PUBLIC"."ENEMY_DROP" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_8A" FOREIGN KEY("ENEMY") REFERENCES "PUBLIC"."ENEMY"("ID") NOCHECK; ALTER TABLE "PUBLIC"."ENEMY_DROP" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_8A" FOREIGN KEY("ENEMY") REFERENCES "PUBLIC"."ENEMY"("ID") NOCHECK;
ALTER TABLE "PUBLIC"."ENEMY" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_3F" FOREIGN KEY("MELEE_WEAPON") REFERENCES "PUBLIC"."MELEE_WEAPON"("ID") NOCHECK; ALTER TABLE "PUBLIC"."ENEMY" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_3F" FOREIGN KEY("MELEE_WEAPON") REFERENCES "PUBLIC"."MELEE_WEAPON"("ID") NOCHECK;

View File

@@ -1,2 +0,0 @@
$1825b6a1-842d-4565-97e0-2005118b2b2b2 ( :+com.bartlomiejpluta.demo.map.ForrestHandler

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,74 @@
package com.bartlomiejpluta.demo.entity;
import DB.model.FriendModel;
import com.bartlomiejpluta.base.api.ai.AI;
import com.bartlomiejpluta.base.api.ai.NPC;
import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.api.context.ContextHolder;
import com.bartlomiejpluta.base.lib.ai.NoopAI;
import com.bartlomiejpluta.base.lib.ai.RandomMovementAI;
import com.bartlomiejpluta.base.util.random.DiceRoller;
import com.bartlomiejpluta.demo.world.item.Item;
import lombok.Getter;
import lombok.NonNull;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
public class Friend extends Creature implements NPC {
@Getter
private AI strategy = NoopAI.INSTANCE;
private AI priorStrategy;
private boolean interacting;
@Getter
private final String name;
@Getter
private final int dialogNameColor;
private Function<Friend, CompletableFuture<Object>> interaction;
public Friend(@NonNull String id) {
this(DB.dao.friend.find(id));
}
public Friend(@NonNull FriendModel template) {
super(ContextHolder.INSTANCE.getContext().createCharacter(A.charsets.byName(template.getCharset()).$));
name = template.getName();
setSpeed(DiceRoller.roll(template.getSpeed()) / 10f);
setBlocking(template.isBlocking());
dialogNameColor = Integer.parseInt(template.getDialogColor(), 16);
}
@Override
public void removeItemFromEquipment(Item item) {
}
public CompletableFuture<Object> interact(Character trigger) {
if(interaction != null && !interacting) {
setFaceDirection(getDirectionTowards(trigger));
priorStrategy = strategy;
strategy = NoopAI.INSTANCE;
interacting = true;
return interaction.apply(this).thenApply(o -> {
strategy = priorStrategy;
interacting = false;
return o;
});
}
return CompletableFuture.completedFuture(null);
}
public Friend interaction(Function<Friend, CompletableFuture<Object>> interaction) {
this.interaction = interaction;
return this;
}
public Friend asAnimal() {
this.strategy = new RandomMovementAI<>(this, 4f);
return this;
}
}

View File

@@ -17,4 +17,8 @@ public abstract class NamedCharacter extends CharacterDelegate {
} }
public abstract String getName(); public abstract String getName();
public int getDialogNameColor() {
return 0xFFFFFF;
}
} }

View File

@@ -47,12 +47,22 @@ public class Player extends Creature {
for (var i = 0; i < entities.size(); ++i) { for (var i = 0; i < entities.size(); ++i) {
var entity = entities.get(i); var entity = entities.get(i);
// Use some map object which player is looking at if (entity.getCoordinates().equals(coords)) {
if (entity.getCoordinates().equals(coords) && entity instanceof MapObject object) {
object.triggerInteraction(); // Use some map object which player is looking at
return; if(entity instanceof MapObject object) {
object.triggerInteraction();
return;
}
// Interact with friend creature which player is looking at
if(entity instanceof Friend friend) {
friend.interact(this).thenApply(o -> interactionCooldown = INTERACTION_COOLDOWN);
return;
}
} }
if (entity.getCoordinates().equals(getCoordinates())) { if (entity.getCoordinates().equals(getCoordinates())) {
// Pick some item from the ground // Pick some item from the ground
@@ -223,7 +233,12 @@ public class Player extends Creature {
@Override @Override
public String getName() { public String getName() {
return "Player"; return "Luna";
}
@Override
public int getDialogNameColor() {
return 0x00AA00;
} }
@Override @Override

View File

@@ -0,0 +1,54 @@
package com.bartlomiejpluta.demo.gui;
import A.fonts;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.lib.gui.TextView;
import com.bartlomiejpluta.base.lib.gui.VOptionChoice;
import java.util.Collections;
import java.util.Map;
public class DialogChoiceWindow extends DecoratedWindow {
@Ref("speaker")
private TextView speaker;
@Ref("choice")
private VOptionChoice choice;
@SuppressWarnings("unchecked")
@Override
public void onOpen(WindowManager manager, Object[] args) {
super.onOpen(manager, args);
speaker.setText((String) args[0]);
speaker.setColor((int) args[1]);
var index = 0;
choice.removeAllChildren();
var options = (String[]) args[2];
for(var option : options) {
var button = new Button(context, gui, Collections.emptyMap());
choice.add(button);
button.setText(option);
button.setColor(0xFFFFFF);
button.setWidthMode(SizeMode.RELATIVE);
button.setWidth(1f);
button.setFont(fonts.roboto_regular.$);
button.setFontSize(20f);
button.setAction(onChoose(index));
++index;
}
choice.focus();
}
private Runnable onChoose(int index) {
return () -> resolve(index);
}
public DialogChoiceWindow(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
}
}

View File

@@ -5,14 +5,18 @@ import com.bartlomiejpluta.base.api.gui.*;
import com.bartlomiejpluta.base.api.input.Key; import com.bartlomiejpluta.base.api.input.Key;
import com.bartlomiejpluta.base.api.input.KeyAction; import com.bartlomiejpluta.base.api.input.KeyAction;
import com.bartlomiejpluta.base.api.input.KeyEvent; import com.bartlomiejpluta.base.api.input.KeyEvent;
import com.bartlomiejpluta.base.lib.gui.PrintedTextView;
import com.bartlomiejpluta.base.lib.gui.TextView; import com.bartlomiejpluta.base.lib.gui.TextView;
import java.util.Map; import java.util.Map;
public class DialogWindow extends DecoratedWindow { public class DialogWindow extends DecoratedWindow {
@Ref("speaker")
private TextView speaker;
@Ref("message") @Ref("message")
private TextView text; private PrintedTextView text;
public DialogWindow(Context context, GUI gui, Map<String, Component> refs) { public DialogWindow(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs); super(context, gui, refs);
@@ -26,6 +30,12 @@ public class DialogWindow extends DecoratedWindow {
} }
if (event.getKey() == Key.KEY_ENTER && event.getAction() == KeyAction.PRESS) { if (event.getKey() == Key.KEY_ENTER && event.getAction() == KeyAction.PRESS) {
if (text.isPrinting()) {
text.printAll();
event.consume();
return;
}
manager.close(); manager.close();
event.consume(); event.consume();
} }
@@ -35,11 +45,16 @@ public class DialogWindow extends DecoratedWindow {
public void onOpen(WindowManager manager, Object[] args) { public void onOpen(WindowManager manager, Object[] args) {
super.onOpen(manager, args); super.onOpen(manager, args);
text.setText((String) args[0]); speaker.setText((String) args[0]);
speaker.setColor((int) args[1]);
if (args.length > 1) { text.setText((String) args[2]);
setWindowPosition((WindowPosition) args[1]);
if (args.length > 3) {
setWindowPosition((WindowPosition) args[3]);
} }
text.start();
} }
@Override @Override

View File

@@ -0,0 +1,49 @@
package com.bartlomiejpluta.demo.gui;
import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.gui.Component;
import com.bartlomiejpluta.base.api.gui.GUI;
import com.bartlomiejpluta.base.lib.gui.TextView;
import lombok.Setter;
import java.util.Map;
public class PrintTextView extends TextView {
@Setter
private Float duration;
private float acc;
private String originalText;
public void start() {
acc = 0f;
}
public boolean isPrinting() {
return originalText.length() != super.getText().length();
}
public void printAll() {
acc = originalText.length() * duration;
}
@Override
public void setText(String text) {
super.setText("");
this.originalText = text;
}
@Override
public void update(float dt) {
super.update(dt);
acc += dt;
super.setText(originalText.substring(0, Math.min(originalText.length(), (int) (acc / duration))));
}
public PrintTextView(Context context, GUI gui, Map<String, Component> refs) {
super(context, gui, refs);
}
}

View File

@@ -1,29 +1,22 @@
package com.bartlomiejpluta.demo.map; package com.bartlomiejpluta.demo.map;
import A.maps;
import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.context.Context; import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.entity.Entity;
import com.bartlomiejpluta.base.api.gui.Window;
import com.bartlomiejpluta.base.api.gui.WindowPosition; import com.bartlomiejpluta.base.api.gui.WindowPosition;
import com.bartlomiejpluta.base.api.icon.Icon; import com.bartlomiejpluta.base.api.icon.Icon;
import com.bartlomiejpluta.base.api.input.Input; import com.bartlomiejpluta.base.api.input.Input;
import com.bartlomiejpluta.base.api.input.Key; import com.bartlomiejpluta.base.api.input.Key;
import com.bartlomiejpluta.base.api.map.handler.MapHandler; import com.bartlomiejpluta.base.api.map.handler.MapHandler;
import com.bartlomiejpluta.base.api.map.layer.object.MapPin; import com.bartlomiejpluta.base.api.map.layer.object.MapPin;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.api.map.model.GameMap; import com.bartlomiejpluta.base.api.map.model.GameMap;
import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.lib.camera.CameraController; import com.bartlomiejpluta.base.lib.camera.CameraController;
import com.bartlomiejpluta.base.lib.camera.FollowingCameraController; import com.bartlomiejpluta.base.lib.camera.FollowingCameraController;
import com.bartlomiejpluta.base.util.input.InputUtil; import com.bartlomiejpluta.base.util.input.InputUtil;
import com.bartlomiejpluta.base.util.world.CharacterSpawner; import com.bartlomiejpluta.base.util.world.CharacterSpawner;
import com.bartlomiejpluta.base.util.world.Warp; import com.bartlomiejpluta.base.util.world.Warp;
import com.bartlomiejpluta.demo.entity.Chest; import com.bartlomiejpluta.demo.entity.*;
import com.bartlomiejpluta.demo.entity.Door;
import com.bartlomiejpluta.demo.entity.Enemy;
import com.bartlomiejpluta.demo.entity.Player;
import com.bartlomiejpluta.demo.event.EnemyDiedEvent; import com.bartlomiejpluta.demo.event.EnemyDiedEvent;
import com.bartlomiejpluta.demo.menu.GuiManager; import com.bartlomiejpluta.demo.menu.GuiManager;
import com.bartlomiejpluta.demo.runner.DemoRunner; import com.bartlomiejpluta.demo.runner.DemoRunner;
@@ -82,12 +75,16 @@ public abstract class BaseMapHandler implements MapHandler {
cameraController.update(); cameraController.update();
} }
public CompletableFuture<Window> dialog(String message, WindowPosition position) { public CompletableFuture<Object> dialog(NamedCharacter speaker, String message, WindowPosition position) {
return guiManager.showDialog(message, position); return guiManager.showDialog(speaker.getName(), speaker.getDialogNameColor(), message, position);
} }
public CompletableFuture<Window> dialog(String message) { public CompletableFuture<Object> dialog(NamedCharacter speaker, String message) {
return guiManager.showDialog(message, WindowPosition.BOTTOM); return guiManager.showDialog(speaker.getName(), speaker.getDialogNameColor(), message, WindowPosition.BOTTOM);
}
public CompletableFuture<Integer> dialogChoice(NamedCharacter speaker, String... choices) {
return guiManager.showDialogChoice(speaker.getName(), speaker.getDialogNameColor(), choices);
} }
protected <T extends Entity> T addEntity(T entity, MapPin tile) { protected <T extends Entity> T addEntity(T entity, MapPin tile) {
@@ -100,6 +97,10 @@ public abstract class BaseMapHandler implements MapHandler {
return addEntity(new Enemy(id), tile); return addEntity(new Enemy(id), tile);
} }
public Friend friend(@NonNull MapPin tile, @NonNull String id) {
return addEntity(new Friend(id), tile);
}
public Chest chest(@NonNull MapPin tile, @NonNull String id) { public Chest chest(@NonNull MapPin tile, @NonNull String id) {
return addEntity(new Chest(id), tile); return addEntity(new Chest(id), tile);
} }

View File

@@ -1,11 +1,11 @@
package com.bartlomiejpluta.demo.map; package com.bartlomiejpluta.demo.map;
import com.bartlomiejpluta.base.api.context.Context; import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.input.Input;
import com.bartlomiejpluta.base.api.map.model.GameMap; import com.bartlomiejpluta.base.api.map.model.GameMap;
import com.bartlomiejpluta.base.api.map.handler.MapHandler;
import com.bartlomiejpluta.base.api.screen.Screen;
public class HeroHomeHandler extends BaseMapHandler { public class HeroHomeHandler extends BaseMapHandler {
@Override
public void onOpen(Context context, GameMap map) {
dialog(player, "Ahhh, another beautiful day for an adventure... Let's go!");
}
} }

View File

@@ -26,6 +26,7 @@ public class GuiManager {
private final EquipmentWindow equipment; private final EquipmentWindow equipment;
private final LootWindow loot; private final LootWindow loot;
private final DialogWindow dialog; private final DialogWindow dialog;
private final DialogChoiceWindow dialogChoice;
private final Consumer<KeyEvent> gameMenuHandler = this::handleGameMenuKeyEvent; private final Consumer<KeyEvent> gameMenuHandler = this::handleGameMenuKeyEvent;
public GuiManager(@NonNull DemoRunner runner, @NonNull Context context) { public GuiManager(@NonNull DemoRunner runner, @NonNull Context context) {
@@ -49,6 +50,7 @@ public class GuiManager {
this.gameMenu.reference("exit", Button.class).setAction(runner::exit); this.gameMenu.reference("exit", Button.class).setAction(runner::exit);
this.dialog = gui.inflateWindow(A.widgets.dialog.$, DialogWindow.class); this.dialog = gui.inflateWindow(A.widgets.dialog.$, DialogWindow.class);
this.dialogChoice = gui.inflateWindow(A.widgets.dialog_choice.$, DialogChoiceWindow.class);
this.loot = gui.inflateWindow(widgets.loot_menu.$, LootWindow.class); this.loot = gui.inflateWindow(widgets.loot_menu.$, LootWindow.class);
} }
@@ -83,7 +85,7 @@ public class GuiManager {
return manager.size(); return manager.size();
} }
public CompletableFuture<Window> showStartMenu() { public CompletableFuture<Object> showStartMenu() {
manager.closeAll(); manager.closeAll();
return manager.open(startMenu); return manager.open(startMenu);
} }
@@ -100,19 +102,23 @@ public class GuiManager {
manager.setDisplayMode(DisplayMode.DISPLAY_TOP); manager.setDisplayMode(DisplayMode.DISPLAY_TOP);
} }
public CompletableFuture<Window> showDialog(@NonNull String message, @NonNull WindowPosition position) { public CompletableFuture<Object> showDialog(@NonNull String speaker, int color, @NonNull String message, @NonNull WindowPosition position) {
return manager.open(dialog, message, position); return manager.open(dialog, speaker, color, message, position);
} }
public CompletableFuture<Window> openLootWindow(@NonNull Enemy enemy) { public CompletableFuture<Integer> showDialogChoice(@NonNull String speaker, int color, @NonNull String... choices) {
return manager.openForResult(Integer.class, dialogChoice, speaker, color, choices);
}
public CompletableFuture<Object> openLootWindow(@NonNull Enemy enemy) {
return manager.open(loot, enemy.getLoot(), "Loot"); return manager.open(loot, enemy.getLoot(), "Loot");
} }
public CompletableFuture<Window> openChestWindow(@NonNull Chest chest) { public CompletableFuture<Object> openChestWindow(@NonNull Chest chest) {
return manager.open(loot, chest.getContent(), chest.getName()); return manager.open(loot, chest.getContent(), chest.getName());
} }
public CompletableFuture<Window> openGameMenu() { public CompletableFuture<Object> openGameMenu() {
return manager.open(gameMenu); return manager.open(gameMenu);
} }

View File

@@ -7,7 +7,10 @@
margin="20f" margin="20f"
width="900f" width="900f"
height="auto"> height="auto">
<base:TextView ref="message" alignment="top|left" font="A.fonts.roboto_regular.$" fontSize="40f" width="relative"
rows="4" color="0xFFFFFF"/> <base:VLayout width="relative" height="auto">
<base:TextView ref="speaker" alignment="top|left" font="A.fonts.roboto_regular.$" fontSize="40f" width="relative" color="0x00AA00" />
<base:PrintedTextView ref="message" duration="0.01f" alignment="top|left" font="A.fonts.roboto_regular.$" fontSize="40f" width="relative" rows="4" color="0xFFFFFF"/>
</base:VLayout>
</demo:DialogWindow> </demo:DialogWindow>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<demo:DialogChoiceWindow
xmlns:base="com.bartlomiejpluta.base.lib.gui"
xmlns:demo="com.bartlomiejpluta.demo.gui"
windowPosition="bottom"
padding="20f"
margin="20f"
width="900f"
height="auto">
<base:VLayout width="relative" height="auto">
<base:TextView ref="speaker" alignment="top|left" font="A.fonts.roboto_regular.$" fontSize="40f" width="relative" color="0x00AA00" />
<base:VOptionChoice ref="choice" width="relative" />
</base:VLayout>
</demo:DialogChoiceWindow>