module RumorGame
Constants
- MAX_QUESTIONS
- PLUGIN
- STYLE_TITLE
Public Instance Methods
Source
# File lib/rumor_game.rb, line 187 def activate(game) game = game.dup game["stage"] = "facts" game["facts"] = {} { game: game, message: "Rumor Mill started โ both players: !rumor fact <channel fact (prefix fake: if lying)>" } end
Source
# File lib/rumor_game.rb, line 94 def answer_question(game:, user:, answer:) pending = game&.dig("pending_question") return { error: "No question waiting for an answer." } unless pending opponent = AsyncDuel.opponent(game, pending["asker"]) return { error: "That question is not for you." } unless GameStore.same_nick?(user, opponent) game = game.dup questions = (game["questions"] || {}).dup questions[pending["asker"]] ||= [] questions[pending["asker"]] << { "q" => pending["question"], "a" => answer } game["questions"] = questions game.delete("pending_question") asked = (game["questions_asked"] || {}).dup asker = pending["asker"] asked[asker] = asked[asker].to_i + 1 game["questions_asked"] = asked if asked.values.all? { |n| n >= MAX_QUESTIONS } game["stage"] = "guessing" game.delete("asker") else game["asker"] = opponent end { game: game, message: "Answer recorded (#{answer})." } end
Source
# File lib/rumor_game.rb, line 75 def ask_question(game:, user:, question:) return { error: "Not in questioning phase." } unless game && game["stage"] == "questioning" return { error: "It is not your turn to ask." } unless GameStore.same_nick?(user, game["asker"]) q = question.to_s.strip return { error: "Question cannot be empty." } if q.empty? asked = game["questions_asked"] || {} count = asked[GameStore.norm_nick(user)].to_i return { error: "You have used all #{MAX_QUESTIONS} questions." } if count >= MAX_QUESTIONS game = game.dup game["pending_question"] = { "asker" => GameStore.norm_nick(user), "question" => q } { game: game, message: "Question sent to #{AsyncDuel.opponent(game, user)} โ answer with !rumor answer yes|no" } end
Source
# File lib/rumor_game.rb, line 172 def format_header(title) IrcFormat.report_header(tag: "RUMOR", title: title, style: STYLE_TITLE) end
Source
# File lib/rumor_game.rb, line 163 def format_results(game, scores) lines = [format_header("Results")] scores.each do |player, points| lines << "#{player} โ #{points} point#{points == 1 ? '' : 's'}" end lines << IrcFormat.report_footer("rumor mill") lines.join("\n") end
Source
# File lib/rumor_game.rb, line 176 def format_status(game) return format_header("No game") + "\nNo active rumor game in this channel." unless game stage = game["stage"] meta = [game["challenger"], game["target"]].compact.join(" vs ") lines = [format_header("#{meta} ยท #{stage}")] lines << "Questions: #{game['questions_asked']}" if game["questions_asked"] lines << IrcFormat.report_footer(stage) lines.join("\n") end
Source
# File lib/rumor_game.rb, line 19 def parse_command(text) base = AsyncDuel.parse_base(text, usage: usage_message) return base unless base[:action] == :unknown parts = base[:tail] case parts[0].downcase when "fact" return { error: usage_message } if parts.length < 2 { action: :fact, text: parts[1..].join(" ") } when "ask" return { error: usage_message } if parts.length < 2 { action: :ask, question: parts[1..].join(" ") } when "answer" return { error: usage_message } if parts.length < 2 value = parts[1].downcase return { error: "Answer must be yes or no." } unless %w[yes no].include?(value) { action: :answer, answer: value } when "guess" return { error: usage_message } if parts.length < 2 value = parts[1].downcase return { error: "Guess must be true or false." } unless %w[true false].include?(value) { action: :guess, guess: value == "true" } else { error: usage_message } end end
Source
# File lib/rumor_game.rb, line 149 def score_guesses(game) guesses = game["guesses"] || {} facts = game["facts"] || {} scores = {} guesses.each do |player, guess| opponent = AsyncDuel.opponent(game, player) # Players mark facts as true/false claims; guess true = believe it is true claimed_true = !facts[opponent].to_s.strip.downcase.start_with?("fake:") correct = guess == claimed_true scores[player] = correct ? 1 : 0 end scores end
Source
# File lib/rumor_game.rb, line 52 def submit_fact(game:, user:, text:) return { error: "No active rumor game." } unless game && %w[facts questioning guessing].include?(game["stage"]) return { error: "You are not in this game." } unless AsyncDuel.player?(game, user) fact = text.to_s.strip return { error: "Fact cannot be empty." } if fact.empty? game = game.dup facts = (game["facts"] || {}).dup key = GameStore.norm_nick(user) return { error: "You already submitted a fact." } if facts[key] facts[key] = fact game["facts"] = facts if facts.size >= 2 game["stage"] = "questioning" game["questions"] ||= {} game["asker"] = game["challenger"] game["questions_asked"] = { game["challenger"] => 0, game["target"] => 0 } end { game: game, message: "Fact recorded. Waiting for opponent." } end
Source
# File lib/rumor_game.rb, line 123 def submit_guess(game:, user:, guess:) return { error: "Not in guessing phase." } unless game && game["stage"] == "guessing" return { error: "You are not in this game." } unless AsyncDuel.player?(game, user) game = game.dup guesses = (game["guesses"] || {}).dup key = GameStore.norm_nick(user) return { error: "You already guessed." } if guesses[key] opponent = AsyncDuel.opponent(game, user) opponent_fact = game.dig("facts", opponent) return { error: "Opponent fact missing." } unless opponent_fact guesses[key] = guess game["guesses"] = guesses if guesses.size >= 2 results = score_guesses(game) game["stage"] = "done" game["results"] = results { game: game, message: format_results(game, results), done: true } else { game: game, message: "Guess recorded. Waiting for opponent." } end end
Source
# File lib/rumor_game.rb, line 14 def usage_message "Usage: !rumor challenge <nick> | accept | decline | fact <text> | ask <question> | " \ "answer yes|no | guess true|false | status" end