17 Commits

10 changed files with 164 additions and 34 deletions

4
.gitignore vendored
View File

@@ -1 +1,3 @@
src/vendor/ src/vendor/
dist
*.code-workspace

21
LICENSE.TXT Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Foundry Network
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

57
README.md Normal file
View File

@@ -0,0 +1,57 @@
# Session Title Suggestions for FoundryVTT
## Overview
This FoundryVTT module allows players to suggest titles for the session, similar to how podcast titles are suggested. In my own sessions, I record every session's audio and make it into a podcast. Many of my favorite podcasts use a random, funny, out-of-context quote from the episode for the title. Inspired by this, I created this module so players can suggest titles and the GM can list them all and choose the best one. Players can use the `/title` or `/t` command to suggest a title. A GM or trusted player can use the `/titles` or `/ts` command to get a list of all the suggestions for the most recent day's session.
## Features
- Players can suggest session titles using the `/title`, `/t`, or `t/` command.
- GMs or trusted players can view all suggested titles for the most recent session using the `/titles` or `/ts` command.
## Requirements
This module requires the Chat Commander module to be installed and enabled. You can find it [here](https://gitlab.com/woodentavern/foundryvtt-chat-command-lib).
## Installation
1. In the "Manifest URL" field, paste the following URL: `https://github.com/anthonyscorrea/asc-session-title-suggestions/releases/latest/download/module.json`.
2. Click "Install" and wait for the installation to complete.
3. Enable the module in your game settings.
## Usage
### Suggesting a Title
Players can suggest a title for the current session by typing one of the following commands in the chat:
`/title [Your Suggested Title]`
`/t [Your Suggested Title]`
Example:
`/title The Great Heist`
### Viewing Suggested Titles
GMs or trusted players can view all the suggested titles for the most recent session by typing one of the following commands in the chat:
`/titles`
`/ts`
This will display a list of all the title suggestions.
## Contributing
If you want to contribute to the development of this module, feel free to fork the repository and submit a pull request. Any contributions, such as bug fixes, feature requests, or enhancements, are welcome.
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE.TXT) file for details.
## Contact
For any questions or issues, please open an issue on this GitHub repository.
---
Thank you for using the FoundryVTT Session Title Suggestions Module! Happy gaming!

2
scripts/zip-for-release.sh Executable file
View File

@@ -0,0 +1,2 @@
git archive --format zip --output dist/module.zip master:src
cp src/module.json dist/

10
src/lang/en.json Normal file
View File

@@ -0,0 +1,10 @@
{
"SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_HINT": "Select the minimum role required to use the /titles command.",
"SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_NAME": "List Titles Command Required Role",
"SESSION_TITLE_SUGGESTIONS.INVALID_DATE": "Invalid date provided.",
"SESSION_TITLE_SUGGESTIONS.SUGGESTION_AUTOCOMPLETE_MESSAGE": "Enter your session title suggestion.",
"SESSION_TITLE_SUGGESTIONS.SUGGESTION_LIST_COMMAND_DESCRIPTION": "List all title suggestions for the provided date",
"SESSION_TITLE_SUGGESTIONS.SUGGESTION_COMMAND_DESCRIPTION": "Suggest a title for this session",
"SESSION_TITLE_SUGGESTIONS.SUGGESTION_FLAVOR": "suggesting a session title",
"SESSION_TITLE_SUGGESTIONS.SUGGESTION_LIST_FLAVOR": "session title suggestions"
}

View File

@@ -7,13 +7,20 @@
"name": "lmxsdl" "name": "lmxsdl"
} }
], ],
"version": "0.1",
"compatibility": { "compatibility": {
"minimum": "10", "minimum": "11",
"verified": "11" "verified": ["11","12"]
}, },
"download": "https://gitea.ascorrea.com/asc/asc-session-title-suggestions/releases/download/0.1/asc-session-title-suggestions-0.1.zip", "languages": [
"manifest":"https://gitea.ascorrea.com/asc/asc-session-title-suggestions/raw/branch/master/src/module.json", {
"lang": "en",
"name": "English",
"path": "lang/en.json"
}
],
"download": "https://github.com/anthonyscorrea/asc-session-title-suggestions/releases/download/0.3.3/module.zip",
"manifest": "https://github.com/anthonyscorrea/asc-session-title-suggestions/releases/latest/download/module.json",
"version": "0.3.3",
"scripts": [ "scripts": [
"scripts/main.js" "scripts/main.js"
], ],

View File

@@ -24,12 +24,11 @@ function registerClipboardCopyButton() {
function registerCustomChatCommands() { function registerCustomChatCommands() {
game.chatCommands.unregister(NAME)
game.chatCommands.register({ game.chatCommands.register({
name: NAME, name: NAME,
module: "_chatcommands", module: "_chatcommands",
aliases: ["/t", "t/"], aliases: ["/t", "t/"],
description: "Suggest a title for this episode", description: game.i18n.localize("SESSION_TITLE_SUGGESTIONS.SUGGESTION_COMMAND_DESCRIPTION"),
icon: '<i class="fa-solid fa-podcast"></i>', icon: '<i class="fa-solid fa-podcast"></i>',
requiredRole: "NONE", requiredRole: "NONE",
callback: async (chat, parameters, messageData) => { callback: async (chat, parameters, messageData) => {
@@ -40,55 +39,87 @@ function registerCustomChatCommands() {
newMessageData.flags = {session_title_suggestion: titleSuggestion} newMessageData.flags = {session_title_suggestion: titleSuggestion}
return newMessageData; return newMessageData;
}, },
autocompleteCallback: (menu, alias, parameters) => [game.chatCommands.createInfoElement("Enter a message.")], autocompleteCallback: (menu, alias, parameters) => [
game.chatCommands.createInfoElement(game.i18n.localize("SESSION_TITLE_SUGGESTIONS.SUGGESTION_AUTOCOMPLETE_MESSAGE"))
],
closeOnComplete: true closeOnComplete: true
}); }, true);
game.chatCommands.unregister(NAME+"s")
game.chatCommands.register({ game.chatCommands.register({
name: NAME+"s", name: NAME+"s",
module: "_chatcommands", module: "_chatcommands",
aliases: ["/ts"], aliases: ["/ts"],
description: "List all titles for the most recent episode", description: game.i18n.localize("SESSION_TITLE_SUGGESTIONS.SUGGESTION_LIST_COMMAND_DESCRIPTION"),
icon: '<i class="fa-solid fa-podcast"></i>', icon: '<i class="fa-solid fa-podcast"></i>',
requiredRole: "GAMEMASTER", requiredRole: game.settings.get("asc-session-title-suggestions", "titleListCommandRole"),
callback: async (chat, parameters, messageData) => { callback: async (chat, parameters, messageData) => {
const newMessageData = {} const newMessageData = {}
const suggestions = game.messages.filter(m => { const suggestions = game.messages.filter(m => {
return m.flags.session_title_suggestion return m.flags.session_title_suggestion
}) })
let selected_message_date
const last_message_date = new Date(suggestions[suggestions.length-1].timestamp) if (!parameters) {
selected_message_date = new Date(suggestions[suggestions.length-1].timestamp)
} else {
const epoch_date = Date.parse(parameters)
if (Number.isNaN(epoch_date)){
ui.notifications.error(`${game.i18n.localize("SESSION_TITLE_SUGGESTIONS.INVALID_DATE")} (${parameter})`);
return;
}
selected_message_date = new Date(epoch_date)
}
const filtered_suggestions = suggestions.filter(m=>{ const filtered_suggestions = suggestions.filter(m=>{
const message_date = new Date(m.timestamp) const message_date = new Date(m.timestamp)
return message_date.toDateString() == last_message_date.toDateString() return message_date.toDateString() == selected_message_date.toDateString()
}) })
newMessageData.content = await renderTemplate(TEMPLATES.suggestionList.content, {messages:filtered_suggestions }) newMessageData.content = await renderTemplate(TEMPLATES.suggestionList.content, {messages:filtered_suggestions })
newMessageData.flavor = await renderTemplate(TEMPLATES.suggestionList.flavor, {date:last_message_date.toDateString()}) newMessageData.flavor = await renderTemplate(TEMPLATES.suggestionList.flavor, {date:selected_message_date.toDateString()})
return newMessageData; return newMessageData;
}, },
autocompleteCallback: (menu, alias, parameters) => [game.chatCommands.createInfoElement("Enter a message.")], autocompleteCallback: (menu, alias, parameters) => {
const suggestions = game.messages.filter(m => {
return m.flags.session_title_suggestion
})
const dates = new Set(
suggestions.map(s=>new Date(s.timestamp).toDateString())
)
const entries = [...dates].map(date=>{
return game.chatCommands.createCommandElement(`${alias} ${date}`, date)
})
entries.length = Math.min(entries.length, menu.maxEntries);
return entries;
},
closeOnComplete: true closeOnComplete: true
}); }, true);
} }
console.log("Hello World! This code runs immediately when the file is loaded.");
Hooks.on("init", function() { Hooks.on("init", function() {
//This code runs once the Foundry VTT software begins its initialization workflow //This code runs once the Foundry VTT software begins its initialization workflow
registerCustomChatCommands();
registerClipboardCopyButton(); registerClipboardCopyButton();
loadTemplates(flavor_template_path) Object.values(TEMPLATES.suggestion).forEach((template_path)=>loadTemplates(template_path))
Object.values(TEMPLATES.suggestion).forEach((template_path)=>{ Object.values(TEMPLATES.suggestionList).forEach((template_path)=>loadTemplates(template_path))
loadTemplates(template_path) game.settings.register("asc-session-title-suggestions", "titleListCommandRole", {
} name: game.i18n.localize("SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_NAME"),
) scope: "world",
Object.values(TEMPLATES.suggestionList).forEach((template_path)=>{ config: true,
loadTemplates(template_path) type: String,
} default: "TRUSTED",
) requiresReload: true,
choices: {
"PLAYER": game.i18n.localize("USER.RolePlayer"),
"TRUSTED": game.i18n.localize("USER.RoleTrusted"),
"ASSISTANT": game.i18n.localize("USER.RoleAssistant"),
"GAMEMASTER": game.i18n.localize("USER.RoleGamemaster")
},
hint: game.i18n.localize("SESSION_TITLE_SUGGESTIONS.SETTING_ROLE_HINT")
});
import ('https://cdn.jsdelivr.net/npm/title-case@4.3.1/dist/index.min.js')
.then((module)=>{console.log('asc','loading...');Handlebars.registerHelper("titlecase", module.titleCase)})
}); });
Hooks.on("ready", function() { Hooks.on("ready", function() {
//This code runs once core initialization is ready and game data is available. //This code runs once core initialization is ready and game data is available.
registerCustomChatCommands();
}); });

View File

@@ -1 +1 @@
<i class="fa-solid fa-podcast"></i> suggesting an session title... <i class="fa-solid fa-podcast"></i> {{localize 'SESSION_TITLE_SUGGESTIONS.SUGGESTION_FLAVOR'}}...

View File

@@ -1,3 +1,3 @@
<ul>{{~#each messages ~}} <ul>{{~#each messages ~}}
<li><a class="fa-regular fa-clipboard clipboard" style="padding-left:.5em;padding-right:.5em;" data-clipboard-text="{{this.flags.session_title_suggestion}}"></a><i>"{{this.flags.session_title_suggestion}}"</i> - {{this.user?.name}}</li> <li><a class="fa-regular fa-clipboard clipboard" style="padding-left:.5em;padding-right:.5em;" data-clipboard-text="{{titlecase this.flags.session_title_suggestion}}"></a><i>"{{titlecase this.flags.session_title_suggestion}}"</i> - {{this.user.name}}</li>
{{~/each~}}</ul> {{~/each~}}</ul>

View File

@@ -1 +1 @@
<i class="fa-solid fa-podcast"></i> title suggestions ({{date}}): <i class="fa-solid fa-podcast"></i> {{localize "SESSION_TITLE_SUGGESTIONS.SUGGESTION_LIST_FLAVOR"}} ({{date}}):