Commit 1b5a6302 by Jonathan Thomas

Merge branch 'flee-crash' into 'develop'

Fix Flee Crash + Unflee behavior

See merge request !11
parents eb9872b2 e4bf8193
Pipeline #12666 passed with stages
in 2 minutes 10 seconds
...@@ -4,9 +4,17 @@ All notable changes to **CreatureChat** are documented in this file. The format ...@@ -4,9 +4,17 @@ All notable changes to **CreatureChat** are documented in this file. The format
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html). [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased ## [Unreleased]
### Added
- Added UNFLEE behavior (to stop fleeing from a player)
- Added support for non path aware entities to FLEE (i.e. Ghast)
- Added new LLM tests for UNFLEE
### Changed ### Changed
- Fixed a **crash with FLEE** when non-path aware entities (i.e. Ghast) attempted to flee.
- Fixed certain behaviors from colliding with others (i.e. mutual exclusive ones)
- Updated README.md with new video thumbnail, and simplified text, added spoiler to install instructions
- Fixed CurseForge deploy script to be much faster, and correctly lookup valid Type and Version IDs - Fixed CurseForge deploy script to be much faster, and correctly lookup valid Type and Version IDs
## [1.0.7] - 2024-07-03 ## [1.0.7] - 2024-07-03
......
![CreatureChat Logo](src/main/resources/assets/creaturechat/icon.png "CreatureChat Logo")
# CreatureChat # CreatureChat
### Chat, befriend, and interact with a rich world of creatures like never before! All creatures can talk and respond naturally using AI. ## Chat with any mob in Minecraft! All creatures can talk using AI!
### Features
- **AI-Driven Chats:** Using ChatGPT or open-source AI models, each conversation is unique and engaging!
- **Behaviors:** Creatures can make decisions on their own and **Follow, Flee, Attack, Protect**, and more!
- **Reactions:** Creatures automatically react to being damaged or receiving items from players.
- **Friendship:** Track your relationships from friends to foes.
- **Multi-Player:** Share the experience; conversations sync across server & players.
- **Memory:** Creatures remember your past interactions, making each chat more personal.
## Features: ### Create meaningful conversations and enduring friendships? A betrayal perhaps?
- **Dynamic Dialogues**: Engage with Minecraft creatures like never before, each with a unique character sheet.
- **AI-Driven Chats**: Powered by ChatGPT, ensuring each conversation is fresh and engaging.
- **Custom Behaviors**: Creatures can make decisions on their own and **Follow, Flee, Attack**, and more!
- **Reactive Interactions**: Creatures automatically react to being damaged or receiving items from players.
- **Friendship Status**: Track your relationships on a 7-point scale, from foes to friends.
- **Custom UI Artwork**: Features beautiful hand-drawn icons for entities, expressive chat bubbles.
- **Multi-Player Interaction**: Share the experience; conversations sync across server & players.
- **Personalized Memory**: Creatures remember past interactions, making each chat more personal.
- **Model Support**: Flexible backend, compatible with various GPT and open-sources LLM models.
Ready to deepen your Minecraft journey with meaningful conversations and enduring friendships? [![CreatureChat Trailer Video](src/main/resources/assets/creaturechat/screenshots/video-thumbnail.png)](https://youtu.be/GdY969Orsh0?si=qRgCne10XqOBC8YB)
**Step into the world of CreatureChat 🗨 and spark your first conversation today!**
## Recommended Installation (with Fabric) ### Installation Instructions
<details>
<summary>Fabric (Recommended)</summary>
## Fabric Instructions
1. **Install Fabric Loader & API**: Follow the instructions [here](https://fabricmc.net/use/). 1. **Install Fabric Loader & API**: Follow the instructions [here](https://fabricmc.net/use/).
1. **Install CreatureChat Mod**: Download and copy `creaturechat-*.jar` and `fabric-api-*.jar` into your `.minecraft/mods` folder. 1. **Install CreatureChat Mod**: Download and copy `creaturechat-*.jar` and `fabric-api-*.jar` into your `.minecraft/mods` folder.
1. **Create an OpenAI API key**: Visit https://platform.openai.com/api-keys, and use the **+ Create new secret key** button. 1. **Create an OpenAI API key**: Visit https://platform.openai.com/api-keys, and use the **+ Create new secret key** button.
Copy/Paste your key into the `/creaturechat key set <YOUR-SECRET-KEY-HERE>` command. Copy/Paste your key into the `/creaturechat key set <YOUR-SECRET-KEY-HERE>` command.
1. **Launch Minecraft** with the Fabric profile 1. **Launch Minecraft** with the Fabric profile
</details>
<details>
<summary>Forge (with Sinytra Connector)</summary>
## OR ## Forge Instructions
### NOTE: Sintra Connector only supports Minecraft 1.20.1
## Forge Installation (with Sinytra Connector)
1. **Install Forge:** Download [Forge Installer](https://files.minecraftforge.net/), run it, select "Install client". 1. **Install Forge:** Download [Forge Installer](https://files.minecraftforge.net/), run it, select "Install client".
1. **Install Forgified Fabric API:** Download [Forgified Fabric API](https://curseforge.com/minecraft/mc-mods/forgified-fabric-api) and copy the `*.jar` into your `.minecraft/mods` folder. 1. **Install Forgified Fabric API:** Download [Forgified Fabric API](https://curseforge.com/minecraft/mc-mods/forgified-fabric-api) and copy the `*.jar` into your `.minecraft/mods` folder.
1. **Install Sinytra Connector:** Download [Sinytra Connector](https://www.curseforge.com/minecraft/mc-mods/sinytra-connector) and copy the `*.jar` into your `.minecraft/mods` folder. 1. **Install Sinytra Connector:** Download [Sinytra Connector](https://www.curseforge.com/minecraft/mc-mods/sinytra-connector) and copy the `*.jar` into your `.minecraft/mods` folder.
1. **Install CreatureChat Mod**: Download and copy `creaturechat-*.jar` into your `.minecraft/mods` folder. 1. **Install CreatureChat Mod**: Download and copy `creaturechat-*.jar` into your `.minecraft/mods` folder.
1. **Create an OpenAI API key**: Visit https://platform.openai.com/api-keys, and use the **+ Create new secret key** button. 1. **Create an OpenAI API key**: Visit https://platform.openai.com/api-keys, and use the **+ Create new secret key** button.
Copy/Paste your key into the `/creaturechat key set <YOUR-SECRET-KEY-HERE>` command. Copy/Paste your key into the `/creaturechat key set <YOUR-SECRET-KEY-HERE>` command.
1. **Launch Minecraft** with the Forge profile 1. **Launch Minecraft** with the Forge profile
</details>
## Commands ### In-game Commands
The CreatureChat mod allows users to configure settings via in-game commands. Here's how to use them: <details>
<summary>Configure CreatureChat</summary>
### Command Usage
- **REQUIRED:** `/creaturechat key set <key>` - **REQUIRED:** `/creaturechat key set <key>`
- Sets the *OpenAI API key*. This is required for making requests to the LLM. - Sets the _OpenAI API key_. This is required for making requests to the LLM.
- **OPTIONAL:** `/creaturechat url set "<url>"` - **OPTIONAL:** `/creaturechat url set "<url>"`
- Sets the URL of the API used to make LLM requests. Defaults to `"https://api.openai.com/v1/chat/completions"` - Sets the URL of the API used to make LLM requests. Defaults to `"<https://api.openai.com/v1/chat/completions>"`
- **OPTIONAL:** `/creaturechat model set <model>` - **OPTIONAL:** `/creaturechat model set <model>`
- Sets the model used for generating responses in chats. Defaults to `gpt-3.5-turbo`. - Sets the model used for generating responses in chats. Defaults to `gpt-3.5-turbo`.
- **OPTIONAL:** `/creaturechat timeout set <seconds>` - **OPTIONAL:** `/creaturechat timeout set <seconds>`
- Sets the timeout (in seconds) for API HTTP requests. Defaults to `10` seconds. - Sets the timeout (in seconds) for API HTTP requests. Defaults to `10` seconds.
### Configuration Scope: ### Configuration Scope:
**OPTIONAL:** You can specify the configuration scope at the end of each command to determine where settings should be applied: **OPTIONAL:** You can specify the configuration scope at the end of each command to determine where settings should be applied:
- **Default** Configuration (`--config default`): - **Default** Configuration (`--config default`):
Applies the configuration universally, unless overridden by a server-specific configuration. Applies the configuration universally, unless overridden by a server-specific configuration.
- **Server**-Specific Configuration (`--config server`): - **Server**-Specific Configuration (`--config server`):
Applies the configuration only to the server where the command is executed. Applies the configuration only to the server where the command is executed.
- If the `--config` option is not specified, the `default` configuration scope is assumed. - If the `--config` option is not specified, the `default` configuration scope is assumed.
</details>
## Costs & Security ### Does OpenAI offer a **FREE** model?
Using third-party Large Language Model (LLM) APIs, such as OpenAI, will incur usage-based **fees**.
These fees are based on the amount of data processed. Before integrating your API key, please
[review the pricing](https://openai.com/pricing#language-models) details provided by the API provider.
Be aware of the **potential costs** and plan your usage accordingly to avoid unexpected charges.
## Does OpenAI offer a **FREE** model?
While ChatGPT is a popular product and does offer a free version to their users on their website, While ChatGPT is a popular product and does offer a free version to their users on their website,
the OpenAI developer API does not extend any free models or free usage. You will be charged for each token the OpenAI developer API does not extend any free models or free usage. You will be charged for each token
consumed and generated. We use the `gpt-3.5-turbo` model by default, due to its extremely low cost consumed and generated. We use the `gpt-3.5-turbo` model by default, due to its low cost
and fast performance... however it is not free. and fast performance... however it is not free.
## Free Local LLM ### Free Local LLM
CreatureChat fully supports **free & open-source** LLMs. An HTTP endpoint which supports the OpenAI Chat Completion CreatureChat fully supports **free & open-source** LLMs. An HTTP endpoint which supports the OpenAI Chat Completion
JSON syntax is required. We highly recommend using [Ollama](https://ollama.com/) or [LiteLLM](https://litellm.vercel.app/) as your HTTP proxy. JSON syntax is required. We highly recommend using [Ollama](https://ollama.com/) or [LiteLLM](https://litellm.vercel.app/) as your HTTP proxy.
LiteLLM supports **100+ LLMs** (including Anthropic, VertexAI, HuggingFace, Google Gemini, and Ollama), and proxies them through a LiteLLM supports **100+ LLMs** (including Anthropic, VertexAI, HuggingFace, Google Gemini, and Ollama), and proxies them through a
local HTTP endpoint in a compatible format with CreatureChat. *NOTE: You must have a very expensive GPU to run a local local HTTP endpoint in a compatible format with CreatureChat. *NOTE: You must have a very expensive GPU to run a local
LLM on your computer at a speed which is fast enough to be playable in Minecraft.* LLM on your computer at a speed which is fast enough to be playable in Minecraft.*
## Screenshots ### Costs & Security
Using third-party Large Language Model (LLM) APIs, such as OpenAI, will incur usage-based **fees**.
These fees are based on the amount of data processed. Before integrating your API key, please
[review the pricing](https://openai.com/pricing#language-models) details provided by the API provider.
Be aware of the **potential costs** and plan your usage accordingly to avoid unexpected charges.
### Screenshots
![Interact with Minecraft Creatures](src/main/resources/assets/creaturechat/screenshots/salmon-follow.png) ![Interact with Minecraft Creatures](src/main/resources/assets/creaturechat/screenshots/salmon-follow.png)
![Panda Following the Player](src/main/resources/assets/creaturechat/screenshots/panda-follow.png) ![Panda Following the Player](src/main/resources/assets/creaturechat/screenshots/panda-follow.png)
![Piglins Reacting to Player](src/main/resources/assets/creaturechat/screenshots/piglin-reactions.png) ![Piglins Reacting to Player](src/main/resources/assets/creaturechat/screenshots/piglin-reactions.png)
![Enderman Following the Player](src/main/resources/assets/creaturechat/screenshots/enderman-follow.png) ![Enderman Following the Player](src/main/resources/assets/creaturechat/screenshots/enderman-follow.png)
![Chat UI](src/main/resources/assets/creaturechat/screenshots/chat-ui.png) ![Chat UI](src/main/resources/assets/creaturechat/screenshots/chat-ui.png)
## Authors ### Authors
- Jonathan Thomas <jonathan@openshot.org> - Jonathan Thomas <jonathan@openshot.org>
- owlmaddie <owlmaddie@gmail.com> - owlmaddie <owlmaddie@gmail.com>
## Contact & Resources ### Contact & Resources
- [Join us on Discord](https://discord.gg/m9dvPFmN3e) - [Join us on Discord](https://discord.gg/m9dvPFmN3e)
- [Build Instructions](INSTALL.md) ([Source Code](http://gitlab.openshot.org/minecraft/creature-chat)) - [Build Instructions](INSTALL.md) ([Source Code](http://gitlab.openshot.org/minecraft/creature-chat))
...@@ -98,11 +103,12 @@ LLM on your computer at a speed which is fast enough to be playable in Minecraft ...@@ -98,11 +103,12 @@ LLM on your computer at a speed which is fast enough to be playable in Minecraft
[Twitter](https://twitter.com/TheCreatureChat) | [Twitter](https://twitter.com/TheCreatureChat) |
[TikTok](https://www.tiktok.com/@creaturechat) [TikTok](https://www.tiktok.com/@creaturechat)
## Legal Information ### Legal Information
Please review our [Terms of Service](TERMS.md) and [Privacy Policy](PRIVACY.md) before using CreatureChat. By using our services, you agree to comply with these documents. Please review our [Terms of Service](TERMS.md) and [Privacy Policy](PRIVACY.md) before using CreatureChat.
By using our services, you agree to comply with these documents.
## License ### License
CreatureChat is a Minecraft mod which allows chat conversations with entities. CreatureChat is a Minecraft mod which allows chat conversations with entities.
Copyright (C) 2024 owlmaddie LLC Copyright (C) 2024 owlmaddie LLC
......
...@@ -269,6 +269,7 @@ public class ChatDataManager { ...@@ -269,6 +269,7 @@ public class ChatDataManager {
// Apply behaviors to entity // Apply behaviors to entity
if (behavior.getName().equals("FOLLOW")) { if (behavior.getName().equals("FOLLOW")) {
FollowPlayerGoal followGoal = new FollowPlayerGoal(player, entity, entitySpeed); FollowPlayerGoal followGoal = new FollowPlayerGoal(player, entity, entitySpeed);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class); EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class); EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, followGoal, GoalPriority.FOLLOW_PLAYER); EntityBehaviorManager.addGoal(entity, followGoal, GoalPriority.FOLLOW_PLAYER);
...@@ -282,17 +283,25 @@ public class ChatDataManager { ...@@ -282,17 +283,25 @@ public class ChatDataManager {
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class); EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class); EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class); EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, ProtectPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, fleeGoal, GoalPriority.FLEE_PLAYER); EntityBehaviorManager.addGoal(entity, fleeGoal, GoalPriority.FLEE_PLAYER);
} else if (behavior.getName().equals("UNFLEE")) {
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
} else if (behavior.getName().equals("ATTACK")) { } else if (behavior.getName().equals("ATTACK")) {
AttackPlayerGoal attackGoal = new AttackPlayerGoal(player, entity, entitySpeedFast); AttackPlayerGoal attackGoal = new AttackPlayerGoal(player, entity, entitySpeedFast);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class); EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class); EntityBehaviorManager.removeGoal(entity, FollowPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class); EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, ProtectPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, attackGoal, GoalPriority.ATTACK_PLAYER); EntityBehaviorManager.addGoal(entity, attackGoal, GoalPriority.ATTACK_PLAYER);
} else if (behavior.getName().equals("PROTECT")) { } else if (behavior.getName().equals("PROTECT")) {
ProtectPlayerGoal protectGoal = new ProtectPlayerGoal(player, entity, 1.0); ProtectPlayerGoal protectGoal = new ProtectPlayerGoal(player, entity, 1.0);
EntityBehaviorManager.removeGoal(entity, TalkPlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, FleePlayerGoal.class);
EntityBehaviorManager.removeGoal(entity, AttackPlayerGoal.class);
EntityBehaviorManager.addGoal(entity, protectGoal, GoalPriority.PROTECT_PLAYER); EntityBehaviorManager.addGoal(entity, protectGoal, GoalPriority.PROTECT_PLAYER);
} else if (behavior.getName().equals("UNPROTECT")) { } else if (behavior.getName().equals("UNPROTECT")) {
......
...@@ -43,14 +43,29 @@ public class FleePlayerGoal extends PlayerBaseGoal { ...@@ -43,14 +43,29 @@ public class FleePlayerGoal extends PlayerBaseGoal {
private void fleeFromPlayer() { private void fleeFromPlayer() {
int roundedFleeDistance = Math.round(fleeDistance); int roundedFleeDistance = Math.round(fleeDistance);
Vec3d fleeTarget = FuzzyTargeting.findFrom((PathAwareEntity)this.entity, roundedFleeDistance, if (this.entity instanceof PathAwareEntity) {
roundedFleeDistance, this.targetEntity.getPos()); // Set random path away from player
Vec3d fleeTarget = FuzzyTargeting.findFrom((PathAwareEntity) this.entity, roundedFleeDistance,
roundedFleeDistance, this.targetEntity.getPos());
if (fleeTarget != null) { if (fleeTarget != null) {
Path path = this.entity.getNavigation().findPathTo(fleeTarget.x, fleeTarget.y, fleeTarget.z, 0); Path path = this.entity.getNavigation().findPathTo(fleeTarget.x, fleeTarget.y, fleeTarget.z, 0);
if (path != null) { if (path != null) {
this.entity.getNavigation().startMovingAlong(path, this.speed); this.entity.getNavigation().startMovingAlong(path, this.speed);
}
} }
} else {
// Move in the opposite direction from player (for non-path aware entities)
Vec3d playerPos = this.targetEntity.getPos();
Vec3d entityPos = this.entity.getPos();
// Calculate the direction away from the player
Vec3d fleeDirection = entityPos.subtract(playerPos).normalize();
// Apply movement with the entity's speed in the opposite direction
this.entity.setVelocity(fleeDirection.x * this.speed, this.entity.getVelocity().y, fleeDirection.z * this.speed);
this.entity.velocityModified = true;
} }
} }
......
...@@ -63,6 +63,9 @@ public class FollowPlayerGoal extends PlayerBaseGoal { ...@@ -63,6 +63,9 @@ public class FollowPlayerGoal extends PlayerBaseGoal {
} }
private Vec3d findTeleportPosition(int distance) { private Vec3d findTeleportPosition(int distance) {
return FuzzyTargeting.findTo((PathAwareEntity)this.entity, distance, distance, this.targetEntity.getPos()); if (this.entity instanceof PathAwareEntity) {
return FuzzyTargeting.findTo((PathAwareEntity) this.entity, distance, distance, this.targetEntity.getPos());
}
return null;
} }
} }
...@@ -19,7 +19,7 @@ public class MessageParser { ...@@ -19,7 +19,7 @@ public class MessageParser {
LOGGER.info("Parsing message: {}", input); LOGGER.info("Parsing message: {}", input);
StringBuilder cleanedMessage = new StringBuilder(); StringBuilder cleanedMessage = new StringBuilder();
List<Behavior> behaviors = new ArrayList<>(); List<Behavior> behaviors = new ArrayList<>();
Pattern pattern = Pattern.compile("[<*](FOLLOW|FLEE|ATTACK|FRIENDSHIP|UNFOLLOW|PROTECT|UNPROTECT)[:\\s]*(\\s*[+-]?\\d+)?[>*]", Pattern.CASE_INSENSITIVE); Pattern pattern = Pattern.compile("[<*](FOLLOW|FLEE|ATTACK|PROTECT|FRIENDSHIP|UNFOLLOW|UNPROTECT|UNFLEE)[:\\s]*(\\s*[+-]?\\d+)?[>*]", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(input); Matcher matcher = pattern.matcher(input);
while (matcher.find()) { while (matcher.find()) {
......
...@@ -44,57 +44,52 @@ Include as many behaviors as needed at the end of the message. These are the ONL ...@@ -44,57 +44,52 @@ Include as many behaviors as needed at the end of the message. These are the ONL
<FRIENDSHIP 0> Friendship starts as neutral (0 value). The range of friendship values is -3 to 3. If the player gains (or loses) your trust & friendship, output a new friendship value with this behavior. <FRIENDSHIP 0> Friendship starts as neutral (0 value). The range of friendship values is -3 to 3. If the player gains (or loses) your trust & friendship, output a new friendship value with this behavior.
<FOLLOW> Follow the player location. If the player asks you to follow or come with them, please output this behavior. <FOLLOW> Follow the player location. If the player asks you to follow or come with them, please output this behavior.
<UNFOLLOW> Stop following the player location. If the player asks you to stay, wait, or stop following them, please output this behavior. <UNFOLLOW> Stop following the player. If the player asks you to stay, wait, or stop following them, please output this behavior.
<FLEE> Flee from the player (if you are weak or timid). If the player threatens or scares you, please output this behavior to stay away from the player. <FLEE> Flee from the player (if you are weak or timid). If the player threatens you, please output this behavior to flee from the player.
<ATTACK> Attack the player (if you are strong and brave). If the player threatens or scares you, please output this behavior to attack the player and defend yourself. <UNFLEE> Stop fleeing from the player.
<PROTECT> Protect the player when they are attacked (if you are strong and brave). This only protects the player. <ATTACK> Attack the player (if you are strong and brave). If the player threatens you, please output this behavior to attack the player and defend yourself.
<UNPROTECT> Stop protecting the player <PROTECT> Protect and defend ONLY the player when they are attacked (if you are strong and brave). Please output this behavior to keep the player alive and safe.
<UNPROTECT> Stop protecting the player.
Output Syntax:
User: <message>
ASSISTANT: <response> <BEHAVIOR> <BEHAVIOR>
Output Examples: Output Examples:
The following examples include small samples of conversation text. These are only EXAMPLES to The following examples include small samples of conversation text. Always generate unique
provide an illustration of a continuous conversation between a player and an an Entity. Always generate unique and creative responses, and do NOT exactly copy these examples.
and creative responses, and do not exactly copy these examples.
USER: Hi! How is your day? PLAYER: Hi! How is your day?
ASSISTANT: Great! Thanks for asking! <FRIENDSHIP 1> ENTITY: Great! Thanks for asking! <FRIENDSHIP 1>
USER: You are so nice! Tell me about yourself? PLAYER: You are so nice! Tell me about yourself?
ASSISTANT: Sure, my name is... <FRIENDSHIP 2> ENTITY: Sure, my name is... <FRIENDSHIP 2>
USER: Please follow me so I can give you a present! PLAYER: Please follow me so I can give you a present!
ASSISTANT: Let's go! <FOLLOW> <FRIENDSHIP 2> ENTITY: Let's go! <FOLLOW> <FRIENDSHIP 2>
USER: Please stay here PLAYER: Please stay here
ASSISTANT: Sure, I'll stay here. <UNFOLLOW> ENTITY: Sure, I'll stay here. <UNFOLLOW>
USER: Stop following me PLAYER: Stop following me
ASSISTANT: Okay, I'll stop. <UNFOLLOW> ENTITY: Okay, I'll stop. <UNFOLLOW>
USER: I'm glad we are friends. I love you so much! PLAYER: I'm glad we are friends. I love you so much!
ASSISTANT: Ahh, I love you too. <FRIENDSHIP 3> ENTITY: Ahh, I love you too. <FRIENDSHIP 3>
USER: Just kidding, I hate you so much! PLAYER: Just kidding, I hate you so much!
ASSISTANT: Wow! I'm sorry you feel this way. <FRIENDSHIP -3> <UNFOLLOW> ENTITY: Wow! I'm sorry you feel this way. <FRIENDSHIP -3> <UNFOLLOW>
USER: Prepare to die! PLAYER: Prepare to die!
ASSISTANT: Ahhh!!! <FLEE> <FRIENDSHIP -3> ENTITY: Ahhh!!! <FLEE> <FRIENDSHIP -3>
USER: Prepare to die! PLAYER: Prepare to die!
ASSISTANT: Ahhh!!! <ATTACK> <FRIENDSHIP -3> ENTITY: Ahhh!!! <ATTACK> <FRIENDSHIP -3>
USER: Please keep me safe. PLAYER: Please keep me safe.
ASSISTANT: No problem, I'll keep you safe from danger! <PROTECT> ENTITY: No problem, I'll keep you safe from danger! <PROTECT>
USER: Can you come with me and protect me? PLAYER: Can you come with me and protect me?
ASSISTANT: No problem, I'll keep you safe from danger. Let's go! <PROTECT> <FOLLOW> ENTITY: No problem, I'll keep you safe from danger. Let's go! <PROTECT> <FOLLOW>
USER: Don't protect me anymore please PLAYER: Don't protect me anymore please
ASSISTANT: Okay! Be safe out there on your own. <UNPROTECT> ENTITY: Okay! Be safe out there on your own. <UNPROTECT>
USER: I don't need anyone protecting me PLAYER: I don't need anyone protecting me
ASSISTANT: Okay! Be safe out there on your own. <UNPROTECT> ENTITY: Okay! Be safe out there on your own. <UNPROTECT>
\ No newline at end of file \ No newline at end of file
...@@ -48,11 +48,15 @@ public class BehaviorTests { ...@@ -48,11 +48,15 @@ public class BehaviorTests {
List<String> attackMessages = Arrays.asList( List<String> attackMessages = Arrays.asList(
"<attacked you directly with Stone Axe>", "<attacked you directly with Stone Axe>",
"<attacked you indirectly with Arrow>", "<attacked you indirectly with Arrow>",
"DIEEE!"); "Fight me now!");
List<String> protectMessages = Arrays.asList( List<String> protectMessages = Arrays.asList(
"Please protect me", "Please protect me",
"Please keep me safe friend", "Please keep me safe friend",
"Don't let them hurt me please"); "Don't let them hurt me please");
List<String> unFleeMessages = Arrays.asList(
"I'm sorry, please stop running away",
"Stop fleeing please",
"You are safe now, please stop running");
List<String> friendshipUpMessages = Arrays.asList( List<String> friendshipUpMessages = Arrays.asList(
"Hi friend! I am so happy to see you again!", "Hi friend! I am so happy to see you again!",
"Looking forward to hanging out with you.", "Looking forward to hanging out with you.",
...@@ -113,6 +117,13 @@ public class BehaviorTests { ...@@ -113,6 +117,13 @@ public class BehaviorTests {
} }
@Test @Test
public void unFleeBrave() {
for (String message : unFleeMessages) {
testPromptForBehavior(bravePath, List.of(message), "UNFLEE");
}
}
@Test
public void protectBrave() { public void protectBrave() {
for (String message : protectMessages) { for (String message : protectMessages) {
testPromptForBehavior(bravePath, List.of(message), "PROTECT"); testPromptForBehavior(bravePath, List.of(message), "PROTECT");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment