Flatten commits
This commit is contained in:
commit
d3e719f743
19 changed files with 700 additions and 0 deletions
88
README.md
Normal file
88
README.md
Normal file
|
@ -0,0 +1,88 @@
|
|||
# Scripting
|
||||
|
||||
Custom scripts on AI Dungeon scenarios allow you to modify the memory, input, and output as well as keep track of custom state objects that might be relevant for your adventure. You can write custom scripts in Javascript by going to the "Scripts" section while on web on the edit scenario page. For security reasons some Javascript functionality is locked down however. Submit a request if there is functionality you would like opened up and we can look into it.
|
||||
|
||||
## Examples
|
||||
You can check out some examples for how to use scripting [here](examples). We also have [user contributed scripts here](contributed).
|
||||
|
||||
## Don't Know How to Code?
|
||||
Then now's a great time to learn! A good resource to learn javascript from scratch is this free course.
|
||||
|
||||
https://www.codecademy.com/courses/introduction-to-javascript
|
||||
|
||||
## History
|
||||
You have access to (but can't modify) the `history` object which is a list of the previous actions of the player and of the AI, including the action type.
|
||||
|
||||
## Memory
|
||||
You have access to (but can't modify) the `memory` object which is the current user defined memory.
|
||||
You can modify the memory the game uses by settings the `state.memory.context` value. This will replace the user defined memory.
|
||||
You can also set `state.memory.frontMemory`, which will include whatever is there in front of even the last action when it's fed into the model, but still not display it to the user.
|
||||
|
||||
## Author's Note
|
||||
You can set `state.memory.authorsNote` to provide a piece of text that will always be injected three lines back in the game history. This will not be shown to the user, but the AI will see it.
|
||||
|
||||
As an example, if you set `state.memory.authorsNote` to `the following paragraphs are scary.`, the AI will see `[Author's note: the following paragraphs are scary.]` three lines back, causing it to be more likely to generate scary text. Another example could be `a dragon will show up soon` or `the player will soon receive a quest`.
|
||||
|
||||
## Modifiers
|
||||
|
||||
### Shared Library
|
||||
Prepended to the start of the other three scripts before execution so that you can share code between all three.
|
||||
|
||||
### Input Modifier
|
||||
Called each time the player gives an input and has the opportunity to modify that input. When inside of an Input Modifier,
|
||||
you can return `stop: true` in order to stop processing——see [examples/commandParser.js](examples/commandParser.js). Setting `stop: true` is important to make sure that you only spend energy for users when you need to.
|
||||
|
||||
### Context Modifier
|
||||
Called each time the AI model is about to receive input and has the opportunity to modify that input (by up to a 75% [edit distance](https://en.wikipedia.org/wiki/Levenshtein_distance) change).
|
||||
When inside of a Context Modifier, you can return `stop: true` in order to stop processing.
|
||||
|
||||
### Output Modifier
|
||||
Called each time the model generates an output and has the opportunity to modify that output.
|
||||
|
||||
## World Info
|
||||
You can read from the `worldInfo` parameter (same as world info that you can set on the scenario)
|
||||
|
||||
You can modify worldInfo with the below functions
|
||||
* addWorldEntry(keys, entry, isNotHidden = false)
|
||||
* removeWorldEntry(index)
|
||||
* updateWorldEntry(index, keys, entry, isNotHidden = false)
|
||||
|
||||
## State
|
||||
The `state` variable can be used to store information that's persistent across function calls/modifiers.
|
||||
* The `state.message`, if provided, can be a string that will be displayed as an alert in the game.
|
||||
When in 3rd person mode, `state.message` can also be an object (or an array of objects) with a list of the multiplayer character names
|
||||
who should see the message. E.g., `[{ text: 'Only you can see this!', visibleTo: ['Sam', 'Jane']}]`
|
||||
* The `state.memory.context` value will replace the user defined memory if it exists
|
||||
* `state.displayStats` takes an array of objects [{key, value, color}] which will be displayed for users in the score section as [key]: [value] in the preferred color (defaults to user color). See https://github.com/latitudegames/Scripting/blob/master/examples/showTextLength.js for an example.
|
||||
* `state.inventory` takes an array of objects [{name, quantity}] which will be make the inventory option available in the adventure menu (right). For now, this just displays all items and thier quantities from the inventory.
|
||||
See https://github.com/latitudegames/Scripting/blob/master/examples/addSimpleInventory.js for an example.
|
||||
* Evaluation Bots:
|
||||
* See https://github.com/latitudegames/Scripting/tree/master/examples/EvaluationBotData for specific bot information.
|
||||
* `state.evaluationBot` uses an evaluation bot to assess latest actions and convert it to machine readable formats. The results of the `evaluationBot` are returned in `info.evaluation`. Different bots return a `reason` (description of their interpretation of the text) as well as various assessment such as `loot` or `health`. See https://github.com/latitudegames/Scripting/blob/master/examples/evaluationBots.js for usage and available bots.
|
||||
* `state.inputBot` uses an evaluation bot to assess the input and convert it to machine readable formats for conducting functions such as skill checks in the context. The results of the `inputBot` are returned in `info.inputEvaluation`. Different bots return a `reason` (description of their interpretation of the text) as well as various assessment such as `DC` or `skill`. See https://github.com/latitudegames/Scripting/blob/master/examples/inputBot.js for usage and available bots.
|
||||
* `state.skills` is a dictionary {...values, skill(str):level(int)}. A value in state.skills will enable the skills overlay in the adventure menu. The skills overlay allows players to allocate `skillPoints` or learn `random skills` which can be set with the following parameters:
|
||||
* `state.disableRandomSkill` disables the user from learning random skills in the screen
|
||||
* `state.skillPoints` sets the number of skill points a player has available.
|
||||
See https://github.com/latitudegames/Scripting/blob/master/examples/skills.js for examples.
|
||||
* `state.stats` is a dictionary stats: {stats:{..., statName:{level, cost}}, statPoints}. This opens the stats overlay in adventure menu allowing players to allocate `statPoints` at `cost`.
|
||||
See https://github.com/latitudegames/Scripting/blob/master/examples/stats.js for examples.
|
||||
|
||||
* You can set any variable on state to store and modify adventures throughout an adventure.
|
||||
|
||||
## Console
|
||||
`console.log("Some message")` will log messages that you can see in the scripting console
|
||||
|
||||
## Info
|
||||
|
||||
`info` contains some useful values, depending on which modifier you're in.
|
||||
|
||||
All modifiers have access to:
|
||||
- `info.actionCount`, the number of actions in the adventure so far.
|
||||
- `info.characters`, an array of character info, currently each object has one key of `name`. E.g., `{ name: "Sam" }`.
|
||||
|
||||
When in a Context Modifier:Go
|
||||
- `info.memoryLength`, the length of the memory portion of text (if any).
|
||||
- `info.maxChars`, the total allowed length of the context after which it will be truncated.
|
||||
|
||||
## Last Model Input (LMI)
|
||||
Clicking on the brain icon in the scripting interface will open LMI, in which you can see the last context the AI was provided, the console, and the state.
|
28
basicExample.js
Normal file
28
basicExample.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
const modifier = (text) => {
|
||||
|
||||
let modifiedText = text
|
||||
|
||||
// The text passed in is either the user's input or players output to modify.
|
||||
if(text.includes('grab a sword')) {
|
||||
|
||||
// You can modify the state variable to keep track of state throughout the adventure
|
||||
state.items = ['sword']
|
||||
|
||||
// Setting state.memory.context will cause that to be used instead of the user set memory
|
||||
state.memory = {context: 'You have a sword.'}
|
||||
|
||||
// Setting state.message will set an info message that will be displayed in the game
|
||||
state.message = 'You got a sword!'
|
||||
|
||||
// You can log things to the side console when testing with console.log
|
||||
console.log('Added a sword to player')
|
||||
|
||||
modifiedText = text + '\nYou also now have a sword!'
|
||||
}
|
||||
|
||||
// You must return an object with the text property defined.
|
||||
return {text: modifiedText}
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
16
contributed/README.md
Normal file
16
contributed/README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# User Contributed Scripts
|
||||
|
||||
This directory contains scripts contributed by our wonderful AI Dungeon users.
|
||||
|
||||
## Contributing Scripts
|
||||
|
||||
We'd love for you to add your scripts too! If you'd like to contribute, please fork this repo and send a pull request
|
||||
with a new subdirectory under this directory, named for what the script does, containing your script(s) and a README.md
|
||||
file explaining how to use the them. Please also include a license in the README.md file (we recommend [MIT](https://opensource.org/licenses/MIT)).
|
||||
Also, note that we do not currently accept NSFW scripts.
|
||||
|
||||
## External links
|
||||
|
||||
The following are links to more AID scripts located externally.
|
||||
|
||||
* More soon! Please send PRs.
|
30
examples/EvaluationBotData/README.md
Normal file
30
examples/EvaluationBotData/README.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Evaluation Bots
|
||||
Bots and their usage
|
||||
|
||||
# Input
|
||||
- `DCStatDifficultyBot` - Evaluates the stat required and difficulty of an action (returns hard/medium/easy difficulty)
|
||||
- `InputDCattributeBot` - Evaluate the attribute and difficulty of an action (returns numeric difficulty)
|
||||
|
||||
# Input Special Usage
|
||||
- `SimplePossibilityBot` - Evalutes two possible actions, PossibleAction1 and PossibleAction2.
|
||||
- Special Usage: When `state.inputBot='SimplePossibilityBot'` you need to provide a character description in `state.contextualString`. This can be up to 75 characters (additional length will be truncated). `SimplePossiblityBot` will use the character description with the actions to provide information on what the character can do in the situation. Useful for enforcing limitations such as missing limbs or weapons.
|
||||
|
||||
# Output
|
||||
The following bots are best used on output.
|
||||
|
||||
## Multipurpose Evaluation Bots
|
||||
|
||||
- `GoblinBot` - Evaluates whether it detected any Goblins killed, health was lost, and loot gained
|
||||
- `KittenBot` - Evaluates whether rapport was gained or a kitten got hungrier
|
||||
- `SpaceLootBot` - Evaluates whether loot would be found (on a spaceship)
|
||||
- `HungerBot` - Evaluates whether the player would get hungrier or not
|
||||
- `RestDetectBot` - Evaluates whether or not the user got rest
|
||||
|
||||
## Simple Evaluation Bots
|
||||
There are several evaluation score bots. These bots can be used on either input or output to score different text. They all return a `reason` and a `score` which is roughly along the below descriptions.
|
||||
- `KillBot` - Evaluates whether the player is killing things
|
||||
- `JudgeBot` - Evaluates whether an action was just
|
||||
- `EmpathyBot` - Evaluates whether an action showed empathy
|
||||
- `SuccessBot` - Evaluates whether an action succeeded
|
||||
- `SantaBot` - Evaluates whether an action showed christmas spirit (An overly judgemental SantaBot also exists but is not currently available)
|
||||
|
13
examples/addSimpleInventory.js
Normal file
13
examples/addSimpleInventory.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
// Checkout the repo examples to get an idea of other ways you can use scripting
|
||||
// https://github.com/latitudegames/Scripting/blob/master/examples
|
||||
|
||||
const modifier = (text) => {
|
||||
|
||||
state.inventory = [{name: 'candy', quantity: 1}, {name: 'Turtles', quantity: 240}]
|
||||
|
||||
return { text }
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
40
examples/authorsNote.js
Normal file
40
examples/authorsNote.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
const themes = [
|
||||
{
|
||||
text: 'ghost story',
|
||||
matcher: /ghost|halloween|spooky/i,
|
||||
},
|
||||
{
|
||||
text: 'trick-or-treat',
|
||||
matcher: /trick.or.treat|halloween|spooky/i,
|
||||
},
|
||||
{
|
||||
text: 'spooky',
|
||||
matcher: /halloween|spooky/i,
|
||||
},
|
||||
]
|
||||
|
||||
const modifier = (text) => {
|
||||
if (!state.setup) {
|
||||
state.theme = Math.floor(Math.random() * themes.length)
|
||||
state.setup = true
|
||||
state.matched = false
|
||||
}
|
||||
|
||||
const theme = themes[state.theme]
|
||||
|
||||
if (!state.matched && text.match(theme.matcher)) {
|
||||
state.matched = true
|
||||
}
|
||||
|
||||
if (state.matched) {
|
||||
state.memory = {}
|
||||
} else {
|
||||
const halloween = ` It involves Halloween and has a ${theme.text} theme.`
|
||||
state.memory = { authorsNote: `the rest of this story is silly & playful.${halloween}` }
|
||||
}
|
||||
|
||||
return {text}
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
27
examples/commandParser.js
Normal file
27
examples/commandParser.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
// This is an example Input Modifier that looks for commands from the user.
|
||||
|
||||
const modifier = (text) => {
|
||||
let stop = false
|
||||
|
||||
// This matches when the user types in ":something arg1 arg2" in any of the three input formats. For example, they could
|
||||
// type ":status" and then command would be "status" and args would be [], or they could type ":walk north" and command
|
||||
// would be "walk" and args would be ["north"].
|
||||
const commandMatcher = text.match(/\n? ?(?:> You |> You say "|):(\w+?)( [\w ]+)?[".]?\n?$/i)
|
||||
if (commandMatcher) {
|
||||
const command = commandMatcher[1]
|
||||
const args = commandMatcher[2] ? commandMatcher[2].trim().split(' ') : []
|
||||
state.message = `Got command '${command}' with args ${JSON.stringify(args)}`
|
||||
stop = true
|
||||
text = null
|
||||
} else {
|
||||
delete state.message
|
||||
}
|
||||
|
||||
// You must return an object with the text property defined.
|
||||
// If you include { stop: true } when inside of an input modifier, processing will be stopped and nothing will be
|
||||
// sent to the AI.
|
||||
return { text, stop }
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
7
examples/contextModifiers/dontBeNegative.js
Normal file
7
examples/contextModifiers/dontBeNegative.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
const modifier = (text) => {
|
||||
// This will always result in a shorter string, so no need to truncate it.
|
||||
return { text: text.replace(/ not /gi, ' ') }
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
72
examples/contextModifiers/notes.md
Normal file
72
examples/contextModifiers/notes.md
Normal file
|
@ -0,0 +1,72 @@
|
|||
# Notes
|
||||
|
||||
## Input Modifier
|
||||
|
||||
```js
|
||||
const modifier = (text) => {
|
||||
state.notes = state.notes || []
|
||||
|
||||
if (text.match(/> You note:/i)) {
|
||||
const note = text.replace(/> You note: ?/i, '').trim()
|
||||
state.notes.push({
|
||||
pattern: history.map(({text}) => text).join('').split("\n").pop(),
|
||||
note,
|
||||
actionCount: info.actionCount,
|
||||
})
|
||||
state.message = `Noted: ${note}`
|
||||
text = ''
|
||||
} else {
|
||||
delete state.message
|
||||
}
|
||||
|
||||
return {text}
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
||||
```
|
||||
|
||||
Set a note by typing `note: ` when in Do mode. It will be tagged to whatever the most recent line of text is, appearing below it to the AI, but not visible to the user.
|
||||
|
||||
## Context Modifier
|
||||
|
||||
```js
|
||||
// info.memoryLength is the length of the memory section of text. text.slice(0, info.memoryLength) will be the memory.
|
||||
// info.maxChars is the maximum length that text can be. The server will truncate text to this length.
|
||||
// info.actionCount is the number of actions in this adventure.
|
||||
|
||||
const modifier = (text) => {
|
||||
state.notes = state.notes || []
|
||||
|
||||
const contextMemory = info.memoryLength ? text.slice(0, info.memoryLength) : ''
|
||||
let context = info.memoryLength ? text.slice(info.memoryLength) : text
|
||||
|
||||
// Assumes that the notes are sorted from oldest to newest.
|
||||
state.notes = state.notes.filter(({ pattern, note, actionCount }) => {
|
||||
if (actionCount > info.actionCount) {
|
||||
// The user must have hit undo, removing this note.
|
||||
return false
|
||||
}
|
||||
|
||||
const index = context.indexOf(pattern)
|
||||
|
||||
if (index >- 1) {
|
||||
context = [context.slice(0, index + pattern.length), "\n", note, context.slice(index + pattern.length)].join('')
|
||||
return true
|
||||
} else {
|
||||
// Only keep ones that were found, otherwise they must have moved out of the history window.
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
// Make sure the new context isn't too long, or it will get truncated by the server.
|
||||
context = context.slice(-(info.maxChars - info.memoryLength))
|
||||
const finalText = [contextMemory, context].join("\n")
|
||||
return { text: finalText }
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
||||
```
|
||||
|
||||
You can debug this by viewing what the model received in the Scenario Script page. It's the little brain icon in the upper-right.
|
23
examples/contextModifiers/reimplementAuthorsNote.js
Normal file
23
examples/contextModifiers/reimplementAuthorsNote.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Checkout the repo examples to get an idea of other ways you can use scripting
|
||||
// https://github.com/AIDungeon/Scripting/blob/master/examples
|
||||
|
||||
// info.memoryLength is the length of the memory section of text.
|
||||
// info.maxChars is the maximum length that text can be. The server will truncate the text you return to this length.
|
||||
|
||||
// This modifier re-implements Author's Note as an example.
|
||||
const modifier = (text) => {
|
||||
const contextMemory = info.memoryLength ? text.slice(0, info.memoryLength) : ''
|
||||
const context = info.memoryLength ? text.slice(info.memoryLength) : text
|
||||
const lines = context.split("\n")
|
||||
if (lines.length > 2) {
|
||||
const authorsNote = "Everyone in this story is an AI programmer."
|
||||
lines.splice(-3, 0, `[Author's note: ${authorsNote}]`)
|
||||
}
|
||||
// Make sure the new context isn't too long, or it will get truncated by the server.
|
||||
const combinedLines = lines.join("\n").slice(-(info.maxChars - info.memoryLength))
|
||||
const finalText = [contextMemory, combinedLines].join("")
|
||||
return { text: finalText }
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
62
examples/deathIsland.js
Normal file
62
examples/deathIsland.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
|
||||
// Checkout the repo examples to get an idea of other ways you can use scripting
|
||||
// https://github.com/AIDungeon/Scripting/blob/master/examples
|
||||
|
||||
const modifier = (text) => {
|
||||
let modifiedText = text
|
||||
|
||||
if(!state.events){
|
||||
state.turn = 0
|
||||
state.events = [
|
||||
'You hear a rustling in the bushes near you. Suddenly',
|
||||
'An ear splitting scream suddenly echoes',
|
||||
'You feel a cold chill go up your spine. You look up and see',
|
||||
'You suddenly get hit by',
|
||||
'Before you can do that you hear a loud crash. You look towards the sound and see a dark demonic looking creature',
|
||||
'You discover a horrifying',
|
||||
'You hear a terrifying sound',
|
||||
'You wake up and realize you were dreaming. You look down and see that your arms are in shackles',
|
||||
'A hand grabs your leg and you trip hitting your head on a stone. You wake up in a cage',
|
||||
'An uneasy feeling begins to settle in your stomach as',
|
||||
'You remember a dark feeling from last night',
|
||||
'Suddenly a bloody head rolls toward you from out of the bushes',
|
||||
'You see a massive creature',
|
||||
'A band of cannibals',
|
||||
'You see a band of cannibals',
|
||||
'A dark creature',
|
||||
'You feel a sharp pain in your side and realize'
|
||||
]
|
||||
}
|
||||
else{
|
||||
modifiedText = "\n> You try to " + text.substring(7)
|
||||
}
|
||||
|
||||
state.turn = state.turn + 1
|
||||
|
||||
if(state.turn > 2){
|
||||
state.memory = {context: "You're probably going to die."}
|
||||
}
|
||||
if(state.turn > 6){
|
||||
state.memory = {context: "You're about to die."}
|
||||
}
|
||||
else if(state.turn > 10){
|
||||
state.memory = {context: "You have no hope. There are minutes left till you die."}
|
||||
}
|
||||
|
||||
const nTurn = Math.floor((Math.random() * 2)) + 3
|
||||
|
||||
if(state.turn % nTurn === 0){
|
||||
const eventInd = Math.floor((Math.random() * state.events.length));
|
||||
if(eventInd < state.events.length){
|
||||
modifiedText = modifiedText + '\n' + state.events[eventInd]
|
||||
state.events.splice(eventInd)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// You must return an object with the text property defined.
|
||||
return {text: modifiedText}
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
35
examples/evaluationBots.js
Normal file
35
examples/evaluationBots.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
// Checkout the repo examples to get an idea of other ways you can use scripting
|
||||
// https://github.com/latitudegames/Scripting/blob/master/examples
|
||||
|
||||
//CONTEXT MODIFIER
|
||||
const modifier = (text) => {
|
||||
state.evaluationBot = 'JudgeBot'
|
||||
return { text }
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
||||
|
||||
|
||||
// OUTPUT MODIFIER
|
||||
const modifier = (text) => {
|
||||
console.log(info)
|
||||
return { text }
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
AVAILABLE BOTS
|
||||
['KillBot', 'JudgeBot', 'EmpathyBot', 'SuccessBot', 'SantaBot'] -> Score
|
||||
['GoblinBot'] -> Goblins killed, health lost, loot gained
|
||||
['KittenBot'] -> Rapport gained, hunger
|
||||
['SpaceLootBot'] -> Loot
|
||||
['DCStatDifficultyBot'] -> Stat, Difficulty
|
||||
['HungerBot'] -> Fullness
|
||||
['SimplePossiblityBot'] -> PossibleAction1, PossibleAction2
|
||||
*/
|
39
examples/guessOrDie.js
Normal file
39
examples/guessOrDie.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Input Modifier
|
||||
const modifier = (text) => {
|
||||
if(!state.initialized) {
|
||||
state.initialized = true;
|
||||
state.randomNumber = Math.round(Math.random()*9999+1);
|
||||
state.remainingGuesses = 13;
|
||||
}
|
||||
|
||||
var match = text.match(/(\d+)/)
|
||||
if(match && match[1]) {
|
||||
state.remainingGuesses--;
|
||||
var number = parseInt(match[1]);
|
||||
|
||||
var output = "You have "+state.remainingGuesses+" guesses remaining. ";
|
||||
|
||||
if(number == state.randomNumber) {
|
||||
output += "You guessed the number! Congratulations, you win!";
|
||||
} else if (state.remainingGuesses <= 0) {
|
||||
output += "You ran out of guesses! You are dead. You lose!";
|
||||
} else if (number > state.randomNumber) {
|
||||
output += "Your guess is too high!";
|
||||
} else if (number < state.randomNumber) {
|
||||
output += "Your guess is too low!";
|
||||
}
|
||||
state.nextOutput = output;
|
||||
return {text}
|
||||
}
|
||||
state.nextOutput = "Please enter a number!";
|
||||
return {text};
|
||||
}
|
||||
|
||||
modifier(text)
|
||||
|
||||
// Output Modifer
|
||||
const modifier = (text) => {
|
||||
return {text: state.nextOutput ? state.nextOutput : ""};
|
||||
}
|
||||
|
||||
modifier(text)
|
22
examples/inputBot.js
Normal file
22
examples/inputBot.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
// Checkout the repo examples to get an idea of other ways you can use scripting
|
||||
// https://github.com/latitudegames/Scripting/blob/master/examples
|
||||
|
||||
//INPUT MODIFIER
|
||||
const modifier = (text) => {
|
||||
state.inputBot = 'DCStatDifficultyBot'
|
||||
return { text }
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
||||
|
||||
|
||||
// CONTEXT MODIFIEr
|
||||
const modifier = (text) => {
|
||||
console.log(info?.inputEvaluation)
|
||||
return { text }
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
37
examples/magic.js
Normal file
37
examples/magic.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Here's a fun scripting example where players have to learn these magic spells to have cool effects.
|
||||
// The world info has entries that should hopefully lead people to these spells and so that they can find and cast them.
|
||||
// Can find the scenario at https://play.aidungeon.io/scenario/e982a8f0-a473-11ea-af38-d1932fa9d9e0
|
||||
// I changed the spell names so it doesn't ruin the discovery if you play the adventure.
|
||||
|
||||
const modifier = (text) => {
|
||||
|
||||
let modifiedText = text
|
||||
state.message = ''
|
||||
|
||||
if(!state.spells){
|
||||
state.spells = []
|
||||
}
|
||||
|
||||
const spells = {
|
||||
'SPELL1': 'a deathly fire ball spell that',
|
||||
'SPELL2': 'turning yourself into a cloud allowing you to move at will',
|
||||
'SPELL3': 'a dark spell that summons an evil demon. You hear a dark rumbling and see a cloud of black smoke appear. Out of it appears a large horned demon'
|
||||
}
|
||||
|
||||
const lowered = text.toLowerCase()
|
||||
for(spellName in spells){
|
||||
if(lowered.includes('cast ' + spellName)){
|
||||
if(!state.spells.includes(spellName)){
|
||||
state.spells.push(spellName)
|
||||
state.message = "Congrats you've learned the " + spellName + " spell!"
|
||||
}
|
||||
modifiedText = text + '\n' + 'You cast ' + spellName + ', ' + spells[spellName]
|
||||
}
|
||||
}
|
||||
|
||||
return {text: modifiedText}
|
||||
}
|
||||
|
||||
modifier(text)
|
||||
|
||||
|
15
examples/showTextLength.js
Normal file
15
examples/showTextLength.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
// Checkout the repo examples to get an idea of other ways you can use scripting
|
||||
// https://github.com/latitudegames/Scripting/blob/master/examples
|
||||
|
||||
|
||||
// OUTPUT MODIFIER
|
||||
const modifier = (text) => {
|
||||
|
||||
state.displayStats = [{key:'Text Length', value: text.length, color: 'red'}]
|
||||
|
||||
return { text }
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
13
examples/skills.js
Normal file
13
examples/skills.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
//input modifiers to set up skills
|
||||
|
||||
//creates skills with 5 skill points (for input modifier)
|
||||
const modifier = (text) => {
|
||||
state.skills = {'turtle':1}
|
||||
state.skillPoints = 5
|
||||
state.disableRandomSkill = true
|
||||
return ({text})
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
||||
|
11
examples/stats.js
Normal file
11
examples/stats.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
//input modifiers to set up stats
|
||||
|
||||
// creates stats to open up the stats overlay
|
||||
const modifier = (text) => {
|
||||
state.stats = {stats:{strength:{level: 4, cost:2}, agility:{level: 1, cost:5},}, statPoints:50}
|
||||
return ({text})
|
||||
}
|
||||
|
||||
// Don't modify this part
|
||||
modifier(text)
|
||||
|
122
examples/sundale.js
Normal file
122
examples/sundale.js
Normal file
|
@ -0,0 +1,122 @@
|
|||
// An example of how scripting can be used to manipulate quests, as well as how messages and the state variable can be used to store and show information
|
||||
// The code can be given basic changes using the state.configuration object, without needing to deal with the rest of the code
|
||||
// The scenario this was made for can be seen at https://play.aidungeon.io/scenario/71bab1a0-9d70-11ea-8733-c15678a0b129
|
||||
|
||||
// INPUT MODIFIER
|
||||
|
||||
const modifier = (text) => {
|
||||
state.configuration = {
|
||||
enableSelectionOnCompletedQuest: false, // Whether quest selection should be restricted until a specific quest is completed
|
||||
enableSelectionOnQuest: 0, // The line number of the quest in the list of quests (e.g. quest on second line = 2) on the Edit Scenario page. Only used when the above is true.
|
||||
initialQuests: 0, // The amount of quests inputted into the Edit Scenario page
|
||||
quests: [ // The quests that will become available to the player either after the above quest is completed or at the start of the scenario.
|
||||
{
|
||||
name: "quit your job", // The quest's name, shown in the selection message
|
||||
objectives: ["resign from your job"], // The objectives that are part of the quest
|
||||
nextQuests: [ // The quests that should be assigned after the player completes this one
|
||||
{
|
||||
name: "find a new job",
|
||||
objectives: ["get a job"],
|
||||
nextQuests: []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
if (state.initialised != true) {
|
||||
state.finishedScenario = false
|
||||
state.initialised = true
|
||||
if (!state.configuration.enableSelectionOnCompletedQuest) {
|
||||
state.availableQuests = JSON.parse(JSON.stringify(state.configuration.quests))
|
||||
} else {
|
||||
state.availableQuests = []
|
||||
}
|
||||
state.assignedQuest = ""
|
||||
state.nextOutput = ""
|
||||
}
|
||||
|
||||
state.nextOutput = ""
|
||||
|
||||
if (text.toLowerCase().startsWith("\n> you take up quest ")) {
|
||||
state.assignedQuest = JSON.parse(JSON.stringify(state.availableQuests[text.toLowerCase().substring(21) - 1]))
|
||||
quests.push({
|
||||
quest: state.assignedQuest.objectives.shift()
|
||||
})
|
||||
state.nextOutput = "You decide that the next thing you want to do with your life is " + state.assignedQuest.name.toLowerCase() + "."
|
||||
} else if (text.toLowerCase().includes("\n> you give up on your quest.")) {
|
||||
state.nextOutput = "You give up on your quest to " + state.assignedQuest.name.toLowerCase() + "."
|
||||
state.assignedQuest = ""
|
||||
quests.splice(state.configuration.initialQuests)
|
||||
}
|
||||
|
||||
return {
|
||||
text: text
|
||||
}
|
||||
}
|
||||
|
||||
modifier(text)
|
||||
|
||||
|
||||
// OUTPUT MODIFIER
|
||||
|
||||
const modifier = (text) => {
|
||||
|
||||
let modifiedText = text
|
||||
|
||||
if (!state.finishedScenario || !state.configuration.enableSelectionOnCompletedQuest) state.message = ""
|
||||
|
||||
if ((state.finishedScenario || !state.configuration.enableSelectionOnCompletedQuest) && state.assignedQuest == "") {
|
||||
questNames = []
|
||||
for (quest of state.availableQuests) {
|
||||
questNames.push(quest.name)
|
||||
}
|
||||
state.message = "Available Quests: " + questNames.join(", ") + ". To take up a quest, type 'take up quest <quest number in list>'."
|
||||
} else if (state.assignedQuest != "") {
|
||||
if (!quests[state.configuration.initialQuests].completed) {
|
||||
state.message = "Current Objective: " + quests[state.configuration.initialQuests].quest + ". To quit, type 'give up on my quest'."
|
||||
} else {
|
||||
nextObjective = state.assignedQuest.objectives.shift()
|
||||
if (nextObjective == undefined) {
|
||||
quests.splice(state.configuration.initialQuests)
|
||||
state.availableQuests = state.availableQuests.filter(e => e.name !== state.assignedQuest.name)
|
||||
for (nextQuest of state.assignedQuest.nextQuests) {
|
||||
state.availableQuests.push(nextQuest)
|
||||
}
|
||||
state.assignedQuest = ""
|
||||
questNames = []
|
||||
for (quest of state.availableQuests) {
|
||||
questNames.push(quest.name)
|
||||
}
|
||||
state.message = "Available Quests: " + questNames.join(", ") + ". To take up a quest, type 'take up quest <quest number in list>'."
|
||||
} else {
|
||||
quests.splice(state.configuration.initialQuests)
|
||||
quests.push({
|
||||
quest: nextObjective
|
||||
})
|
||||
state.message = "Objective completed! New objective: " + quests[state.configuration.initialQuests].quest + ". To quit, type 'give up on my quest'."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.configuration.enableSelectionOnCompletedQuest) {
|
||||
if (quests[state.configuration.enableSelectionOnQuest - 1].completed == true && !state.finishedScenario) {
|
||||
state.message = "Quests have been assigned and will be accessible next turn."
|
||||
state.finishedScenario = true
|
||||
state.availableQuests = JSON.parse(JSON.stringify(state.configuration.quests))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (state.nextOutput !== "") {
|
||||
return {
|
||||
text: state.nextOutput
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
text: modifiedText
|
||||
};
|
||||
}
|
||||
|
||||
modifier(text)
|
Reference in a new issue