87 lines
2.6 KiB
Ruby
87 lines
2.6 KiB
Ruby
module MetalAdventures
|
|
class Dice
|
|
attr_accessor :n, :difficulty, :modifiers, :description, :result, :last_roll
|
|
|
|
# @param [Integer] n is the number of dice to roll
|
|
# @param [Integer] difficulty is the amount of success to get
|
|
# @param [Modifier] modifiers
|
|
def initialize(n:, difficulty: 1, modifiers: Modifiers.new, description: "nodescription")
|
|
@n = n
|
|
@difficulty = difficulty
|
|
@modifiers = modifiers
|
|
@description = description
|
|
end
|
|
|
|
# def add_difficulty!(add = 1)
|
|
# @difficulty += add
|
|
# end
|
|
|
|
# def remove_difficulty!(remove = 1)
|
|
# @difficulty -= remove
|
|
# end
|
|
|
|
# def add_die!(add = 1)
|
|
# @n += add
|
|
# end
|
|
|
|
# def remove_die!(remove = 1)
|
|
# @n -= remove
|
|
# end
|
|
|
|
def to_h
|
|
{ n: @n, difficulty: @difficulty, modifiers: @modifiers.to_h, description: @description }
|
|
end
|
|
|
|
# @return [Integer] the amount of success of a new roll
|
|
def roll
|
|
@modifiers.roll(@n)
|
|
end
|
|
|
|
# Roll the dice and generate a new result.
|
|
# This will overwrite @last_roll and @result.
|
|
# It should be used over {#roll} in most cases.
|
|
#
|
|
# see {#success?} {#last_roll} {#result}
|
|
def roll!
|
|
@last_roll = roll
|
|
@result = @last_roll.count { @modifiers.success?(_1) }
|
|
self
|
|
end
|
|
|
|
# @return [nil|true|false] if the last #roll! was a success or not
|
|
def success?
|
|
if @result
|
|
@result >= @difficulty
|
|
end
|
|
end
|
|
|
|
DEFAULT_PARSER_N = "(?<n>\\d+)"
|
|
DEFAULT_PARSER_D = "(?<difficulty>\\d+)"
|
|
DEFAULT_PARSER_M = "(?<modifiers>(?: +\\w+)*)"
|
|
DEFAULT_PARSER = %r{\A#{DEFAULT_PARSER_N} *(?:/ *#{DEFAULT_PARSER_D})?(?: *#{DEFAULT_PARSER_M})?(?: *:(?<description>.+))?\Z}.freeze
|
|
|
|
# @param [String] prefix must be a string that is matched before the dice to roll
|
|
def self.make_parser(prefix: "!roll ")
|
|
%r{\A#{prefix}#{DEFAULT_PARSER_N} *(?:/ *#{DEFAULT_PARSER_D})?(?: *#{DEFAULT_PARSER_M})?(?: *:(?<description>.+))?\Z}
|
|
end
|
|
|
|
# @param parser must be a regexp with named groups: n, difficulty (optiontal), modifiers.
|
|
# see {.marke_parser} for easy boilerplate
|
|
def self.parse(string, parser: DEFAULT_PARSER, will_raise: false)
|
|
match = string.match(parser)
|
|
|
|
if match.nil?
|
|
raise "Dice: Impossible to parse the string #{string}" if will_raise
|
|
return nil
|
|
end
|
|
|
|
Dice.new(
|
|
description: match["description"].to_s.strip,
|
|
n: match["n"].strip.to_i,
|
|
difficulty: (match["difficulty"] || "1").strip.to_i,
|
|
modifiers: Dice::Modifiers.new(*match["modifiers"].to_s.split(" ").map(&:strip)),
|
|
)
|
|
end
|
|
end
|
|
end
|