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