# # hq-prob-table.rb: generate a probability table for Issaries's HeroQuest # RPG, and interactively assess probabilities between # two Ability Ranks. # CRIT_ROLL = 1 FUMB_ROLL = 20 CRITICAL = 2 SUCCESS = 1 FAILURE = 0 FUMBLE = -1 DEGREES = [ :complete_victory, :major_victory, :minor_victory, :marginal_victory, :tie, :marginal_defeat, :minor_defeat, :major_defeat, :complete_defeat ] def outcome(rank, roll) if roll == CRIT_ROLL then CRITICAL elsif roll == FUMB_ROLL then FUMBLE elsif roll <= rank then SUCCESS else FAILURE end end def degree(mastery, a, r, rolla, rollr) diff = mastery + outcome(a, rolla) - outcome(r, rollr) case diff when 3 then :complete_victory when 2 then :major_victory when 1 then :minor_victory when 0 then if rolla < rollr then return :marginal_victory elsif rolla == rollr then return :tie else return :marginal_defeat end when -1 then :minor_defeat when -2 then :major_defeat when -3 then :complete_defeat else (diff > 0) ? :complete_victory : :complete_defeat end end def counts(mastery, a, r) result = Hash.new(0) 1.upto(20) do |rolla| 1.upto(20) do |rollr| result[degree(mastery, a, r, rolla, rollr)] += 1 end end return result end def total_success(c) return [ :complete_victory, :major_victory, :minor_victory, :marginal_victory,].inject(0.0) { |sum, d| sum + c[d].to_f/4 } end def parse_rank(s) match = /(\d+)([MmWw])?(\d+)?/.match(s) return nil unless match a = match[1].to_i if match[3] then m = match[3].to_i elsif match[2] then m = 1 else m = 0 end return a, m end def rank(a, m) astr = a.to_s astr << 'w' if m > 0 astr << m.to_s if m > 1 return astr end def print_header printf("