Compare commits

..

8 Commits

9 changed files with 149 additions and 34 deletions

19
.rubocop.yml Normal file
View File

@ -0,0 +1,19 @@
Style/TrailingCommaInArguments:
Enabled: false
Style/TrailingCommaInArrayLiteral:
Enabled: false
Style/TrailingCommaInHashLiteral:
Enabled: false
Style/StringLiterals:
Enabled: false
Layout/HashAlignment:
Enabled: false
Style/FrozenStringLiteralComment:
Enabled: false
Style/ClassAndModuleChildren:
Enabled: false
EnforcedStyle: compact
Style/NegatedIf:
Enabled: false
Style/AccessModifierDeclarations:
Enabled: false

View File

@ -9,7 +9,8 @@ source "https://rubygems.org"
# gem "slim", "~> 4"
# discord, irc, ...
gem "discordrb", "~> 3"
# gem "discordrb", git: "https://github.com/shardlab/discordrb"
gem "discordrb", github: "shardlab/discordrb", glob: '*.gemspec' # ref: "dc27fe18463da3ccfd0f0266030aa7ad51b2c2b9"
# database
gem "sequel", "~> 5"
@ -46,3 +47,5 @@ group :test do
end
gem "roo", "~> 2.9.0"
gem "yard", "~> 0.9.28"

View File

@ -1,3 +1,17 @@
GIT
remote: https://github.com/shardlab/discordrb.git
revision: dc27fe18463da3ccfd0f0266030aa7ad51b2c2b9
glob: *.gemspec
specs:
discordrb (3.4.2)
discordrb-webhooks (~> 3.4.2)
ffi (>= 1.9.24)
opus-ruby
rest-client (>= 2.0.0)
websocket-client-simple (>= 0.3.0)
discordrb-webhooks (3.4.2)
rest-client (>= 2.0.0)
GEM
remote: https://rubygems.org/
specs:
@ -9,14 +23,6 @@ GEM
coderay (1.1.3)
colorize (0.8.1)
concurrent-ruby (1.1.10)
discordrb (3.4.0)
discordrb-webhooks (~> 3.3.0)
ffi (>= 1.9.24)
opus-ruby
rest-client (>= 2.0.0)
websocket-client-simple (>= 0.3.0)
discordrb-webhooks (3.3.0)
rest-client (>= 2.1.0.rc1)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.8.1)
@ -62,10 +68,13 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
webrick (1.7.0)
websocket (1.2.9)
websocket-client-simple (0.5.1)
websocket-client-simple (0.6.0)
event_emitter
websocket
yard (0.9.28)
webrick (~> 1.7.0)
PLATFORMS
x86_64-linux
@ -73,7 +82,7 @@ PLATFORMS
DEPENDENCIES
activesupport (~> 7)
colorize (~> 0)
discordrb (~> 3)
discordrb!
dotenv (~> 2)
m (~> 1)
minitest (~> 5)
@ -83,6 +92,7 @@ DEPENDENCIES
roo (~> 2.9.0)
sequel (~> 5)
sqlite3 (~> 1)
yard (~> 0.9.28)
BUNDLED WITH
2.3.17
2.3.22

View File

@ -19,13 +19,13 @@ bundle install
echo DISCORD_TOKEN=XXXX > .env
echo DATABASE_URL=sqlite://dev.db >> .env
rake db:migrate
bundle exec rake db:migrate
```
## Run discord
```
./src/discord/bot.rb
bundle exec ./src/discord/bot.rb
```
## Development
@ -39,13 +39,13 @@ rake db:migrate
### Run tests
```
rake test
bundle exec rake test
```
### Generate local dock
```
yard -- src
bundle exec yard -- src
```
### Discord: Create a new plugin

3
bin/discordbot Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env sh
bundle exec ./src/discord/bot.rb

View File

@ -9,8 +9,8 @@ class MetalAdventuresDiscord::CleanPlugin
HISTORY_SIZE = 100
REGEXP_TO_CLEAN = [
/^!ref/, /^!roll/, /^!clean/,
]
/^!(ref|refs|roll|clean)/,
].freeze
def hook_scene!
@bot.message(with_text: /^!clean/) do |event|

View File

@ -1,5 +1,6 @@
require "yaml"
# Refs handles rules as written
class MetalAdventuresDiscord::RefsPlugin
include Gem::Text # #levenshtein_distance/2
@ -7,6 +8,7 @@ class MetalAdventuresDiscord::RefsPlugin
@bot = bot
@ref_cache = {}
hook_ref!
hook_refs!
end
REF_HOOK_SPECIAL = {
@ -17,17 +19,41 @@ class MetalAdventuresDiscord::RefsPlugin
"page" => "ref",
"full" => "full",
"tout" => "full",
}
}.freeze
# !refs will generate a few messages with a component that shows actions (by chunks of 25 rules)
def hook_refs!
@bot.message(with_text: /^!refs$/) do |event|
list_refs.each_slice(25) do |refs_slice|
event.message.reply!(
"Recherche de règles (#{refs_slice.first} - #{refs_slice.last})",
# components: _components_search_refs,
components: _components_search_list(refs_slice),
)
end
end
@bot.interaction_create do |event|
values = event.interaction.data["values"] # TODO: pattern matching for destructuration
custom_id = event.interaction.data["custom_id"]
if custom_id == "class_select_ref" && values.size > 0
values.each do |ref_name|
begin
ref = load_ref(name: ref_name)
event.channel.send_embed "", ref_to_embed(event, ref, "full")
rescue StandardError => _e
event.channel.send_embed "", _err_invalid_ref_embed(ref_name)
end
end
end
end
end
# !ref short blablabla
# !ref full blablabla
# !ref blablabla
# event.message.reply! "Yo frèro", embed: { image: { url: event.user.avatar_url } }
def hook_ref!
@bot.message(with_text: /^!refs$/) do |event|
event.message.reply Dir.glob("scenes/actions/*.yaml").map { _1.tr('_', ' ').split('/').last.split('.').first }.join(', ')
end
@bot.message(with_text: /!ref .+/) do |event|
match = event.message.content.match(/\A!ref (?<total>(?<modifier>\w+ )?(?<nomodifier>.+))/)
ref_name = match["total"]
@ -39,10 +65,8 @@ class MetalAdventuresDiscord::RefsPlugin
ref_name = match["nomodifier"]
end
ref_filename = "#{ref_name.downcase.tr(' ', '_')}.yaml"
begin
ref = load_ref(ref_filename)
ref = load_ref(name: ref_name)
event.message.reply! "", embed: ref_to_embed(event, ref, display_choice)
rescue StandardError => _e
event.message.reply! "", embed: _err_invalid_ref_embed(ref_name)
@ -50,6 +74,51 @@ class MetalAdventuresDiscord::RefsPlugin
end
end
def list_refs
Dir.glob("scenes/actions/*.yaml").map { _1.tr('_', ' ').split('/').last.split('.').first }
end
# TODO: not working yet
# generate a text input
def _components_search_refs
[
{
"type" => 1,
"components" => [
{
"type" => 4,
"custom_id" => "search_refs_field",
"label" => "Text to search",
"style" => 1,
# "min_length" => 0,
# "max_length" => 80,
# "placeholder" => "Courir",
# "required" => true,
},
],
},
]
end
# Generate a menu to show all refs
def _components_search_list(refs)
[
{
"type" => 1,
"components" => [
{
"type" => 3,
"custom_id" => "class_select_ref",
"options" => refs.map { { "label" => _1, "value" => _1, "description" => _1, } },
"placeholder" => "Reference à afficher",
"min_values" => 1,
"max_values" => 1,
},
],
},
]
end
def _err_invalid_ref_embed(ref)
{
color: 0xFF0000,
@ -58,8 +127,15 @@ class MetalAdventuresDiscord::RefsPlugin
}
end
def load_ref(filename)
@ref_cache[filename] ||= YAML.load_file("scenes/actions/#{filename}")
# Load an existing ref by filename or name.
# It will cache without TTL the result to fasten the operation by default.
def load_ref(filename: nil, name: nil, cache: true)
filename = "#{name.downcase.tr(' ', '_')}.yaml" if name && !filename
if cache
@ref_cache[filename] ||= YAML.load_file("scenes/actions/#{filename}")
else
YAML.load_file("scenes/actions/#{filename}")
end
end
DURATIONS = { "S" => "Simple", "C" => "Complexe", "G" => "Gratuite", nil => "Spéciale" }.freeze
@ -71,7 +147,10 @@ class MetalAdventuresDiscord::RefsPlugin
"FS" => "Fer et Sang",
"PE" => "Pirates de l'Espace",
"MA" => "Mutant Apocalypse",
}
}.freeze
# Generate a discord embed for the ref.
# Several formats of ref are available (see the constant {REFS})
def ref_to_embed(_event, ref, display_choice)
description =
case display_choice

View File

@ -1,3 +1,4 @@
require "rubygems/text"
class MetalAdventuresDiscord::ScenesPlugin
include Gem::Text # #levenshtein_distance/2

View File

@ -8,11 +8,11 @@ module MetalAdventures
# 2 partial change to one onrmal
# sc and pmf cancel e2f
#
# :sc|:SC : "seconde chance", reroll failed dice and sum
# :pmf|:PMF : "peut mieux faire", reroll success and sum
# :e2f|:E2F : "easy to fail", reroll success to confirm
# :td : "très difficile", only 6 are success
# :tf : "très facile", only 1 are failures
# - :sc, :SC : "seconde chance", reroll failed dice and sum
# - :pmf, :PMF : "peut mieux faire", reroll success and sum
# - :e2f, :E2F : "easy to fail", reroll success to confirm
# - :td : "très difficile", only 6 are success
# - :tf : "très facile", only 1 are failures
#
# @param [Array(Symbol)|Array(String)] list
# @param [:pmf|:sc] priority if :sc and :pmf are available, choose only one