X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=data%2Frbot%2Fplugins%2Fgames%2Funo.rb;h=df6a1eee1bf040b6f6f7c921ae298c05a56d07c1;hb=6cf365c49ce5fbe24c0a4ff0663550390b501fea;hp=5b2593ee746212db524e62ca5b5a33cbf4171cb2;hpb=ec5745fa7abd47b8ca12bd783b0759079dff9917;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/data/rbot/plugins/games/uno.rb b/data/rbot/plugins/games/uno.rb index 5b2593ee..df6a1eee 100644 --- a/data/rbot/plugins/games/uno.rb +++ b/data/rbot/plugins/games/uno.rb @@ -108,7 +108,7 @@ class UnoGame @color = 'Wild' raise if value and not value == '+4' if value - @value = value.dup + @value = value.dup @shortform = 'w'+value else @value = nil @@ -211,6 +211,13 @@ class UnoGame @bot.notice player.user, msg, opts end + def notify_error(player, msg, opts={}) + announce _("you can't do that, %{p}") % { + :p => player.user + } + notify player, msg, opts + end + def make_base_stock @base_stock = COLORS.inject([]) do |list, clr| VALUES.each do |n| @@ -237,6 +244,7 @@ class UnoGame end def start_game + @join_timer = nil debug "Starting game" @players.shuffle! show_order @@ -323,13 +331,13 @@ class UnoGame else @special = false end - @must_play = nil end def next_turn(opts={}) + @must_play = nil @players << @players.shift @player_has_picked = false - show_turn + show_turn unless opts[:silent] end def can_play(card) @@ -374,7 +382,7 @@ class UnoGame def play_card(source, cards) debug "Playing card #{cards}" p = get_player(source) - shorts = cards.gsub(/\s+/,'').match(/^(?:([rbgy]\+?\d){1,2}|([rbgy][rs])|(w(?:\+4)?)([rbgy])?)$/).to_a + shorts = cards.gsub(/\s+/,'').match(/^(?:([rbgy]\+?\d)\1?|([rbgy][rs])|(w(?:\+4)?)([rbgy])?)$/).to_a debug shorts.inspect if shorts.empty? announce _("what cards were that again?") @@ -390,14 +398,28 @@ class UnoGame toplay = (full == short) ? 1 : 2 end debug [full, short, jolly, jcolor, toplay].inspect - # r7r7 -> r7r7, r7, nil, nil - # r7 -> r7, r7, nil, nil - # w -> w, nil, w, nil - # wg -> wg, nil, w, g + # r7r7 -> r7r7, r7, nil, nil, 2 + # r7 -> r7, r7, nil, nil, 1 + # w -> w, nil, w, nil, 1 + # wg -> wg, nil, w, g, 1 + + # if @color is nil, the player just played a wild without specifying + # a color. (s)he should now use "co ", but we allow him to + # replay the wild _and_ specify the color, without actually replaying + # the card (which would otherwise happen if the player has another wild) + if @color.nil? + if jcolor + choose_color(p.user, jcolor) + else + announce _("you already played your card, ") + _("%{p}, choose a color with: co r|b|g|y") % { :p => p } + end + return + end + if cards = p.has_card?(short) debug cards unless can_play(cards.first) - announce _("you can't play that card") + notify_error p, _("you can't play that card") return end if cards.length >= toplay @@ -411,7 +433,7 @@ class UnoGame # only be possible if the first W+4 was illegal, so it wouldn't # apply for a W+4 played on a +2 anyway. # - if @picker == 0 and Wild === cards.first and cards.first.value + if @picker == 0 and Wild === cards.first and cards.first.value # save the previous discard in case of challenge @last_discard = @discard.dup # save the color too, in case it was a Wild @@ -451,10 +473,10 @@ class UnoGame announce _("%{p}, choose a color with: co r|b|g|y") % { :p => p } end else - announce _("you don't have two cards of that kind") + notify_error p, _("you don't have two cards of that kind") end else - announce _("you don't have that card") + notify_error p, _("you don't have that card") end end @@ -476,6 +498,7 @@ class UnoGame lp.cards.each do |c| if c.color == @last_color and not c.special? legal = false + break end end if legal @@ -492,7 +515,7 @@ class UnoGame announce _("%{lp}'s move was %{b}not%{b} legal, %{lp} must pick %{b}%{n}%{b} cards and play again!") % { :cp => cp, :lp => lp, :b => Bold, :n => @picker } - lp.cards << @discard # put the W+4 back in place + played = @discard # store the misplayed W+4 # reset the discard @color = @last_color.dup @@ -504,7 +527,10 @@ class UnoGame # force the player to play the current cards @must_play = lp.cards.dup + # but not the same (type of) card he misplayed, though + @must_play.delete(played) + lp.cards << played # reinstate the W+4 in the list of player cards # give him the penalty cards deal(lp, @picker) @picker = 0 @@ -522,6 +548,10 @@ class UnoGame } deal(p, @picker) @picker = 0 + # make sure that if this is the "pick and pass" after a W+4, + # then the following player cannot do a challenge: + @last_discard = nil + @last_color = nil else if @player_has_picked announce _("%{p} passes turn") % { :p => p } @@ -578,6 +608,12 @@ class UnoGame end def show_turn(opts={}) + if @players.empty? + announce _("nobody is playing %{uno} yet!") % { + :uno => UNO + } + return false + end cards = true cards = opts[:cards] if opts.key?(:cards) player = @players.first @@ -662,6 +698,13 @@ class UnoGame return end end + if @last_discard + announce _("you can't join now, %{p}, a %{card} was just played, wait until next turn") % { + :card => @discard, + :p => user + } + return + end cards = 7 if @start_time cards = (@players.inject(0) do |s, pl| @@ -699,11 +742,18 @@ class UnoGame } case @players.length when 2 + if @join_timer + @bot.timer.remove(@join_timer) + announce _("game start countdown stopped") + @join_timer = nil + end if p == @players.first - next_turn + next_turn :silent => @start_time.nil? + end + if @start_time + end_game + return end - end_game - return when 1 end_game(true) return @@ -719,11 +769,17 @@ class UnoGame def replace_player(old, new) # The new user user = channel.get_user(new) - if p = get_player(user) + if not user + announce _("there is no '%{nick}' here") % { + :nick => new + } + return false + end + if pl = get_player(user) announce _("%{p} is already playing %{uno} here") % { - :p => p, :uno => UNO + :p => pl, :uno => UNO } - return + return false end # We scan the player list of the player with the old nick, instead # of using get_player, in case of IRC drops etc @@ -733,16 +789,22 @@ class UnoGame announce _("%{p} takes %{b}%{old}%{b}'s place at %{uno}") % { :p => p, :b => Bold, :old => old, :uno => UNO } - return + return true end end announce _("%{b}%{old}%{b} isn't playing %{uno} here") % { :uno => UNO, :b => Bold, :old => old } + return false end def end_game(halted = false) runtime = @start_time ? Time.now - @start_time : 0 + if @join_timer + @bot.timer.remove(@join_timer) + announce _("game start countdown stopped") + @join_timer = nil + end if halted if @start_time announce _("%{uno} game halted after %{time}") % { @@ -772,12 +834,12 @@ class UnoGame deal(p, @picker) @picker = 0 end - score = @players.inject(0) do |sum, p| - if p.cards.length > 0 + score = @players.inject(0) do |sum, pl| + if pl.cards.length > 0 announce _("%{p} still had %{cards}") % { - :p => p, :cards => p.cards.join(' ') + :p => pl, :cards => pl.cards.join(' ') } - sum += p.cards.inject(0) do |cs, c| + sum += pl.cards.inject(0) do |cs, c| cs += c.score end end @@ -880,6 +942,7 @@ class UnoPlugin < Plugin return unless @games.key?(m.channel) return unless m.plugin # skip messages such as: botname, g = @games[m.channel] + replied = true case m.plugin.intern when :jo # join game return if m.params @@ -945,7 +1008,10 @@ class UnoPlugin < Plugin else g.show_turn(:cards => false) end + else + replied=false end + m.replied=true if replied end def create_game(m, p)