From 0d83e2f726172e53dae584060f49610f2d53f8e7 Mon Sep 17 00:00:00 2001
From: Igor Padoim
Date: Thu, 27 Jun 2024 19:43:31 -0300
Subject: [PATCH] v2.0.0
---
CHANGELOG.md | 10 +-
Gemfile | 1 +
Gemfile.lock | 2 +
classic.rb | 191 ++++++++++++++++++++
main.rb | 205 ++--------------------
v2.rb | 481 +++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 703 insertions(+), 187 deletions(-)
create mode 100644 classic.rb
create mode 100644 v2.rb
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b62020..be2ded6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,9 +6,16 @@ The format is based on [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).
## [Unreleased]
+
+## [2.0.0] - 2024-06-27
### Added
- Random damage generator.
- Generator of Robe of Useful Items's items.
+## Changed
+- Fully refurbished DDB methods, creating:
+ - Attacks generator;
+ - Traits generator; and
+ - Legendary Actions generator.
## [1.1.2] - 2022-05-12
### Changed
@@ -33,7 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Recharge generation; and
- General generation.
-[Unreleased]: https://github.com/Nereare/DDB-Rollable/compare/v1.1.2..HEAD
+[Unreleased]: https://github.com/Nereare/DDB-Rollable/compare/v2.0.0..HEAD
+[2.0.0]: https://github.com/Nereare/DDB-Rollable/compare/v1.1.2...v2.0.0
[1.1.2]: https://github.com/Nereare/DDB-Rollable/compare/v1.1.0...v1.1.2
[1.1.0]: https://github.com/Nereare/DDB-Rollable/compare/v1.0.0...v1.1.0
[1.0.0]: https://github.com/Nereare/DDB-Rollable/releases/tag/v1.0.0
diff --git a/Gemfile b/Gemfile
index 2d2f2de..7cd1ffb 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,5 +2,6 @@
source "https://rubygems.org"
+gem "humanize"
gem "clipboard"
gem "ffi", platforms: %i[mingw x64_mingw mswin mri]
diff --git a/Gemfile.lock b/Gemfile.lock
index 488a9d6..6a17940 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -3,6 +3,7 @@ GEM
specs:
clipboard (1.3.6)
ffi (1.17.0-x64-mingw-ucrt)
+ humanize (3.1.0)
PLATFORMS
x64-mingw-ucrt
@@ -10,6 +11,7 @@ PLATFORMS
DEPENDENCIES
clipboard
ffi
+ humanize
BUNDLED WITH
2.3.16
diff --git a/classic.rb b/classic.rb
new file mode 100644
index 0000000..0d263a1
--- /dev/null
+++ b/classic.rb
@@ -0,0 +1,191 @@
+# Classic methods for generating DDB rollables
+def classic_ddb
+ # Final output format, with its two major fields:
+ final = "[rollable]OUTPUT;JSON[/rollable]"
+ # The JSON part of the final output, with its two mandatory parameters:
+ json = "{\"diceNotation\":\"DICE\",\"rollType\":\"TYPE\"OTHER}"
+ # An array to contain any other parameter of the JSON part:
+ other = []
+ # The rollAction parameter:
+ action = "\"rollAction\":\"ACTION_NAME\""
+ # The rollDamageType parameter:
+ damage = "\"rollDamageType\":\"DAMAGE_TYPE\""
+
+ # The supported rollType's:
+ roll_types = [
+ ["roll", "Used for a generic dice roll"],
+ ["to hit", "Used for attack rolls"],
+ ["damage", "Used for damage rolls. Should include rollDamageType when using this"],
+ ["heal", "Used for healing"],
+ ["spell", "Can be used to differentiate a spell attack from a regular attack roll"],
+ ["save", "Used for saving throws"],
+ ["check", "Used for profiency checks (skills)"],
+ ["recharge", "Used for recharging abilities"]
+ ]
+ # The supported rollDamageType's:
+ damage_types = [
+ "Acid",
+ "Bludgeoning",
+ "Cold",
+ "Fire",
+ "Force",
+ "Lightning",
+ "Necrotic",
+ "Piercing",
+ "Poison",
+ "Psychic",
+ "Radiant",
+ "Slashing",
+ "Thunder"
+ ]
+
+ puts "What do you wish to generate? (Choose from the below)"
+ puts " 1. To hit;"
+ puts " 2. Damage (default);"
+ puts " 3. Heal;"
+ puts " 4. Recharge; or"
+ puts " 5. General roll."
+
+ case gets.to_i
+ when 1
+ puts "What is the attack bonus?"
+ ab = gets.to_i
+ sign = (ab < 0) ? "-" : "+"
+
+ puts "Is there a name for this attack? (Leave blank if not)"
+ name = gets.strip
+ if name
+ action.sub!(/ACTION_NAME/, name)
+ json.sub!(/OTHER/, "," + action)
+ end
+
+ puts "Is the attack a magical one? (y/N)"
+ if gets.strip.downcase == "y"
+ json.sub!(/TYPE/, "spell")
+ else
+ json.sub!(/TYPE/, "to hit")
+ end
+
+ json.sub!(/DICE/, "1d20" + sign + ab.abs.to_s)
+
+ final.sub!(/OUTPUT/, sign + ab.abs.to_s)
+ .sub!(/JSON/, json)
+ when 3
+ puts "What is the healing amount? (Use the format NdN+/-N, where N is a natural number)"
+ heal = gets.downcase.gsub!(/\s/, "")
+
+ json.sub!(/TYPE/, "heal")
+
+ puts "Is there a name for this action? (Leave blank if not)"
+ name = gets.strip
+ if name
+ action.sub!(/ACTION_NAME/, name)
+ json.sub!(/OTHER/, "," + action)
+ end
+
+ json.sub!(/DICE/, heal)
+
+ final.sub!(/OUTPUT/, heal)
+ .sub!(/JSON/, json)
+ when 4
+ puts "The recharge uses 1d6? (Y/n)"
+ if gets.strip.downcase == "n"
+ puts "What is roll for this recharging? (Use the format NdN+/-N, where N is a natural number)"
+ roll = gets.downcase.gsub!(/\s/, "")
+ else
+ roll = "1d6"
+ end
+
+ puts "The recharging occurs from..."
+ min = gets.to_i
+ puts "...to..."
+ max = gets.to_i
+
+ text = "Recharge #{min}-#{max}"
+
+ json.sub!(/TYPE/, "recharge")
+
+ puts "Is there a name for the action to be recharged? (Leave blank if not)"
+ name = gets.strip
+ if name
+ action.sub!(/ACTION_NAME/, name)
+ json.sub!(/OTHER/, "," + action)
+ end
+
+ json.sub!(/DICE/, roll)
+
+ final.sub!(/OUTPUT/, text)
+ .sub!(/JSON/, json)
+ when 5
+ puts "What is the dice roll? (Use the format NdN+/-N, where N is a natural number)"
+ roll = gets.downcase.gsub!(/\s/, "")
+ json.sub!(/DICE/, roll)
+
+ puts "Is the text to be shown the dice roll above? (Y/n)"
+ if gets.strip.downcase == "n"
+ puts "What is the text to be shown?"
+ final.sub!(/OUTPUT/, gets.strip)
+ else
+ final.sub!(/OUTPUT/, roll)
+ end
+
+ puts "What is the type of roll? (Choose the number)"
+ roll_types.each_with_index do |v, i|
+ puts " #{i.to_s.rjust(2,"0")}. #{v[0]} (#{v[1]})"
+ end
+ index = gets.to_i
+ json.sub!(/TYPE/, roll_types[index][0])
+
+ puts "Is there a name for this roll? (Leave blank if not)"
+ name = gets.strip
+ if name
+ action.sub!(/ACTION_NAME/, name)
+ other.push action
+ end
+
+ notice = (index == 2) ? "A damage type is MADATORY when rollType is \"damage\"." : "Optional, and may not be even shown."
+ puts "Is the a damage type associated? #{notice} (Y/n)"
+ if gets.strip.downcase != "n"
+ puts "What is the type of damage dealt by this attack? (Choose the number)"
+ damage_types.each_with_index do |v, i|
+ puts " #{i.to_s.rjust(2,"0")}. #{v}"
+ end
+ index = gets.to_i
+ damage.sub!(/DAMAGE_TYPE/, damage_types[index])
+ other.push damage
+ end
+
+ json.sub!(/OTHER/, "," + other.join(","))
+ final.sub!(/JSON/, json)
+ else
+ puts "What is the damage? (Use the format NdN+/-N, where N is a natural number)"
+ dmg = gets.downcase.gsub!(/\s/, "")
+
+ json.sub!(/TYPE/, "damage")
+
+ puts "Is there a name for this attack? (Leave blank if not)"
+ name = gets.strip
+ if name
+ action.sub!(/ACTION_NAME/, name)
+ other.push action
+ end
+
+ puts "What is the type of damage dealt by this attack? (Choose the number)"
+ damage_types.each_with_index do |v, i|
+ puts " #{i.to_s.rjust(2,"0")}. #{v}"
+ end
+ index = gets.to_i
+ damage.sub!(/DAMAGE_TYPE/, damage_types[index])
+ other.push damage
+
+ json.sub!(/DICE/, dmg)
+ json.sub!(/OTHER/, "," + other.join(","))
+
+ final.sub!(/OUTPUT/, dmg)
+ final.sub!(/JSON/, json)
+ end
+
+ puts "Final output: " + final
+ Clipboard.copy(final)
+ puts "Copied to clipboard!"
+end
\ No newline at end of file
diff --git a/main.rb b/main.rb
index bc43edd..be12ee5 100644
--- a/main.rb
+++ b/main.rb
@@ -1,197 +1,30 @@
require "Clipboard"
-
-# Final output format, with its two major fields:
-final = "[rollable]OUTPUT;JSON[/rollable]"
-# The part of the final output that the user will read - the contents of the
-# button:
-output = ""
-# The JSON part of the final output, with its two mandatory parameters:
-json = "{\"diceNotation\":\"DICE\",\"rollType\":\"TYPE\"OTHER}"
-# An array to contain any other parameter of the JSON part:
-other = []
-# The rollAction parameter:
-action = "\"rollAction\":\"ACTION_NAME\""
-# The rollDamageType parameter:
-damage = "\"rollDamageType\":\"DAMAGE_TYPE\""
-
-# The supported rollType's:
-roll_types = [
- ["roll", "Used for a generic dice roll"],
- ["to hit", "Used for attack rolls"],
- ["damage", "Used for damage rolls. Should include rollDamageType when using this"],
- ["heal", "Used for healing"],
- ["spell", "Can be used to differentiate a spell attack from a regular attack roll"],
- ["save", "Used for saving throws"],
- ["check", "Used for profiency checks (skills)"],
- ["recharge", "Used for recharging abilities"]
-]
-# The supported rollDamageType's:
-damage_types = [
- "Acid",
- "Bludgeoning",
- "Cold",
- "Fire",
- "Force",
- "Lightning",
- "Necrotic",
- "Piercing",
- "Poison",
- "Psychic",
- "Radiant",
- "Slashing",
- "Thunder"
-]
+require "humanize"
+require_relative "classic.rb"
+require_relative "v2.rb"
puts "#######################################"
puts "# D&D Beyond Rollable Generator #"
+puts "# v2 #"
puts "#######################################"
-puts "What do you wish to generate? (Choose from the below)"
-puts " 1. To hit;"
-puts " 2. Damage (default);"
-puts " 3. Heal;"
-puts " 4. Recharge; or"
-puts " 5. General roll."
-
-case gets.to_i
-when 1
- puts "What is the attack bonus?"
- ab = gets.to_i
- sign = (ab < 0) ? "-" : "+"
-
- puts "Is there a name for this attack? (Leave blank if not)"
- name = gets.strip
- if name
- action.sub!(/ACTION_NAME/, name)
- json.sub!(/OTHER/, "," + action)
- end
+puts "Select generator:"
+puts "1. Attacks (default);"
+puts "2. Traits;"
+puts "3. Legendary actions; or"
+puts "4. Classic options."
+puts ""
- puts "Is the attack a magical one? (y/N)"
- if gets.strip.downcase == "y"
- json.sub!(/TYPE/, "spell")
- else
- json.sub!(/TYPE/, "to hit")
- end
+option = gets.to_i
+puts ""
- json.sub!(/DICE/, "1d20" + sign + ab.abs.to_s)
-
- final.sub!(/OUTPUT/, sign + ab.abs.to_s)
- .sub!(/JSON/, json)
+case option
+when 2
+ attributes()
when 3
- puts "What is the healing amount? (Use the format NdN+/-N, where N is a natural number)"
- heal = gets.downcase.gsub!(/\s/, "")
-
- json.sub!(/TYPE/, "heal")
-
- puts "Is there a name for this action? (Leave blank if not)"
- name = gets.strip
- if name
- action.sub!(/ACTION_NAME/, name)
- json.sub!(/OTHER/, "," + action)
- end
-
- json.sub!(/DICE/, heal)
-
- final.sub!(/OUTPUT/, heal)
- .sub!(/JSON/, json)
+ legendary_actions()
when 4
- puts "The recharge uses 1d6? (Y/n)"
- if gets.strip.downcase == "n"
- puts "What is roll for this recharging? (Use the format NdN+/-N, where N is a natural number)"
- roll = gets.downcase.gsub!(/\s/, "")
- else
- roll = "1d6"
- end
-
- puts "The recharging occurs from..."
- min = gets.to_i
- puts "...to..."
- max = gets.to_i
-
- text = "Recharge #{min}-#{max}"
-
- json.sub!(/TYPE/, "recharge")
-
- puts "Is there a name for the action to be recharged? (Leave blank if not)"
- name = gets.strip
- if name
- action.sub!(/ACTION_NAME/, name)
- json.sub!(/OTHER/, "," + action)
- end
-
- json.sub!(/DICE/, roll)
-
- final.sub!(/OUTPUT/, text)
- .sub!(/JSON/, json)
-when 5
- puts "What is the dice roll? (Use the format NdN+/-N, where N is a natural number)"
- roll = gets.downcase.gsub!(/\s/, "")
- json.sub!(/DICE/, roll)
-
- puts "Is the text to be shown the dice roll above? (Y/n)"
- if gets.strip.downcase == "n"
- puts "What is the text to be shown?"
- final.sub!(/OUTPUT/, gets.strip)
- else
- final.sub!(/OUTPUT/, roll)
- end
-
- puts "What is the type of roll? (Choose the number)"
- roll_types.each_with_index do |v, i|
- puts " #{i.to_s.rjust(2,"0")}. #{v[0]} (#{v[1]})"
- end
- index = gets.to_i
- json.sub!(/TYPE/, roll_types[index][0])
-
- puts "Is there a name for this roll? (Leave blank if not)"
- name = gets.strip
- if name
- action.sub!(/ACTION_NAME/, name)
- other.push action
- end
-
- notice = (index == 2) ? "A damage type is MADATORY when rollType is \"damage\"." : "Optional, and may not be even shown."
- puts "Is the a damage type associated? #{notice} (Y/n)"
- if gets.strip.downcase != "n"
- puts "What is the type of damage dealt by this attack? (Choose the number)"
- damage_types.each_with_index do |v, i|
- puts " #{i.to_s.rjust(2,"0")}. #{v}"
- end
- index = gets.to_i
- damage.sub!(/DAMAGE_TYPE/, damage_types[index])
- other.push damage
- end
-
- json.sub!(/OTHER/, "," + other.join(","))
- final.sub!(/JSON/, json)
+ classic_ddb()
else
- puts "What is the damage? (Use the format NdN+/-N, where N is a natural number)"
- dmg = gets.downcase.gsub!(/\s/, "")
-
- json.sub!(/TYPE/, "damage")
-
- puts "Is there a name for this attack? (Leave blank if not)"
- name = gets.strip
- if name
- action.sub!(/ACTION_NAME/, name)
- other.push action
- end
-
- puts "What is the type of damage dealt by this attack? (Choose the number)"
- damage_types.each_with_index do |v, i|
- puts " #{i.to_s.rjust(2,"0")}. #{v}"
- end
- index = gets.to_i
- damage.sub!(/DAMAGE_TYPE/, damage_types[index])
- other.push damage
-
- json.sub!(/DICE/, dmg)
- json.sub!(/OTHER/, "," + other.join(","))
-
- final.sub!(/OUTPUT/, dmg)
- final.sub!(/JSON/, json)
-end
-
-puts "Final output: " + final
-Clipboard.copy(final)
-puts "Copied to clipboard!"
+ attacks()
+end
\ No newline at end of file
diff --git a/v2.rb b/v2.rb
new file mode 100644
index 0000000..489abfa
--- /dev/null
+++ b/v2.rb
@@ -0,0 +1,481 @@
+# Final output format, with its two major fields:
+FINAL = "[rollable]OUTPUT;JSON[/rollable]"
+# The JSON part of the final output, with its two mandatory parameters:
+JSON = "{\"diceNotation\":\"DICE\",\"rollType\":\"TYPE\"OTHER}"
+# An array to contain any other parameter of the JSON part:
+OTHER = []
+# The rollAction parameter:
+ACTION = "\"rollAction\":\"ACTION_NAME\""
+# The rollDamageType parameter:
+DAMAGE = "\"rollDamageType\":\"DAMAGE_TYPE\""
+# The supported rollDamageType's:
+DAMAGE_TYPES = [
+ "Acid",
+ "Bludgeoning",
+ "Cold",
+ "Fire",
+ "Force",
+ "Lightning",
+ "Necrotic",
+ "Piercing",
+ "Poison",
+ "Psychic",
+ "Radiant",
+ "Slashing",
+ "Thunder"
+]
+
+# Option #1/Default - Attacks
+def attacks
+ attacks = []
+ foo = ""
+
+ # Has multiattack?
+ puts "Does the creature have the \"Multiattack\" attack? (y/N)"
+ if gets.strip.downcase == "y"
+ # Open paragraph and include multiattack name
+ attack = "Multiattack.. "
+ # Get multiattack text
+ puts "Text for the multiattack:"
+ attack << gets_clipboard()
+ # Close paragraph
+ attack << "
"
+
+ # Show final multiattack
+ puts "Final attack:"
+ puts attack
+ puts ""
+
+ # Inject into array
+ attacks.push(attack)
+ # Announce next step
+ puts "Now, to the actual attacks..."
+ puts ""
+ end
+
+ # Loop to get all attacks
+ while foo != "n"
+ # Inject into array
+ attacks.push(get_attack())
+ # Check to add another
+ puts "Add another? (Y/n)"
+ foo = gets.strip.downcase
+ puts ""
+ end
+
+ # Once all attacks added, check how many
+ if attacks.length > 0
+ # Show total number
+ puts "Total of " + attacks.length.to_s + " attack(s)."
+ # Compile final string
+ final = attacks.join("\n")
+ # Copy final string to clipboard
+ Clipboard.copy(final)
+ puts "Copied to clipboard!"
+ end
+end
+# Sub-method: create attack
+def get_attack
+ attack = ""
+
+ # Show attack options
+ puts "Select type of attack:"
+ puts "1. Basic attack (default);"
+ puts "2. Breath weapon; or"
+ puts "3. Custom."
+
+ case gets.to_i
+ when 2
+ action = ACTION.dup
+ json = JSON.dup
+ final = FINAL.dup
+
+ # Get breath weapon name
+ puts "Breath attack name:"
+ atk_name = gets.strip
+ attack << "" + atk_name + " ("
+ action.sub!(/ACTION_NAME/, atk_name)
+ json.sub!(/OTHER/, "," + action)
+
+ # Get recharge data
+ puts "The recharge uses 1d6? (Y/n)"
+ if gets.strip.downcase == "n"
+ puts "What is roll for this recharging? (Use the format NdN+/-N, where N is a natural number)"
+ roll = gets.downcase.gsub!(/\s/, "")
+ else
+ roll = "1d6"
+ end
+
+ puts "The recharging occurs from..."
+ min = gets.to_i
+ puts "...to..."
+ max = gets.to_i
+
+ # Set rollable text
+ recharge_text = "Recharge #{min}-#{max}"
+ # Set rollable type
+ json.sub!(/TYPE/, "recharge")
+ # Set rollable dice
+ json.sub!(/DICE/, roll)
+ # Set final rollable text
+ final.sub!(/OUTPUT/, recharge_text)
+ final.sub!(/JSON/, json)
+
+ # Add rollable to name
+ attack << final + "). "
+
+ # Get breath attack text
+ puts "Breath attack text:"
+ atk_text = gets_clipboard()
+ # Check for dice rolls
+ if /\d+d\d+([-\+]\d+)?/.match?(atk_text)
+ puts "Your text contains dice rolls, process them? (Y/n)"
+ if gets.strip.downcase != "n"
+ atk_text = process_dmg_rolls(atk_text, atk_name)
+ end
+ end
+ attack << atk_text
+ # Close paragraph
+ attack << "
"
+ when 3
+ # Get custom attack name
+ puts "Attack name:"
+ atk_name = gets.strip
+ attack << "" + atk_name + ". "
+ # Get custom attack text
+ puts "Attack text:"
+ atk_text = gets_clipboard()
+ # Check for dice rolls
+ if /\d+d\d+([-\+]\d+)?/.match?(atk_text)
+ puts "Your text contains dice rolls, process them? (Y/n)"
+ if gets.strip.downcase != "n"
+ atk_text = process_dmg_rolls(atk_text, atk_name)
+ end
+ end
+ attack << atk_text
+ # Close paragraph
+ attack << "
"
+ else
+ # Get attack name
+ puts "Attack name:"
+ atk_name = gets.strip
+ attack << "" + atk_name + ". "
+
+ # Get melee Vs. ranged
+ puts "Attack is melee (1, default) or ranged (2)?"
+ atk_range = gets.to_i == 2 ? "Ranged" : "Melee"
+ # Get weapon Vs. spell
+ puts "Attack if physical (1, default) or magic (2)?"
+ atk_type = gets.to_i == 2 ? "Spell" : "Weapon"
+ # Compile attack type
+ attack << "" + atk_range + " " + atk_type + " Attack "
+
+ # Get attack bonus
+ puts "Whats the attack bonus?"
+ atk_bonus = gets.to_i
+ # Append attack bonus rollable
+ attack << get_attack_bonus(atk_bonus, atk_type, atk_name)
+ attack << " to hit, "
+
+ # Get range/reach
+ if atk_range == "Melee"
+ puts "What's the reach (ft.) of the attack?"
+ atk_reach = gets.to_i
+ attack << "reach " + atk_reach.to_s + " ft."
+ else
+ atk_range = []
+ puts "What's the short range (ft.) of the attack?"
+ atk_range.push(gets.to_i)
+ puts "And the long range (ft.)?"
+ atk_range.push(gets.to_i)
+ attack << "range " + atk_range[0].to_s + "/" + atk_range[1].to_s + " ft."
+ end
+ attack << ", "
+
+ # Get number of targets
+ puts "How many targets? (Defaul = 1)"
+ no = gets.strip
+ atk_targets = no.empty? ? 1 : no.to_i
+ if atk_targets <= 10
+ attack << atk_targets.humanize + (atk_targets > 1 ? " targets" : " target")
+ else
+ attack << atk_targets.to_s + " targets"
+ end
+ attack << ". "
+
+ # Get damage
+ puts "What is the damage? (Use the format NdN+/-N, where N is a natural number)"
+ atk_dmg = gets.downcase.gsub!(/\s/, "")
+ puts "What is the damage's type?"
+ DAMAGE_TYPES.each_with_index do |v, i|
+ puts " #{i.to_s.rjust(2,"0")}. #{v}"
+ end
+ index = gets.to_i
+ atk_dmg_type = DAMAGE_TYPES[index].downcase
+ attack << "Hit: " + get_mean_damage(atk_dmg).to_s + " (" + get_damage_rollable(atk_dmg, atk_dmg_type, atk_name) + ") " + atk_dmg_type + " damage"
+
+ # Check secondary damage
+ puts "Is there a secondary damage dealt? (y/N)"
+ if gets.strip.downcase == "y"
+ attack << " plus "
+ # Get secondary damage
+ puts "What is the secondary damage? (Use the format NdN+/-N, where N is a natural number)"
+ atk2_dmg = gets.downcase.gsub!(/\s/, "")
+ puts "What is the secondary damage's type?"
+ DAMAGE_TYPES.each_with_index do |v, i|
+ puts " #{i.to_s.rjust(2,"0")}. #{v}"
+ end
+ index2 = gets.to_i
+ atk2_dmg_type = DAMAGE_TYPES[index2].downcase
+ attack << get_mean_damage(atk2_dmg).to_s + " (" + get_damage_rollable(atk2_dmg, atk2_dmg_type, atk_name) + ") " + atk2_dmg_type + " damage"
+ end
+
+ # Close paragraph
+ attack << "."
+ end
+
+ # Show final attack
+ puts "Final attack:"
+ puts attack
+ puts ""
+
+ # Return attack
+ return attack
+end
+# Sub-method - Get damage rollable
+def get_damage_rollable(dice_notation, damage_type, name)
+ action = ACTION.dup
+ damage = DAMAGE.dup
+ other = OTHER.dup
+ json = JSON.dup
+ final = FINAL.dup
+
+ # Set rollable type
+ json.sub!(/TYPE/, "damage")
+ # Set rollable name
+ action.sub!(/ACTION_NAME/, name)
+ other.push action
+ # Set rollable damage type
+ damage.sub!(/DAMAGE_TYPE/, damage_type)
+ other.push damage
+ # Set rollable damage
+ json.sub!(/DICE/, dice_notation)
+ # Append misc rollable data
+ json.sub!(/OTHER/, "," + other.join(","))
+ # Compile rollable
+ final.sub!(/OUTPUT/, dice_notation)
+ final.sub!(/JSON/, json)
+
+ return final
+end
+# Sub-method - Get mean damage
+def get_mean_damage(dice_notation)
+ dice_count, dice_type, dmg_bonus = dice_notation.match(/(\d+)d(\d+)([-\+]\d+)?/).captures
+ dice_count = dice_count.to_f
+ dice_type = dice_type.to_f
+ dmg_bonus = dmg_bonus.to_f
+
+ dmg = (1.0 + dice_type) / 2.0
+ dmg = dmg * dice_count
+ dmg = dmg + dmg_bonus
+
+ return dmg.to_i
+end
+# Sub-method - Process damage bonus
+def get_attack_bonus(bonus, type, name)
+ action = ACTION.dup
+ json = JSON.dup
+ final = FINAL.dup
+
+ # Set rollable name
+ action.sub!(/ACTION_NAME/, name)
+ json.sub!(/OTHER/, "," + action)
+
+ # Set rollable type
+ if type.strip.downcase == "spell"
+ json.sub!(/TYPE/, "spell")
+ else
+ json.sub!(/TYPE/, "to hit")
+ end
+
+ # Set rollable roll
+ sign = (bonus < 0) ? "-" : "+"
+ json.sub!(/DICE/, "1d20" + sign + bonus.abs.to_s)
+
+ # Compile rollable
+ final.sub!(/OUTPUT/, sign + bonus.abs.to_s)
+ final.sub!(/JSON/, json)
+ return final
+end
+# Sub-method - Process damage rolls
+def process_dmg_rolls(txt, name)
+ final = FINAL.dup
+ json = JSON.dup
+ action = ACTION.dup
+
+ final.gsub!(/OUTPUT/, "DICE")
+ action.gsub!(/ACTION_NAME/, name)
+ json.gsub!(/TYPE/, "damage")
+ json.gsub!(/OTHER/, "," + action)
+ final.gsub!(/JSON/, json)
+ txt.gsub!(/(\d+d\d+( ?[-\+] ?\d+)?)/) {|s| s = final.gsub(/DICE/, s.downcase.gsub!(/\s/, "")) }
+
+ return txt
+end
+
+# Option #2 - Traits
+def attributes
+ traits = []
+ foo = ""
+
+ # Loop to get several traits
+ while foo != "n"
+ # Open paragraph tag
+ trait = ""
+ # Get trait name (surrounded by bold tags)
+ puts "Name of the trait:"
+ name = gets.strip
+ trait << "" + name + ". "
+ puts ""
+ # Get trait text
+ puts "Text of the trait:"
+ text = gets_clipboard()
+ # Check for dice rolls
+ if /\d+d\d+([-\+]\d+)?/.match?(text)
+ puts "Your text contains dice rolls, process them? (Y/n)"
+ if gets.strip.downcase != "n"
+ text = process_dmg_rolls(text, name)
+ end
+ end
+ trait << text
+ puts ""
+ # Close paragraph
+ trait << "
"
+
+ # Show final trait
+ puts "Final trait:"
+ puts trait
+ puts ""
+
+ # Inject into array
+ traits.push(trait)
+ # Check to add another
+ puts "Add another? (Y/n)"
+ foo = gets.strip.downcase
+ puts ""
+ end
+
+ # Once all traits added, check how many
+ if traits.length > 0
+ # Show total number
+ puts "Total of " + traits.length.to_s + " trait(s)."
+ # Compile final string
+ final = traits.join("\n")
+ # Copy final string to clipboard
+ Clipboard.copy(final)
+ puts "Copied to clipboard!"
+ end
+end
+
+# Option #3 - Legendary Actions
+def legendary_actions
+ actions = []
+ intro = "The NAME can take COUNT legendary actions, choosing from the options below. Only one legendary action can be used at a time and only at the end of another creature's turn. The NAME regains spent legendary actions at the start of PRONOUN turn."
+ foo = ""
+
+ # Get intro text
+ puts "What name to use in the Legendary Actions intro text?"
+ name = gets.strip
+ puts "What pronoun to use for '#{name}'?"
+ puts " 1. She/Her"
+ puts " 2. He/Him"
+ puts " 3. They/Them"
+ puts " 4. It/Its (default)"
+ index = gets.to_i
+ case index
+ when 1
+ pronoun = "her"
+ when 2
+ pronoun = "his"
+ when 3
+ pronoun = "their"
+ else
+ pronoun = "its"
+ end
+ puts "How many actions can '#{name}' take? (Default = 3)"
+ count = gets.strip
+ count = count.empty? ? 3 : count.to_i
+ # Compile intro
+ intro.gsub!(/NAME/, name)
+ intro.gsub!(/PRONOUN/, pronoun)
+ intro.gsub!(/COUNT/, count.to_s)
+ actions.push("" + intro + "
")
+
+ # Loop to get several actions
+ while foo != "n"
+ # Open paragraph tag
+ action = ""
+ # Get leg. action name (surrounded by bold tags)
+ puts "Name of the legendary action:"
+ act_name = gets.strip
+ action << "" + act_name + ". "
+ puts ""
+ # Get leg. action text
+ puts "Text of the legendary action:"
+ text = gets_clipboard()
+ # Check for dice rolls
+ if /\d+d\d+([-\+]\d+)?/.match?(text)
+ puts "Your text contains dice rolls, process them? (Y/n)"
+ if gets.strip.downcase != "n"
+ text = process_dmg_rolls(text, act_name)
+ end
+ end
+ action << text
+ # Close paragraph
+ action << "
"
+
+ # Show final leg. action
+ puts "Final legendary action:"
+ puts action
+ puts ""
+
+ # Inject into array
+ actions.push(action)
+ # Check to add another
+ puts "Add another? (Y/n)"
+ foo = gets.strip.downcase
+ puts ""
+ end
+
+ # Once all leg. actions added, check how many
+ if actions.length > 1
+ # Show total number
+ puts "Total of " + (actions.length - 1).to_s + " action(s), plus intro."
+ # Compile final string
+ final = actions.join("\n")
+ # Copy final string to clipboard
+ Clipboard.copy(final)
+ puts "Copied to clipboard!"
+ end
+end
+
+# Get contents from user, first checking for
+# clipboard contents.
+def gets_clipboard
+ # Get contents of the Clipboard
+ ctrl_v = Clipboard.paste.encode('UTF-8').to_s.strip
+ # Check if empty
+ if !ctrl_v.empty?
+ # If NOT empty, check if use it
+ puts "Use copied text? (Y/n)"
+ if gets.strip.downcase != "n"
+ return ctrl_v
+ else
+ puts "Enter text:"
+ return gets.strip
+ end
+ else
+ # If EMPTY, get text
+ return gets.strip
+ end
+end
\ No newline at end of file