#
# GoodDay's Uno v0.96
# Copyright (C) 2004 Mark A. Day (techwhiz@earthlink.net)
#
# Uno(tm) is Copyright (C) 2001 Mattel, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

# Default Settings
set UnoChan 		"#honey"
set UnoRobot 		"GoodDay"
set UnoPointsName 	"Points"
set UnoStopAfter 	5
set UnoBonus		1000
set UnoWildDrawTwos	1
set UnoCFGFile		"scripts/uno.cfg"
set UnoScoreFile 	"scores/UnoScores"
set UnoMaxNickLen	9
set UnoMaxPlayers	10
set UnoOpFlags		"o|o"
set UnoNTC		"NOTICE"

# Command Binds
bind pub - !unocmds UnoCmds
bind pub - !remove UnoRemove
bind pub - !pause UnoPause
bind pub - !unowon UnoWon
bind pub - !unotop10 UnoTopTen
bind pub - !unotop10won UnoTopTenWon
bind pub - !unotop3last UnoTopThreeLast
bind pub - !unofast UnoTopFast
bind pub - !unohigh UnoHighScore
bind pub - !unoplayed UnoPlayed
bind pub - !unorecords UnoRecords
bind pub - !unoversion UnoVersion
bind pub - !uno UnoInit
bind pub - !stop UnoStop

# DCC Binds
bind dcc - unohands dccUnoHands
bind dcc - unorehash dcc_unorehash

# Cron Bind For Score Reset
bind time - "00 00 01 * *" UnoNewMonth

# Global Variables
set UnoOn 0
set UnoMode 0
set UnoPaused 0
set UnoPlayers 0
set MasterDeck ""
set UnoDeck ""
set DiscardPile ""
set PlayCard ""
set RoundRobin ""
set ThisPlayer ""
set ThisPlayerIDX 0
set UnoStartTime [unixtime]
set IsColorChange 0
set ColorPicker ""
set IsDraw 0
set UnoIDX ""
set UnPlayedRounds 0

# Scores Records And Ads
set UnoLastMonthCards(0) "Nobody 0"
set UnoLastMonthCards(1) "Nobody 0"
set UnoLastMonthCards(2) "Nobody 0"
set UnoLastMonthGames(0) "Nobody 0"
set UnoLastMonthGames(1) "Nobody 0"
set UnoLastMonthGames(2) "Nobody 0"
set UnoFast "Nobody 600"
set UnoHigh "Nobody 0"
set UnoPlayed "Nobody 0"
set UnoRecordHigh "Nobody 0"
set UnoRecordFast "Nobody 600"
set UnoRecordCard "Nobody 0"
set UnoRecordWins "Nobody 0"
set UnoRecordPlayed "Nobody 0"
set UnoAdNumber 0

# Card Stats
set CardStats(played) 0
set CardStats(passed) 0
set CardStats(drawn) 0
set CardStats(wilds) 0
set CardStats(draws) 0
set CardStats(skips) 0
set CardStats(revs) 0

# Timers
set UnoStartTimer ""
set UnoSkipTimer ""
set UnoCycleTimer ""
set UnoBotTimer ""

# Grace periods and timeouts
# AutoSkip period can be raised but not lower than 2
set AutoSkipPeriod 2
set StartGracePeriod 30
set RobotRestartPeriod 1
set UnoCycleTime 30

# Nick colours
set UnoNickColour "06 13 03 07 12 10 04 11 09 08"

# Debugging info
set Debug 0
set UnoVersion "0.96.74.3"

#
# Bind Channel Commands 
#
proc UnoBindCmds {} {
 bind pub - join JoinUno
 bind pub - jo JoinUno
 bind pub - order UnoOrder
 bind pub - od UnoOrder
 bind pub - time UnoTime
 bind pub - ti UnoTime
 bind pub - cards UnoShowCards
 bind pub - ca UnoShowCards
 bind pub - play UnoPlayCard
 bind pub - pl UnoPlayCard
 bind pub - card UnoTopCard
 bind pub - cd UnoTopCard
 bind pub - turn UnoTurn
 bind pub - tu UnoTurn
 bind pub - draw UnoDraw
 bind pub - dr UnoDraw
 bind pub - color UnoColorChange
 bind pub - co UnoColorChange
 bind pub - pass UnoPass
 bind pub - pa UnoPass
 bind pub - count UnoCount
 bind pub - ct UnoCount
 bind pub - stats UnoCardStats
 bind pub - st UnoCardStats
}

#
# Unbind Channel Commands 
#
proc UnoUnbindCmds {} {
 catch {unbind pub - join JoinUno}
 catch {unbind pub - jo JoinUno}
 catch {unbind pub - order UnoOrder}
 catch {unbind pub - od UnoOrder}
 catch {unbind pub - time UnoTime}
 catch {unbind pub - ti UnoTime}
 catch {unbind pub - cards UnoShowCards}
 catch {unbind pub - ca UnoShowCards}
 catch {unbind pub - play UnoPlayCard}
 catch {unbind pub - pl UnoPlayCard}
 catch {unbind pub - card UnoTopCard}
 catch {unbind pub - cd UnoTopCard}
 catch {unbind pub - turn UnoTurn}
 catch {unbind pub - tu UnoTurn}
 catch {unbind pub - draw UnoDraw}
 catch {unbind pub - dr UnoDraw}
 catch {unbind pub - color UnoColorChange}
 catch {unbind pub - co UnoColorChange}
 catch {unbind pub - pass UnoPass}
 catch {unbind pub - pa UnoPass}
 catch {unbind pub - count UnoCount}
 catch {unbind pub - ct UnoCount}
 catch {unbind pub - stats UnoCardStats}
 catch {unbind pub - st UnoCardStats}
}

#
# Reset Game Variables
#
proc UnoReset {} {
 global UnoOn UnoMode UnoPaused UnoPlayers RoundRobin UnoDeck ThisPlayer ThisPlayerIDX PlayCard
 global DiscardPile IsColorChange ColorPicker IsDraw UnoIDX MasterDeck CardStats
 global UnoStartTimer UnoSkipTimer UnoCycleTimer

 set UnoMode 0
 set UnoPaused 0
 set UnoPlayers 0
 set MasterDeck ""
 set UnoDeck ""
 set DiscardPile ""
 set RoundRobin ""
 set ThisPlayer ""
 set ThisPlayerIDX 0
 set PlayCard ""
 set IsColorChange 0
 set ColorPicker ""
 set IsDraw 0
 set UnoIDX ""
 set UnoAdNumber 0

 set CardStats(played) 0
 set CardStats(passed) 0
 set CardStats(drawn) 0
 set CardStats(wilds) 0
 set CardStats(draws) 0
 set CardStats(skips) 0
 set CardStats(revs) 0

 set UnoStartTimer ""
 set UnoSkipTimer ""
 set UnoCycleTimer ""

 return
}

#
# Stop a game
#
proc UnoStop {nick uhost hand chan arg} {
 global Debug UnoChan UnoOn UnoPaused UnPlayedRounds UnoStartTimer UnoSkipTimer UnoCycleTimer

 if {$chan != $UnoChan} {return}

 catch {killutimer $UnoStartTimer}
 catch {killtimer $UnoSkipTimer}
 catch {killutimer $UnoCycleTimer}

 unomsg "[unoad]\00306 stopped by \00304\[\00312$nick!$uhost\00304\]\003"

 set UnoOn 0
 set UnoPaused 0
 set UnPlayedRounds 0

 UnoUnbindCmds
 UnoReset

 return
}

#
# First Entry
#
proc UnoInit {nick uhost hand chan arg} {
 global UnoChan UnoOn 
 if {($chan != $UnoChan)||($UnoOn > 0)} {return}
 unomsg "[unoad] \00304\[\00310$nick\!$uhost\00304\]\003"
 set UnoOn 1
 UnoBindCmds
 UnoNext
 return
}

#
# Initialize a new game
#
proc UnoNext {} {
 global UnoOn MasterDeck UnoDeck UnoMode StartGracePeriod UnoHand NickColor UnoVersion UnoStartTimer UnoSkipTimer

 if {$UnoOn == 0} {return}

 UnoReset

 set UnoMode 1

 set MasterDeck [list B0 B1 B1 B2 B2 B3 B3 B4 B4 B5 B5 B6 B6 B7 B7 B8 B8 B9 B9 BR BR BS BS BDT BDT R0 R1 R1 R2 R2 R3 R3 R4 R4 R5 R5 R6 R6 R7 R7 R8 R8 R9 R9 RR RR RS RS RDT RDT Y0 Y1 Y1 Y2 Y2 Y3 Y3 Y4 Y4 Y5 Y5 Y6 Y6 Y7 Y7 Y8 Y8 Y9 Y9 YR YR YS YS YDT YDT G0 G1 G1 G2 G2 G3 G3 G4 G4 G5 G5 G6 G6 G7 G7 G8 G8 G9 G9 GR GR GS GS GDT GDT W W W W WDF WDF WDF WDF]
 set UnoDeck ""

 binary scan [unixtime] S1 rseed
 set newrand [expr srand($rseed)]

 while {[llength $UnoDeck] != 108} {
  set pcardnum [rand [llength $MasterDeck]]
  set pcard [lindex $MasterDeck $pcardnum]
  lappend UnoDeck $pcard
  set MasterDeck [lreplace $MasterDeck $pcardnum $pcardnum]
 }

 if [info exist UnoHand] {unset UnoHand}
 if [info exist NickColor] {unset NickColor}

 unomsg " "
 unomsg "[unoad]\003 \0030,6 v$UnoVersion by GoodDay \003"
 unomsg "[unoad]\003 \0030,12 Join Now - You Have $StartGracePeriod Seconds \003"

 set UnoStartTimer [utimer $StartGracePeriod UnoStart]

 return
}

#
# Start a new game
#
proc UnoStart {} {
 global UnoChan UnoOn UnoCycleTime UnoRobot Debug UnoIDX UnoStartTime UnoPlayers RoundRobin ThisPlayer ThisPlayerIDX UnoDeck DiscardPile UnoMode UnoHand PlayCard AutoSkipPeriod
 global UnoSkipTimer UnPlayedRounds UnoStopAfter NickColor

 if {$UnoOn == 0} {return}

 if {[llength $RoundRobin] == 0} {
  unomsg "[unoad] \0030,3 No players - Next game in $UnoCycleTime seconds \003"
  incr UnPlayedRounds
  if {($UnoStopAfter > 0)&&($UnPlayedRounds >= $UnoStopAfter)} {
    unomsg "[unoad] \0030,6 Stopped after $UnoStopAfter unplayed rounds - Type !uno to restart \003"
    utimer 1 "UnoStop $UnoRobot $UnoRobot none $UnoChan none"
    return
  }
  UnoCycle
  return
 }

 # Bot Joins If One Player

 if {[llength $RoundRobin] == 1} {
  incr UnoPlayers

  lappend RoundRobin "$UnoRobot"
  lappend UnoIDX "$UnoRobot"

  if [info exist UnoHand($UnoRobot)] {unset UnoHand($UnoRobot)}
  if [info exist NickColor($UnoRobot)] {unset NickColor($UnoRobot)}

  set UnoHand($UnoRobot) ""
  set NickColor($UnoRobot) [colornick $UnoPlayers]

  unomsg "[nikclr $UnoRobot]\003 joins [unoad]\003"

  UnoShuffle 7

  while {[llength $UnoHand($UnoRobot)] != 7} {
   set pcardnum [rand [llength $UnoDeck]]
   set pcard [lindex $UnoDeck $pcardnum]
   set UnoDeck [lreplace ${UnoDeck} $pcardnum $pcardnum]
   lappend UnoHand($UnoRobot) "$pcard"
  }
  if {$Debug > 1} { unolog $UnoRobot $UnoHand($UnoRobot) }
 }

 unomsg "\0030,6 Welcome to \003 [unoad]\003"
 unomsg "\0030,10 \002$UnoPlayers\002 players this round \0030,6 $RoundRobin \003"

 set UnoMode 2
 set ThisPlayer [lindex $RoundRobin 0]

 # Draw Card From Deck - First Top Card

 set DiscardPile ""
 set pcardnum [rand [llength $UnoDeck]]
 set pcard [lindex $UnoDeck $pcardnum]

 # Play Doesnt Start With A Wild Card

 while {[string range $pcard 0 0] == "W"} {
  set pcardnum [rand [llength $UnoDeck]]
  set pcard [lindex $UnoDeck $pcardnum]
 }

 set PlayCard $pcard

 set UnoDeck [lreplace ${UnoDeck} $pcardnum $pcardnum]

 set Card [CardColor $pcard]

 unomsg "[nikclr $ThisPlayer]\003 plays first - the top card is $Card \003"

 set Card [CardColorAll $ThisPlayer]

 showcards $ThisPlayerIDX $Card

 set UnoStartTime [unixtime]

 # Start Auto-Skip Timer

 set UnoSkipTimer [timer $AutoSkipPeriod UnoAutoSkip]

 set UnPlayedRounds 0
 return
}

#
# Cycle a new game
#
proc UnoCycle {} {
 global UnoOn UnoMode UnoCycleTime UnoCycleTimer UnoSkipTimer
 if {$UnoOn == 0} {return}
 set UnoMode 4
 catch {killtimer $UnoSkipTimer}
 set AdTime [expr $UnoCycleTime /2]
 set UnoAdTimer [utimer $AdTime UnoScoreAdvertise]
 set UnoCycleTimer [utimer $UnoCycleTime UnoNext]
 return
}

#
# Add a player
#
proc JoinUno {nick uhost hand chan arg} {
 global Debug UnoIDX UnoMode UnoPlayers RoundRobin UnoDeck UnoHand UnoChan NickColor UnoMaxPlayers

 if {($chan != $UnoChan)||($UnoMode < 1)||($UnoMode > 2)} {return}

 if {[llength $RoundRobin] == $UnoMaxPlayers} {
  unontc $nick "Sorry $nick - Uno already has $UnoMaxPlayers players, try next game"
  return
 }

 set pcount 0
 while {[lindex $RoundRobin $pcount] != ""} {
  if {[lindex $RoundRobin $pcount] == $nick} {
   return
  }
  incr pcount
 }

 incr UnoPlayers

 lappend RoundRobin $nick
 lappend UnoIDX $nick

 if [info exist UnoHand($nick)] {unset UnoHand($nick)}
 if [info exist NickColor($nick)] {unset NickColor($nick)}

 set UnoHand($nick) ""
 set NickColor($nick) [colornick $UnoPlayers]

 # Re-Shuffle Deck

 UnoShuffle 7

 # Deal Cards To Player

 set Card ""
 while {[llength $UnoHand($nick)] != 7} {
  set pcardnum [rand [llength $UnoDeck]]
  set pcard [lindex $UnoDeck $pcardnum]
  set UnoDeck [lreplace ${UnoDeck} $pcardnum $pcardnum]
  lappend UnoHand($nick) $pcard
  append Card [CardColor $pcard]
 }

 if {$Debug > 1} { unolog $nick $UnoHand($nick) }

 unomsg "[nikclr $nick]\003 joins [unoad]\003"
 unontc $nick "Hand: $Card"
 return
}

#
# Add card(s) to players hand
#
proc UnoAddDrawToHand {cplayer idx num} {
 global UnoHand UnoDeck RoundRobin CardStats

 # Check if deck needs reshuffling
 UnoShuffle $num

 set Card ""

 set newhand [expr [llength $UnoHand($cplayer)] + $num]

 while {[llength $UnoHand($cplayer)] != $newhand} {
  set pcardnum [rand [llength $UnoDeck]]
  set pcard [lindex $UnoDeck $pcardnum]
  set UnoDeck [lreplace ${UnoDeck} $pcardnum $pcardnum]
  lappend UnoHand($cplayer) $pcard
  append Card [CardColor $pcard]
 }

 showdraw $idx $Card

 incr CardStats(drawn) $num
}

#
# Remove played card from player's hand
#
proc UnoRemoveCardFromHand {cplayer pcard} {
 global UnoHand
 set UnoHand($cplayer) [lreplace $UnoHand($cplayer) $pcard $pcard]
}

#
# Add card to discard pile
#
proc AddToDiscardPile {playcard} {
 global DiscardPile
 if {[string range $playcard 1 1] != ""} {
  lappend DiscardPile $playcard
 }
}

#
# Draw a card
#
proc UnoDraw {nick uhost hand chan arg} {
 global UnoChan UnoMode UnoDeck ThisPlayer ThisPlayerIDX UnoHand RoundRobin IsDraw CardStats

 if {($chan != $UnoChan)||($UnoMode != 2)||($nick != $ThisPlayer)} {return}

 if {$IsDraw == 0} {
  set IsDraw 1
  UnoShuffle 1

  set dcardnum [rand [llength $UnoDeck]]
  set dcard [lindex $UnoDeck $dcardnum]
  lappend UnoHand($nick) $dcard
  set UnoDeck [lreplace ${UnoDeck} $dcardnum $dcardnum]

  append Card [CardColor $dcard]

  showdraw $ThisPlayerIDX $Card

  showwhodrew $nick
  incr CardStats(drawn)
  UnoAutoSkipReset

  return
 }

 unontc $nick "You've already drawn a card $nick, play a card or pass"

 UnoAutoSkipReset

 return
}

#
# Pass a turn
#
proc UnoPass {nick uhost hand chan arg} {
 global UnoChan UnoMode ThisPlayer IsDraw ThisPlayerIDX RoundRobin IsColorChange CardStats

 if {($chan != $UnoChan)||($UnoMode != 2)} {return}
 if {($nick != $ThisPlayer)||($IsColorChange == 1)} {return}

 UnoAutoSkipReset

 if {$IsDraw == 1} {
  incr CardStats(passed)
  set IsDraw 0
  UnoNextPlayer
  playpass $nick $ThisPlayer
  set Card [CardColorAll $ThisPlayer]
  showcards $ThisPlayerIDX $Card
  UnoRobotRestart
 } {
  unontc $nick "Sorry $nick - You cant pass without drawing a card"
 }
 return
}

#
# Color change
#
proc UnoColorChange {nick uhost hand chan arg} {
 global UnoChan UnoMode IsDraw PlayCard ColorPicker IsColorChange ThisPlayer ThisPlayerIDX RoundRobin

 if {($chan != $UnoChan)||($UnoMode != 2)} {return}
 if {($nick != $ColorPicker)||($IsColorChange == 0)} {return}

 UnoAutoSkipReset

 regsub -all \[`.,!{}] $arg "" arg

 set NewColor [string toupper [string range $arg 0 0]]

 switch $NewColor {
  "B" { set PlayCard "B"; set Card " \0030,12 Blue \003 "}
  "G" { set PlayCard "G"; set Card " \0030,3 Green \003 "}
  "Y" { set PlayCard "Y"; set Card " \0031,8 Yellow \003 "}
  "R" { set PlayCard "R"; set Card " \0030,4 Red \003 "}
  default { unontc $nick "Choose A Valid Color - Red, Green, Blue, or Yellow"; return }
 }

 UnoNextPlayer

 unomsg "[nikclr $ColorPicker]\003 chose $Card and play continues with [nikclr $ThisPlayer]\003"

 set Card [CardColorAll $ThisPlayer]
 showcards $ThisPlayerIDX $Card

 set ColorPicker ""
 set IsColorChange 0
 set IsDraw 0

 UnoRobotRestart

 return
}

#
# Skip card
#
proc PlayUnoSkipCard {nick pickednum crd} {
 global IsDraw ThisPlayer ThisPlayerIDX PlayCard RoundRobin CardStats

 set c0 [string range $crd 0 0]
 set c1 [string range $crd 1 1]
 set cip0 [string range $PlayCard 0 0]
 set cip1 [string range $PlayCard 1 1]

 if {$c1 != "S"} {return 0}

 if {($c0 != $cip0)&&($c1 != $cip1)} {return 0}

 incr CardStats(played)
 incr CardStats(skips)

 AddToDiscardPile $PlayCard

 UnoRemoveCardFromHand $nick $pickednum

 set PlayCard $crd
 set Card [CardColor $crd]

 set SkipPlayer $ThisPlayer

 UnoNextPlayer

 set SkippedPlayer [lindex $RoundRobin $ThisPlayerIDX]

 UnoNextPlayer

 # No Cards Left = Winner
 if {[check_unowin $SkipPlayer $Card] > 0} {
  showwin $SkipPlayer $Card
  UnoWin $SkipPlayer
  UnoCycle
  return 1
 }

 playskip $nick $Card $SkippedPlayer $ThisPlayer

 check_hasuno $SkipPlayer

 set Card [CardColorAll $ThisPlayer]
 showcards $ThisPlayerIDX $Card

 set IsDraw 0
 return 1
}

#
# Reverse card
#
proc PlayUnoReverseCard {nick pickednum crd} {
 global IsDraw UnoIDX ThisPlayer ThisPlayerIDX PlayCard RoundRobin CardStats

 set c0 [string range $crd 0 0]
 set c1 [string range $crd 1 1]
 set cip0 [string range $PlayCard 0 0]
 set cip1 [string range $PlayCard 1 1]

 if {$c1 != "R"} {return 0}

 if {($c0 != $cip0)&&($c1 != $cip1)} {return 0}

 incr CardStats(played)
 incr CardStats(revs)

 AddToDiscardPile $PlayCard

 UnoRemoveCardFromHand $nick $pickednum

 set PlayCard $crd
 set Card [CardColor $crd]

 # Reverse RoundRobin and Move To Next Player
 set NewRoundRobin ""
 set OrigOrderLength [llength $RoundRobin]
 set IDX $OrigOrderLength

 while {$OrigOrderLength != [llength $NewRoundRobin]} {
  set IDX [expr ($IDX - 1)]
  lappend NewRoundRobin [lindex $RoundRobin $IDX]
 }

 set Newindexorder ""
 set OrigindexLength [llength $UnoIDX]
 set IDX $OrigindexLength

 while {$OrigindexLength != [llength $Newindexorder]} {
  set IDX [expr ($IDX - 1)]
  lappend Newindexorder [lindex $UnoIDX $IDX]
 }

 set UnoIDX $Newindexorder
 set RoundRobin $NewRoundRobin

 set ReversePlayer $ThisPlayer

 # Next Player After Reversing RoundRobin

 set pcount 0
 while {$pcount != [llength $RoundRobin]} {
  if {[lindex $RoundRobin $pcount] == $ThisPlayer} {
   set ThisPlayerIDX $pcount
   break
  }
  incr pcount
 }

 # <3 Players Act Like A Skip Card

 if {[llength $RoundRobin] > 2} {
  incr ThisPlayerIDX
  if {$ThisPlayerIDX >= [llength $RoundRobin]} {set ThisPlayerIDX 0}
 }

 set ThisPlayer [lindex $RoundRobin $ThisPlayerIDX]

 # No Cards Left = Winner
 if {[check_unowin $ReversePlayer $Card] > 0} {
  showwin $ReversePlayer $Card
  UnoWin $ReversePlayer
  UnoCycle
  return 1
 }

 playcard $nick $Card $ThisPlayer

 check_hasuno $ReversePlayer

 set Card [CardColorAll $ThisPlayer]
 showcards $ThisPlayerIDX $Card

 set IsDraw 0
 return 1
}

#
# Draw Two card
#
proc PlayUnoDrawTwoCard {nick pickednum crd} {
 global IsDraw ThisPlayer ThisPlayerIDX PlayCard RoundRobin CardStats UnoWildDrawTwos

 set CardOk 0
 set c0 [string range $crd 0 0]
 set c2 [string range $crd 2 2]
 set cip0 [string range $PlayCard 0 0]
 set cip1 [string range $PlayCard 1 1]
 set cip2 [string range $PlayCard 2 2]

 if {$c2 != "T"} {return 0}

 if {$c0 == $cip0} {set CardOk 1}
 if {$cip2 == "T"} {set CardOk 1}
 if {$UnoWildDrawTwos != 0} {
  if {($cip1 != "")&&($cip2 != "F")} {set CardOk 1}
 }

 if {$CardOk == 1} {
  incr CardStats(draws)
  incr CardStats(played)

  AddToDiscardPile $PlayCard

  UnoRemoveCardFromHand $nick $pickednum

  set PlayCard $crd
  set Card [CardColor $crd]

  set DrawPlayer $ThisPlayer
  set DrawPlayerIDX $ThisPlayerIDX

  # Move to the player that draws

  UnoNextPlayer

  set PlayerThatDrew $ThisPlayer
  set PlayerThatDrewIDX $ThisPlayerIDX

  # Move To The Next Player

  UnoNextPlayer

  if {[check_unowin $nick $Card] > 0} {
   UnoAddDrawToHand $PlayerThatDrew $PlayerThatDrewIDX 2
   showwin $nick $Card
   UnoWin $nick
   UnoCycle
   return 1
  }

  playdraw $nick $Card $PlayerThatDrew $ThisPlayer

  UnoAddDrawToHand $PlayerThatDrew $PlayerThatDrewIDX 2

  check_hasuno $nick

  set Card [CardColorAll $ThisPlayer]
  showcards $ThisPlayerIDX $Card

  set IsDraw 0
  return 1
 }
 return 0
}

#
# Wild Draw Four card
#
proc PlayUnoWildDrawFourCard {nick pickednum crd isrobot} {
 global ThisPlayer ThisPlayerIDX PlayCard RoundRobin IsColorChange ColorPicker CardStats

 if {[string range $crd 2 2] != "F"} {return 0}

 incr CardStats(wilds)
 incr CardStats(played)

 set ColorPicker $ThisPlayer

 AddToDiscardPile $PlayCard

 UnoRemoveCardFromHand $nick $pickednum

 set PlayCard $crd
 set Card [CardColor $crd]

 # move to the player that draws
 UnoNextPlayer

 set PlayerThatDrew $ThisPlayer
 set PlayerThatDrewIDX $ThisPlayerIDX

 if {$isrobot > 0} {
  # choose color and move to next player
  set cip [UnoBotPickAColor]
  UnoNextPlayer
 }

 if {[check_unowin $nick $Card] > 0} {
  UnoAddDrawToHand $PlayerThatDrew $PlayerThatDrewIDX 4
  showwin $nick $Card
  UnoWin $nick
  UnoCycle
  return 1
 }

 if {$isrobot > 0} {
  botplaywildfour $ColorPicker $PlayerThatDrew $ColorPicker $cip $ThisPlayer
  set ColorPicker ""
  set IsColorChange 0
 } {
  playwildfour $nick $PlayerThatDrew $ColorPicker
  set IsColorChange 1
 }

 UnoAddDrawToHand $PlayerThatDrew $PlayerThatDrewIDX 4

 check_hasuno $nick

 if {$isrobot > 0} {
  set Card [CardColorAll $ThisPlayer]
  showcards $ThisPlayerIDX $Card
 }

 set IsDraw 0
 return 1
}

#
# Wild card
#
proc PlayUnoWildCard {nick pickednum crd isrobot} {
 global IsDraw ThisPlayer ThisPlayerIDX PlayCard RoundRobin IsColorChange ColorPicker CardStats

 if {[string range $crd 0 0] != "W"} {return 0}

 incr CardStats(wilds)
 incr CardStats(played)

 set ColorPicker $ThisPlayer

 AddToDiscardPile $PlayCard

 UnoRemoveCardFromHand $nick $pickednum

 set PlayCard $crd
 set Card [CardColor $crd]

 # Ok to remove this?
 #set ThisPlayer [lindex $RoundRobin $ThisPlayerIDX]
 #set DrawnPlayer $ThisPlayer
 
 if {$isrobot > 0} {
  # Make A Color Choice
  set cip [UnoBotPickAColor]
  UnoNextPlayer
 }

 # No Cards Left = Winner
 if {[check_unowin $nick $Card] > 0} {
  showwin $nick $Card
  UnoWin $nick
  UnoCycle
  return 1
 }

 if {$isrobot > 0} {
  botplaywild $nick $ColorPicker $cip $ThisPlayer
  set ColorPicker ""
  set Card [CardColorAll $ThisPlayer]
  showcards $ThisPlayerIDX $Card
  set IsColorChange 0
 } {
  playwild $nick $ColorPicker
  set IsColorChange 1
 }

 check_hasuno $nick

 set IsDraw 0
 return 1
}

#
# Number card
#
proc PlayUnoNumberCard {nick pickednum crd} {
 global IsDraw ThisPlayer ThisPlayerIDX PlayCard RoundRobin CardStats

 set CardOk 0
 set c1 [string range $crd 0 0]
 set c2 [string range $crd 1 1]
 set cip1 [string range $PlayCard 0 0]
 set cip2 [string range $PlayCard 1 1]

 if {$c2 == -1} {return 0}

 if {$c1 == $cip1} {set CardOk 1}

 if {($cip2 != "")} {
  if {$c2 == $cip2} {set CardOk 1}
 }

 if {$CardOk == 1} {
  incr CardStats(played)
  AddToDiscardPile $PlayCard

  UnoRemoveCardFromHand $nick $pickednum

  set PlayCard $crd
  set Card [CardColor $crd]

  set NumberCardPlayer $ThisPlayer

  UnoNextPlayer

  if {[check_unowin $NumberCardPlayer $Card] > 0} {
   showwin $NumberCardPlayer $Card
   UnoWin $NumberCardPlayer
   UnoCycle
   return 1
  }

  playcard $nick $Card $ThisPlayer

  check_hasuno $NumberCardPlayer

  set Card [CardColorAll $ThisPlayer]
  showcards $ThisPlayerIDX $Card

  set IsDraw 0
  return 1
 }
 unontc $nick "Oops! Not a valid card - draw or play another"
 return 0
}

#
# Attempt to find card in hand
#
proc UnoFindCard {nick pickednum crd IsRobot} {
 global UnoRobot ThisPlayer ThisPlayerIDX

  #if {$Debug > 1} {unolog $UnoRobot "UnoFindCard: [lindex $UnoHand($ThisPlayer) $pickednum"}

  # Wild Draw Four
  set FoundCard [PlayUnoWildDrawFourCard $nick $pickednum $crd $IsRobot]
  if {$FoundCard == 1} {return 4}

  # Wild
  set FoundCard [PlayUnoWildCard $nick $pickednum $crd $IsRobot]
  if {$FoundCard == 1} {return 5}

  # Draw Two
  set FoundCard [PlayUnoDrawTwoCard $nick $pickednum $crd]
  if {$FoundCard == 1} {return 3}

  # Skip
  set FoundCard [PlayUnoSkipCard $nick $pickednum $crd]
  if {$FoundCard == 1} {return 1}

  # Reverse
  set FoundCard [PlayUnoReverseCard $nick $pickednum $crd]
  if {$FoundCard == 1} {return 2}

  # Number card
  set FoundCard [PlayUnoNumberCard $nick $pickednum $crd]
  if {$FoundCard == 1} {return 6}

  return 0
}

#
# Play a card
#
proc UnoPlayCard {nick uhost hand chan arg} {
 global UnoChan UnoMode IsDraw IsColorChange ColorPicker UnoPlayers RoundRobin UnoHand ThisPlayer

 if {($chan != $UnoChan)||($UnoMode != 2)||($nick != $ThisPlayer)} {return}

 UnoAutoSkipReset

 if {$IsColorChange == 1} {return}

 regsub -all \[`,.!{}\ ] $arg "" arg

 if {$arg == ""} {return}

 set pcard [string toupper [string range $arg 0 3]]

 set CardInPlayerHand 0

 set pcount 0
 while {[lindex $UnoHand($nick) $pcount] != ""} {
  if {$pcard == [lindex $UnoHand($nick) $pcount]} {
   set pcardnum $pcount
   set CardInPlayerHand 1
   break
  }
  incr pcount
 }

 if {$CardInPlayerHand == 0} {
  unontc $nick "Sorry $nick - You don't have that card - draw or play another"
  return
 }

 set CardFound [UnoFindCard $nick $pcardnum $pcard 0]

 switch $CardFound {
  0 {return}
  4 {return}
  5 {return}
  default {UnoRobotRestart; return}
 }
}

#
# Robot Player
#

proc UnoRobotPlayer {} {
 global Debug UnoIDX IsDraw IsColorChange ColorPicker UnoMode UnoPlayers RoundRobin UnoDeck UnoHand ThisPlayer ThisPlayerIDX PlayCard CardStats UnoRobot

 # Check for a valid card in hand
 set CardOk 0
 set IsDraw 0
 set CardCount 0

 set cip1 [string range $PlayCard 0 0]
 set cip2 [string range $PlayCard 1 1]

 while {$CardCount < [llength $UnoHand($ThisPlayer)]} {
  set playcard [lindex $UnoHand($ThisPlayer) $CardCount]
  set c1 [string range $playcard 0 0]
  set c2 [string range $playcard 1 1]

  #if {$Debug > 1} {unolog $UnoRobot "Trying: $playcard"}

  if {($c1 == $cip1)||($c2 == $cip2)||($c1 == "W")} {
   set CardOk 1
   set pcard $playcard
   set pcardnum $CardCount
   break
  }
  incr CardCount
 }

 # Play the card if found
 if {$CardOk == 1} {
  set CardFound [UnoFindCard $UnoRobot $pcardnum $pcard 1]
  switch $CardFound {
   0 {}
   5 {return}
   6 {return}
   default {UnoRobotRestart; return}
  }
 }

 # Bot draws a card

 UnoShuffle 1

 set dcardnum [rand [llength $UnoDeck]]
 set dcard [lindex $UnoDeck $dcardnum]
 lappend UnoHand($UnoRobot) "$dcard"
 set UnoDeck [lreplace ${UnoDeck} $dcardnum $dcardnum]

 showwhodrew $UnoRobot

 set CardOk 0
 set CardCount 0

 incr CardStats(drawn)

 while {$CardCount < [llength $UnoHand($ThisPlayer)]} {
  set playcard [lindex $UnoHand($ThisPlayer) $CardCount]
  set c1 [string range $playcard 0 0]
  set c2 [string range $playcard 1 1]

  # if {$Debug > 1} {unolog $UnoRobot "DrawTry: $playcard"}

  if {($c1 == $cip1)||($c2 == $cip2)||($c1 == "W")} {
   set CardOk 1
   set pcard $playcard
   set pcardnum $CardCount
   break
  }
  incr CardCount
 }

 # Bot plays drawn card or passes turn

 if {$CardOk == 1} {
  set CardFound [UnoFindCard $UnoRobot $pcardnum $pcard 1]
  if {$CardFound == 1} {UnoRobotRestart; return}
  switch $CardFound {
   0 {}
   5 {return}
   6 {return}
   default {UnoRobotRestart; return}
  }
 } {
  incr CardStats(passed)

  set IsDraw 0

  UnoNextPlayer

  playpass $UnoRobot $ThisPlayer

  set Card [CardColorAll $ThisPlayer]
  showcards $ThisPlayerIDX $Card
 }
 return
}

#
# Autoskip inactive players
#
proc UnoAutoSkip {} {
 global UnoMode ThisPlayer ThisPlayerIDX RoundRobin AutoSkipPeriod IsColorChange ColorPicker
 global UnoIDX UnoPlayers UnoDeck UnoHand UnoChan UnoSkipTimer Debug NickColor UnoPaused

 if {$UnoMode != 2} {return}
 if {$UnoPaused != 0} {return}

 if {[uno_isrobot $ThisPlayerIDX]} {return}

 set Idler $ThisPlayer
 set IdlerIDX $ThisPlayerIDX

 if {[unotimerexists UnoAutoSkip] != ""} {
  unolog "uno" "AutoSkip Timer Already Exists"
  return
 }

 set InChannel 0
 set uclist [chanlist $UnoChan]

 set pcount 0
 while {[lindex $uclist $pcount] != ""} {
  if {[lindex $uclist $pcount] == $Idler} {
   set InChannel 1
   break
  }
  incr pcount
 }

 if {$InChannel == 0} {
  unomsg "[nikclr $Idler]\003 left the channel and is removed from Uno\003"

  if {$IsColorChange == 1} {
   if {$Idler == $ColorPicker} {
    # Make A Color Choice
    set cip [UnoPickAColor]
    unomsg "\0030,13 $Idler \003was picking a color : randomly selecting $cip \003"
    set IsColorChange 0
   } {
    unolog "uno" "UnoAutoRemove: IsColorChange set but $Idler not ColorPicker"
   }
  }

  UnoNextPlayer
  unomsg "[nikclr $Idler]\003 was the current player, continuing with [nikclr $ThisPlayer]\003"
  if {![uno_isrobot $ThisPlayerIDX]} {
   set Card [CardColorAll $ThisPlayer]
   showcards $ThisPlayerIDX $Card
  }

  set UnoPlayers [expr ($UnoPlayers -1)]

  # Remove Player From Game And Put Cards Back In Deck
  if {$UnoPlayers > 1} {
   set RoundRobin [lreplace ${RoundRobin} $IdlerIDX $IdlerIDX]
   set UnoIDX [lreplace ${UnoIDX} $IdlerIDX $IdlerIDX]
   lappend UnoDeck "$UnoHand($Idler)"
   unset UnoHand($Idler)
   unset NickColor($Idler)
  }

  switch $UnoPlayers {
   1 {
      showwindefault $ThisPlayer
      UnoWin $ThisPlayer
      UnoCycle
     }
   0 {
      unomsg "[unoad] \0030,10 No players - No winner - Recycling \003"
      UnoCycle
     }
   default {
      if {![uno_isrobot $ThisPlayerIDX]} {
       UnoAutoSkipReset
       UnoRobotRestart
      }
     }
  }
  return
 }

 if {$Debug > 0} {unolog "uno" "AutoSkip Player: $Idler"}

 unomsg "[nikclr $Idler]\003 idle for \00313$AutoSkipPeriod \003minutes and is skipped"

 # Player Was ColorPicker

 if {$IsColorChange == 1} {
  if {$Idler == $ColorPicker} {
   # Make A Color Choice
   set cip [UnoPickAColor]
   unomsg "[nikclr $Idler]\003 was picking a color : randomly selecting $cip"
   set IsColorChange 0
  } {
   unolog "uno" "UnoRemove: IsColorChange set but $Idler not ColorPicker"
  }
 }

 UnoNextPlayer

 unomsg "[nikclr $Idler]\003 was the current player. Continuing with [nikclr $ThisPlayer]\003"

 if {![uno_isrobot $ThisPlayerIDX]} {
  set Card [CardColorAll $ThisPlayer]
  showcards $ThisPlayerIDX $Card
 } {
  UnoRobotRestart
 }
 UnoAutoSkipReset
 return
}

#
# Pause play
#
proc UnoPause {nick uhost hand chan arg} {
 global UnoChan UnoOn UnoMode UnoOpFlags UnoPaused

 if {$chan != $UnoChan} {return}
 if {$UnoOn != 1} {return}
 if {$UnoMode != 2} {return}

 if {([validuser $nick])&&([matchattr $nick $UnoOpFlags $UnoChan])} {
  if {$UnoPaused == 0} {
   set UnoPaused 1
   UnoUnbindCmds
   unomsg "[unoad] \0030,4 Paused by $nick \003"
  } {
   set UnoPaused 0
   UnoBindCmds
   UnoAutoSkipReset
   unomsg "[unoad] \0030,4 Play resumed by $nick \003"
  }
 }
}

#
# Remove user from play
#
proc UnoRemove {nick uhost hand chan arg} {
 global UnoChan UnoOn UnoCycleTime UnoIDX UnoPlayers ThisPlayer ThisPlayerIDX RoundRobin UnoDeck DiscardPile UnoHand IsColorChange ColorPicker NickColor UnoOpFlags

 if {$chan != $UnoChan} {return}
 if {$UnoOn == 0} {return}

 regsub -all \[`,.!{}] $arg "" arg

 # Allow Ops To Remove Another Player
 set UnoOpRemove 0

 if {[string length $arg] > 0} {
  if {([validuser $nick])&&([matchattr $nick $UnoOpFlags $UnoChan])} {
   set UnoOpRemove 1
   set UnoOpNick $nick
   set nick $arg
  } {
   return
  }
 }

 set PlayerFound 0

 # Remove Player If Found - Put Cards Back To Bottom Of Deck

 set pcount 0
 while {[lindex $RoundRobin $pcount] != ""} {
  if {[string tolower [lindex $RoundRobin $pcount]] == [string tolower $nick]} {
   set PlayerFound 1
   set FoundIDX $pcount
   set nick [lindex $RoundRobin $pcount]
   break
  }
  incr pcount
 }

 if {$PlayerFound == 1} {
  if {$UnoOpRemove > 0} {
   unomsg "[nikclr $nick]\003 was removed from Uno by $UnoOpNick"
  } {
   unontc $nick "You are now removed from the current Uno game."
   unomsg "[nikclr $nick]\003 left Uno"
  }

  # Player Was ColorPicker

  if {$IsColorChange == 1} {
   if {$nick == $ColorPicker} {
    # Make A Color Choice
    set cip [UnoPickAColor]
    unomsg "[nikclr $nick]\003 was choosing a color... I randomly select $cip"
    set IsColorChange 0
   } {
    unolog "uno" "UnoRemove: IsColorChange Set but $nick not ColorPicker"
   }
  }

  if {$nick == $ThisPlayer} {
   UnoNextPlayer
   if {$UnoPlayers > 2} {
    unomsg "[nikclr $nick]\003 was the current player, continuing with [nikclr $ThisPlayer]\003"
   }
   UnoAutoSkipReset
  }

  set UnoPlayers [expr ($UnoPlayers -1)]

  # Remove Player From Game And Put Cards Back In Deck

  if {$UnoPlayers > 1} {
   set RoundRobin [lreplace ${RoundRobin} $FoundIDX $FoundIDX]
   set UnoIDX [lreplace ${UnoIDX} $FoundIDX $FoundIDX]
   lappend DiscardPile "$UnoHand($nick)"
   unset UnoHand($nick)
   unset NickColor($nick)
  }

  set pcount 0
  while {[lindex $RoundRobin $pcount] != ""} {
   if {[lindex $RoundRobin $pcount] == $ThisPlayer} {
    set ThisPlayerIDX $pcount
    break
   }
   incr pcount
  }

  if {$UnoPlayers == 1} {
   showwindefault $ThisPlayer
   UnoWin $ThisPlayer
   UnoCycle
   return
  }
  UnoRobotRestart
 } {
  # Player not in current game
  return
 }

 if {$UnoPlayers == 0} {
  unomsg "[unoad] \0030,10 No players - No winner - Recycling \003"
  UnoCycle
 }
 return
}

#
# Move to next player
#
proc UnoNextPlayer {} {
 global ThisPlayer ThisPlayerIDX RoundRobin
 incr ThisPlayerIDX
 if {$ThisPlayerIDX >= [llength $RoundRobin]} {set ThisPlayerIDX 0}
 set ThisPlayer [lindex $RoundRobin $ThisPlayerIDX]
}

#
# Pick a random color for skipped/removed players
#
proc UnoPickAColor {} {
 global PlayCard
 set ucolors "r g b y"
 set pcol [string tolower [lindex $ucolors [rand [llength $ucolors]]]]
 switch $pcol {
  "r" {set PlayCard "R"; return "\0030,4 Red \003"}
  "g" {set PlayCard "G"; return "\0030,3 Green \003"}
  "b" {set PlayCard "B"; return "\0030,12 Blue \003"}
  "y" {set PlayCard "Y"; return "\0031,8 Yellow \003"}
 }
}

#
# Robot picks a color by checking hand for 1st color card
# found with matching color, else picks color at random
#
proc UnoBotPickAColor {} {
 global PlayCard UnoHand ThisPlayer
 set CardCount 0
 while {$CardCount < [llength $UnoHand($ThisPlayer)]} {
  set thiscolor [string range [lindex $UnoHand($ThisPlayer) $CardCount] 0 0]
  switch $thiscolor {
   "R" {set PlayCard "R"; return "\0030,4 Red \003"}
   "G" {set PlayCard "G"; return "\0030,3 Green \003"}
   "B" {set PlayCard "B"; return "\0030,12 Blue \003"}
   "Y" {set PlayCard "Y"; return "\0031,8 Yellow \003"}
  }
  incr CardCount
 }
 set ucolors "r g b y"
 set pcol [string tolower [lindex $ucolors [rand [llength $ucolors]]]]
 switch $pcol {
  "r" {set PlayCard "R"; return "\0030,4 Red \003"}
  "g" {set PlayCard "G"; return "\0030,3 Green \003"}
  "b" {set PlayCard "B"; return "\0030,12 Blue \003"}
  "y" {set PlayCard "Y"; return "\0031,8 Yellow \003"}
 }
}

#
# Set robot for next turn
#
proc UnoRobotRestart {} {
 global UnoMode ThisPlayerIDX RobotRestartPeriod UnoBotTimer
 if {$UnoMode != 2} {return}
 if {![uno_isrobot $ThisPlayerIDX]} {return}
 set UnoBotTimer [utimer $RobotRestartPeriod UnoRobotPlayer]
}

#
# Reset autoskip timer
#
proc UnoAutoSkipReset {} {
 global AutoSkipPeriod UnoMode UnoSkipTimer
 catch {killtimer $UnoSkipTimer}
 if {$UnoMode == 2} {
  set UnoSkipTimer [timer $AutoSkipPeriod UnoAutoSkip]
 }
}

#
# Channel triggers
#

#
# Show current player order
#
proc UnoOrder {nick uhost hand chan arg} {
 global UnoChan UnoMode UnoPlayers RoundRobin
 if {($chan != $UnoChan)||($UnoMode < 2)} {return}
 unomsg "\0030,10 Player Order \[$UnoPlayers\]: \0030,6 $RoundRobin "
 return
}

#
# Show game running time
#
proc UnoTime {nick uhost hand chan arg} {
global UnoChan UnoMode
 if {($chan != $UnoChan)||($UnoMode != 2)} {return}
 set unotime "\0030,10 Game Time: \0030,6 [duration [game_time]] \003"
 unomsg "$unotime"
 return
}

#
# Show player what cards they hold
#
proc UnoShowCards {nick uhost hand chan arg} {
 global UnoChan UnoMode UnoHand ThisPlayerIDX
 if {($chan != $UnoChan)||($UnoMode != 2)} {return}
 if [info exist UnoHand($nick)] {
  set Card ""
  set ccnt 0
  while {[llength $UnoHand($nick)] != $ccnt} {
   set pcard [lindex $UnoHand($nick) $ccnt]
   append Card [CardColor $pcard]
   incr ccnt
  }
  if {![uno_isrobot $ThisPlayerIDX]} {
   unontc $nick "Hand: $Card\003"
  }
 }
 return
}

#
# Show current player
#
proc UnoTurn {nick uhost hand chan arg} {
 global UnoChan UnoMode ThisPlayer RoundRobin UnoMode
 if {($chan != $UnoChan)||($UnoMode != 2)} {return}
 if {[llength $RoundRobin] < 1 } {return}
 set info "\0030,10 Current Player: \0030,6 $ThisPlayer \003"
 unomsg "$info"
 return
}

#
# Show current top card
#
proc UnoTopCard {nick uhost hand chan arg} {
 global PlayCard UnoChan UnoMode
 if {($chan != $UnoChan)||($UnoMode != 2)} {return}
 set pcard $PlayCard
 set Card [CardColor $pcard]
 unomsg "\0030,10 Card In Play: \003 $Card \003"
 return
}

#
# Show card stats
#
proc UnoCardStats {nick uhost hand chan arg} {
 global UnoChan UnoMode CardStats
 if {($chan != $UnoChan)||($UnoMode != 2)} {return}
 set passdraw [format "%3.1f" [get_ratio $CardStats(passed) $CardStats(drawn)]]
 set skiprev [expr $CardStats(skips) +$CardStats(revs)]
 unomsg "\0030,10 Card Stats: \0030,6 Played:$CardStats(played)  Pass\/Draw Ratio:$passdraw\%  Skip\/Rev:$skiprev  DrawCards:$CardStats(draws)  WildCards:$CardStats(wilds) \003"
 return
}

#
# Card count
#
proc UnoCount {nick uhost hand chan arg} {
 global RoundRobin UnoHand UnoMode UnoChan
 if {($chan != $UnoChan)||($UnoMode != 2)} {return}
 set ordcnt 0
 set crdcnt ""
 while {[lindex $RoundRobin $ordcnt] != ""} {
  append crdcnt "\0030,10 [lindex $RoundRobin $ordcnt] \0030,6 [llength $UnoHand([lindex $RoundRobin $ordcnt])] Cards "
  incr ordcnt
 }
 unomsg "$crdcnt\003"
 return
}

#
# Show player's score
#
proc UnoWon {nick uhost hand chan arg} {
 global UnoScoreFile UnoPointsName

 regsub -all \[`,.!] $arg "" arg

 if {[string length $arg] == 0} {set arg $nick}

 set scorer [string tolower $arg]

 set pflag 0

 set f [open $UnoScoreFile r]
 while {[gets $f sc] != -1} {
  set cnick [string tolower [lindex [split $sc] 0]]
  if {$cnick == $scorer} {
   set pmsg "\0030,10 [lindex [split $sc] 0] \0030,6 [lindex $sc 2] $UnoPointsName in [lindex $sc 1] Games \003"
   set pflag 1
  }
 }
 close $f

 if {$pflag == 0} {
  set pmsg "\0030,10 $arg \0030,6 No Score \003"
 }
 unomsg "$pmsg"
 return
}

#
# Display current top10
#
proc UnoTopTen {nick uhost hand chan arg} {
 global UnoChan 
 if {$chan != $UnoChan} {return}
 UnoTop10 1
 return
}
proc UnoTopTenWon {nick uhost hand chan arg} {
 global UnoChan 
 if {$chan != $UnoChan} {return}
 UnoTop10 0
 return
}

#
# Display last month's top3
#
proc UnoTopThreeLast {nick uhost hand chan arg} {
 global UnoChan 
 if {$chan != $UnoChan} {return}
 UnoLastMonthTop3 $nick $uhost $hand $chan 0
 unomsg " "
 UnoLastMonthTop3 $nick $uhost $hand $chan 1
 return
}

#
# Display month fastest game 
#
proc UnoTopFast {nick uhost hand chan arg} {
 global UnoChan UnoFast
 if {$chan != $UnoChan} {return}
 unomsg "\0030,6 This Month's Fastest Game \0030,10 [lindex [split $UnoFast] 0] [duration [lindex $UnoFast 1]] \003"
 return
}

#
# Display month high score
#
proc UnoHighScore {nick uhost hand chan arg} {
 global UnoChan UnoHigh UnoPointsName
 if {$chan != $UnoChan} {return}
 unomsg "\0030,6 This Month's High Score \0030,10 [lindex [split $UnoHigh] 0] [lindex $UnoHigh 1] $UnoPointsName \003"
 return
}

#
# Display month most cards played
#
proc UnoPlayed {nick uhost hand chan arg} {
 global UnoChan UnoPlayed
 if {$chan != $UnoChan} {return}
 unomsg "\0030,6 This Month's Most Cards Played \0030,10 [lindex [split $UnoPlayed] 0] [lindex $UnoPlayed 1] Cards \003"
 return
}

#
# Show all-time records
#
proc UnoRecords {nick uhost hand chan arg} {
 global UnoChan UnoRecordFast UnoRecordHigh UnoRecordCard UnoRecordWins UnoRecordPlayed
 if {$chan != $UnoChan} {return}
 unomsg "\0030,6 All-Time Records: Points \0030,10 $UnoRecordCard \0030,6 Games \0030,10 $UnoRecordWins \0030,6 Fast \0030,10 [lindex $UnoRecordFast 0] [duration [lindex $UnoRecordFast 1]] \0030,6 High Score \0030,10 $UnoRecordHigh \0030,6 Cards Played \0030,10 $UnoRecordPlayed \003"
 return
}

#
# Display month top10
#
proc UnoTop10 {mode} {
 global UnoScoreFile unsortedscores UnoPointsName UnoRobot

 if {($mode < 0)||($mode > 1)} {set mode 0}

 switch $mode {
  0 {set winners "\0030,6 Top10 Game Wins "}
  1 {set winners "\0030,6 Top10 $UnoPointsName "}
 }

 if ![file exists $UnoScoreFile] {
  set f [open $UnoScoreFile w]
  puts $f "$UnoRobot 0 0"
  unomsg "\0030,10 The Score File Is Empty - Created A New One\003"
  close $f
  return
 }

 if [info exists unsortedscores] {unset unsortedscores}
 if [info exists top10] {unset top10}

 set f [open $UnoScoreFile r]
 while {[gets $f s] != -1} {
  switch $mode {
   0 {set unsortedscores([lindex [split $s] 0]) [lindex $s 1]}
   1 {set unsortedscores([lindex [split $s] 0]) [lindex $s 2]}
  }
 }
 close $f

 for {set s 0} {$s < 10} {incr s} {
  set top10($s) "Nobody 0"
 }

 set s 0
 foreach n [lsort -decreasing -command UnoSortScores [array names unsortedscores]] {
  set top10($s) "$n $unsortedscores($n)"
  incr s
 }

 for {set s 0} {$s < 10} {incr s} {
  if {[lindex $top10($s) 1] > 0} {
   append winners "\0030,6 #[expr $s +1] \0030,10 [lindex [split $top10($s)] 0] [lindex $top10($s) 1] "
  } {
   append winners "\0030,6 #[expr $s +1] \0030,10 Nobody 0 "
  }
 }
 unomsg "$winners\003"
 return
}

#
# Last month's top3
#
proc UnoLastMonthTop3 {nick uhost hand chan arg} {
 global UnoChan UnoLastMonthCards UnoLastMonthGames UnoPointsName
 if {$chan != $UnoChan} {return}
 if {$arg == 0} {
  if [info exists UnoLastMonthCards] {
   set UnoTop3 "\0030,6 Last Month's Top 3 $UnoPointsName Won "
   for { set s 0} { $s < 3 } { incr s} {
    append UnoTop3 "\0030,6 #[expr $s +1] \0030,10 $UnoLastMonthCards($s) "
   }
   unomsg "$UnoTop3"
  }
 } {
  if [info exists UnoLastMonthGames] {
   set UnoTop3 "\0030,6 Last Month's Top 3 Games Won "
   for { set s 0} { $s < 3 } { incr s} {
    append UnoTop3 "\0030,6 #[expr $s +1] \0030,10 $UnoLastMonthGames($s) "
   }
   unomsg "$UnoTop3"
  }
 }
}

#
# Show game help
#
proc UnoCmds {nick uhost hand chan arg} {
 global UnoChan
 if {$chan != $UnoChan} {return}
 unontc $nick "Uno Commands: !uno !stop !remove \[nick\] !unowon \[nick\] !unocmds"
 unontc $nick "Uno Stats: !unotop10 !unotop3last !unofast !unohigh !unorecords"
 unontc $nick "Uno Card Commands: jo=join pl=play dr=draw pa=pass co=color"
 unontc $nick "Uno Chan Commands: ca=cards cd=card tu=turn od=order ct=count st=stats ti=time"
 return
}

#
# Uno version
#
proc UnoVersion {nick uhost hand chan arg} {
 global UnoVersion
 unomsg "[unoad]\003 \0030,6 v$UnoVersion by GoodDay \003"
 return
}

#
# Read score file
#
proc UnoReadScores {} {
 global unogameswon unoptswon UnoScoreFile UnoRobot

 if [info exists unogameswon] { unset unogameswon }
 if [info exists unoptswon] { unset unoptswon }

 if ![file exists $UnoScoreFile] {
  set f [open $UnoScoreFile w]
  puts $f "$UnoRobot 0 0"
  close $f
 }

 set f [open $UnoScoreFile r]
 while {[gets $f s] != -1} {
  set unogameswon([lindex [split $s] 0]) [lindex $s 1]
  set unoptswon([lindex [split $s] 0]) [lindex $s 2]
 }
 close $f

 return
}

#
# Clear top10 and write monthly scores
#
proc UnoNewMonth {min hour day month year} {
 global unsortedscores unogameswon unoptswon UnoLastMonthCards UnoLastMonthGames UnoScoreFile UnoRobot
 global UnoFast UnoHigh UnoPlayed UnoRecordFast UnoRecordHigh UnoRecordPlayed UnoRecordCard UnoRecordWins

 set lmonth [UnoLastMonthName $month]

 unomsg "[unoad] \0030,4 Clearing monthly scores \003"

 set UnoMonthFileName "$UnoScoreFile.$lmonth"

 # Read Current Scores

 UnoReadScores

 # Write To Old Month File

 if ![file exists $UnoMonthFileName] {
  set f [open $UnoMonthFileName w]
  foreach n [array names unogameswon] {
   puts $f "$n $unogameswon($n) $unoptswon($n)"
  }
  close $f
 }

 # Find Top 3 Card Holders and Game Winners

 set mode 0 

 while {$mode < 2} {
  if [info exists unsortedscores] {unset unsortedscores}
  if [info exists top10] {unset top10}

  set f [open $UnoScoreFile r]
  while {[gets $f s] != -1} {
   switch $mode {
    0 {set unsortedscores([lindex [split $s] 0]) [lindex $s 1]}
    1 {set unsortedscores([lindex [split $s] 0]) [lindex $s 2]}
   }
  }
  close $f

  set s 0
  foreach n [lsort -decreasing -command UnoSortScores [array names unsortedscores]] {
   set top10($s) "$n $unsortedscores($n)"
   incr s
  }

  for {set s 0} {$s < 3} {incr s} {
   if {[lindex $top10($s) 1] > 0} {
    switch $mode {
     0 {set UnoLastMonthGames($s) "[lindex [split $top10($s)] 0] [lindex $top10($s) 1]"}
     1 {set UnoLastMonthCards($s) "[lindex [split $top10($s)] 0] [lindex $top10($s) 1]"}
    }
   } {
    switch $mode {
     0 {set UnoLastMonthGames($s) "Nobody 0"}
     1 {set UnoLastMonthCards($s) "Nobody 0"}
    }
   }
  }
  incr mode
 }

 # Update records
 if {[lindex $UnoFast 1] < [lindex $UnoRecordFast 1]} {set UnoRecordFast $UnoFast}
 if {[lindex $UnoHigh 1] > [lindex $UnoRecordHigh 1]} {set UnoRecordHigh $UnoHigh}
 if {[lindex $UnoPlayed 1] > [lindex $UnoRecordPlayed 1]} {set UnoRecordPlayed $UnoPlayed}
 if {[lindex $UnoLastMonthCards(0) 1] > [lindex $UnoRecordCard 1]} {set UnoRecordCard $UnoLastMonthCards(0)}
 if {[lindex $UnoLastMonthGames(0) 1] > [lindex $UnoRecordWins 1]} {set UnoRecordWins $UnoLastMonthGames(0)}

 # Wipe last months records
 set UnoFast "$UnoRobot 60"
 set UnoHigh "$UnoRobot 100"
 set UnoPlayed "$UnoRobot 100"

 # Save Top3 And Records To Config File
 Uno_WriteCFG

 # Wipe This Months Score File

 set f [open $UnoScoreFile w]
 puts $f "$UnoRobot 0 0"
 close $f

 unolog "uno" "Cleared monthly scores"
 return
}

#
# Update score of winning player
#
proc UnoUpdateScore {winner cardtotals} {
 global unogameswon unoptswon UnoScoreFile

 UnoReadScores

 if {[info exists unogameswon($winner)]} {
  incr unogameswon($winner)
 } {
  set unogameswon($winner) 1
 }

 if {[info exists unoptswon($winner)]} {
  incr unoptswon($winner) $cardtotals
 } {
  set unoptswon($winner) $cardtotals
 }

 set f [open $UnoScoreFile w]
 foreach n [array names unogameswon] {
  puts $f "$n $unogameswon($n) $unoptswon($n)"
 }
 close $f

 return
}

#
# Display winner and game statistics
#
proc UnoWin {winner} {
 global UnoHand ThisPlayer RoundRobin UnoPointsName CardStats UnoMode UnoCycleTime UnoFast UnoHigh UnoPlayed UnoBonus
 
 set cardtotals 0
 set UnoMode 3
 set ThisPlayerIDX 0
 set needCFGWrite 0

 set UnoTime [game_time]

 unomsg "\0030,6 Card Totals \003"

 # Total up all player's cards

 while {$ThisPlayerIDX != [llength $RoundRobin]} {
  set Card ""
  set ThisPlayer [lindex $RoundRobin $ThisPlayerIDX]

  if {$ThisPlayer != $winner} {
   set ccount 0
   while {[lindex $UnoHand($ThisPlayer) $ccount] != ""} {
    set cardtotal [lindex $UnoHand($ThisPlayer) $ccount]
    set c1 [string range $cardtotal 0 0]
    set c2 [string range $cardtotal 1 1]
    set cardtotal 0

    if {$c1 == "W"} {
     set cardtotal 50
    } {
     switch $c2 {
      "S" {set cardtotal 20}
      "R" {set cardtotal 20}
      "D" {set cardtotal 20}
      default {set cardtotal $c2}
     }
    }
    set cardtotals [expr $cardtotals + $cardtotal]
    incr ccount
   }
   set Card [CardColorAll $ThisPlayer]
   unomsg "[strpad [nikclr $ThisPlayer] 12] $Card"
  }
  incr ThisPlayerIDX
 }

 # Check high score record
 set HighScore [lindex $UnoHigh 1]
 if {$cardtotals > $HighScore} {
  unomsg "\0030,4 $winner Broke The High Score Record And Gets $UnoBonus Bonus $UnoPointsName \003"
  set UnoHigh "$winner $cardtotals"
  incr cardtotals $UnoBonus
  set needCFGWrite 1
 }
 # Check played cards record
 set HighPlayed [lindex $UnoPlayed 1]
 if {$CardStats(played) > $HighPlayed} {
  unomsg "\0030,4 $winner Broke The Most Cards Played Record And Gets $UnoBonus Bonus $UnoPointsName \003"
  set UnoPlayed "$winner $CardStats(played)"
  incr cardtotals $UnoBonus
  set needCFGWrite 1
 }
 # Check fast game record
 set FastRecord [lindex $UnoFast 1]
 if {$UnoTime < $FastRecord} {
  unomsg "\0030,4 $winner Broke The Fast Record And Gets $UnoBonus Bonus $UnoPointsName \003"
  incr cardtotals $UnoBonus
  set UnoFast "$winner $UnoTime"
  set needCFGWrite 1
 }

 # Winner
 unomsg "\0030,10 $winner \0030,6 $cardtotals $UnoPointsName In [duration $UnoTime] \003"

 # Card stats
 set passdraw [format "%3.1f" [get_ratio $CardStats(passed) $CardStats(drawn)]]
 set skiprev [expr $CardStats(skips) +$CardStats(revs)]
 unomsg "\0030,10 Cardstats \0030,6 Played:$CardStats(played)  Pass\/Draw Ratio:$passdraw\%  Skip\/Rev:$skiprev  DrawCards:$CardStats(draws)  WildCards:$CardStats(wilds) \003"
 unomsg "[unoad] \0030,3 Next Game In $UnoCycleTime Seconds \003"

 # Write scores
 UnoUpdateScore $winner $cardtotals

 # Write records
 if {$needCFGWrite > 0} {Uno_WriteCFG}

 return
}

#
# Re-Shuffle deck
#
proc UnoShuffle {len} {
 global UnoDeck DiscardPile
 if {[llength $UnoDeck] >= $len} { return }
 unomsg "[unoad] \0030,4 Re-Shuffling Uno Deck \003"
 lappend DiscardPile "$UnoDeck"
 set UnoDeck ""
 set NewDeckSize [llength $DiscardPile]
 while {[llength $UnoDeck] != $NewDeckSize} {
  set pcardnum [rand [llength $DiscardPile]]
  set pcard [lindex $DiscardPile $pcardnum]
  lappend UnoDeck "$pcard"
  set DiscardPile [lreplace ${DiscardPile} $pcardnum $pcardnum]
 }
 return
}

#
# Read config file
#
proc Uno_ReadCFG {} {
 global UnoCFGFile UnoLastMonthCards UnoLastMonthGames UnoPointsName UnoScoreFile UnoRobot UnoChan UnoFast UnoHigh UnoPlayed UnoStopAfter UnoBonus
 global UnoRecordHigh UnoRecordFast UnoRecordCard UnoRecordWins UnoRecordPlayed UnoWildDrawTwos
 if {[file exist $UnoCFGFile]} {
  set f [open $UnoCFGFile r]
  while {[gets $f s] != -1} {
   set kkey [string tolower [lindex [split $s "="] 0]]
   set kval [lindex [split $s "="] 1]
   switch $kkey {
    botname {set UnoRobot $kval}
    channel {set UnoChan $kval}
    points {set UnoPointsName $kval}
    scorefile {set UnoScoreFile $kval}
    stopafter {set UnoStopAfter $kval}
    wilddrawtwos {set UnoWildDrawTwos $kval}
    lastmonthcard1 {set UnoLastMonthCards(0) $kval}
    lastmonthcard2 {set UnoLastMonthCards(1) $kval}
    lastmonthcard3 {set UnoLastMonthCards(2) $kval}
    lastmonthwins1 {set UnoLastMonthGames(0) $kval}
    lastmonthwins2 {set UnoLastMonthGames(1) $kval}
    lastmonthwins3 {set UnoLastMonthGames(2) $kval}
    fast {set UnoFast $kval}
    high {set UnoHigh $kval}
    played {set UnoPlayed $kval}
    bonus {set UnoBonus $kval}
    recordhigh {set UnoRecordHigh $kval}
    recordfast {set UnoRecordFast $kval}
    recordcard {set UnoRecordCard $kval}
    recordwins {set UnoRecordWins $kval}
    recordplayed {set UnoRecordPlayed $kval}
   }
  }
  close $f
  if {$UnoStopAfter < 0} {set UnoStopAfter 0}
  if {$UnoBonus < 0} {set UnoBonus 1000}
  if {($UnoWildDrawTwos < 0)||($UnoWildDrawTwos > 1)} {set UnoWildDrawTwos 0}
  return
 }
 putcmdlog "\[Uno\] Config file $UnoCFGFile not found... saving defaults"
 Uno_WriteCFG
 return
}

#
# Write config file
#
proc Uno_WriteCFG {} {
 global UnoCFGFile UnoLastMonthCards UnoLastMonthGames UnoPointsName UnoScoreFile UnoRobot UnoChan UnoFast UnoHigh UnoPlayed UnoStopAfter UnoBonus
 global UnoRecordHigh UnoRecordFast UnoRecordCard UnoRecordWins UnoRecordPlayed UnoWildDrawTwos
 set f [open $UnoCFGFile w]
 puts $f "# This file is automatically overwritten"
 puts $f "BotName=$UnoRobot"
 puts $f "Channel=$UnoChan"
 puts $f "Points=$UnoPointsName"
 puts $f "ScoreFile=$UnoScoreFile"
 puts $f "StopAfter=$UnoStopAfter"
 puts $f "WildDrawTwos=$UnoWildDrawTwos"
 puts $f "LastMonthCard1=$UnoLastMonthCards(0)"
 puts $f "LastMonthCard2=$UnoLastMonthCards(1)"
 puts $f "LastMonthCard3=$UnoLastMonthCards(2)"
 puts $f "LastMonthWins1=$UnoLastMonthGames(0)"
 puts $f "LastMonthWins2=$UnoLastMonthGames(1)"
 puts $f "LastMonthWins3=$UnoLastMonthGames(2)"
 puts $f "Fast=$UnoFast"
 puts $f "High=$UnoHigh"
 puts $f "Played=$UnoPlayed"
 puts $f "Bonus=$UnoBonus"
 puts $f "RecordHigh=$UnoRecordHigh"
 puts $f "RecordFast=$UnoRecordFast"
 puts $f "RecordCard=$UnoRecordCard"
 puts $f "RecordWins=$UnoRecordWins"
 puts $f "RecordPlayed=$UnoRecordPlayed"
 close $f
 return
}

#
# Score advertiser
#
proc UnoScoreAdvertise {} {
 global UnoChan UnoAdNumber UnoRobot
 unomsg " "
 switch $UnoAdNumber {
  0 {UnoTop10 0}
  1 {UnoLastMonthTop3 $UnoRobot none none $UnoChan 0}
  2 {UnoTop10 1}
  3 {UnoRecords $UnoRobot none none $UnoChan ""}
  4 {UnoPlayed $UnoRobot none none $UnoChan ""}
  5 {UnoHighScore $UnoRobot none none $UnoChan ""}
  6 {UnoTopFast $UnoRobot none none $UnoChan ""}
 }
 incr UnoAdNumber
 if {$UnoAdNumber > 6} {set UnoAdNumber 0}
 return
}

#
# Color all cards in hand
#
proc CardColorAll {cplayer} {
 global UnoHand
 set pCard ""
 set ccount 0
 while {[llength $UnoHand($cplayer)] != $ccount} {
  append pCard [CardColor [lindex $UnoHand($cplayer) $ccount]]
  incr ccount
 }
 return $pCard
}

#
# Color a single card
#
proc CardColor {pcard} {
  set cCard ""
  set c2 [string range $pcard 1 1]
  switch [string range $pcard 0 0] {
   "W" {
     if {$c2 == "D"} {
      append cCard "[wildf]"
     } {	
      append cCard "[wild]"
     }
     return $cCard
    }
   "Y" {append cCard " \0031,8 Yellow "}
   "R" {append cCard " \0030,4 Red "}
   "G" {append cCard " \0030,3 Green "}
   "B" {append cCard " \0030,12 Blue "}
  }
  switch $c2 {
   "S" {append cCard "\002Skip\002 \003 "}
   "R" {append cCard "\002Reverse\002 \003 "}
   "D" {append cCard "\002Draw Two\002 \003 "}
   default {append cCard "$c2 \003 "}
  }
  return $cCard
}

#
# Check if player has Uno
#
proc check_hasuno {cplayer} {
 global UnoHand
 if {[llength $UnoHand($cplayer)] > 1} {return}
 hasuno $cplayer
 return
}

#
# Check for winner
#
proc check_unowin {cplayer ccard} {
 global UnoHand
 if {[llength $UnoHand($cplayer)] > 0} {return 0}
 return 1
}

#
# Show player what cards they have
#
proc showcards {idx pcards} {
 global UnoIDX
 if {[uno_isrobot $idx]} {return}
 unontc [lindex $UnoIDX $idx] "Hand: $pcards"
}

#
# Check if this is the robot player
#
proc uno_isrobot {cplayerIDX} {
 global RoundRobin UnoRobot UnoMaxNickLen
 if {[string range [lindex $RoundRobin $cplayerIDX] 0 $UnoMaxNickLen] != $UnoRobot} {return 0}
 return 1
}

# Show played card
proc playcard {who crd nplayer} {
 unomsg "[nikclr $who]\003 plays $crd \003to [nikclr $nplayer]\003"
}

# Show played draw card
proc playdraw {who crd dplayer nplayer} {
 unomsg "[nikclr $who]\003 plays $crd [nikclr $dplayer]\003 draws \002two cards\002 and is skipped - Current Player: [nikclr $nplayer]\003"
}

# Show played wildcard
proc playwild {who chooser} {
 unomsg "[nikclr $who]\003 plays [wild] Choose a color [nikclr $chooser]\003"
}

# Show played wild draw four
proc playwildfour {who skipper chooser} {
 unomsg "[nikclr $who]\003 plays [wildf] [nikclr $skipper]\003 draws \002four cards\002 and is skipped - Choose a color [nikclr $chooser]\003"
}

# Show played skip card
proc playskip {who crd skipper nplayer} {
 unomsg "[nikclr $who]\003 plays $crd\003 and skips [nikclr $skipper]\003 to [nikclr $nplayer]\003"
}

proc showwhodrew {who} {
 unomsg "[nikclr $who]\003 \002drew\002 a card"
}

proc playpass {who nplayer} {
 unomsg "[nikclr $who]\003 \002passes\002 to [nikclr $nplayer]\003"
}

proc botplaywild {who chooser ncolr nplayer} {
 unomsg "[nikclr $who]\003 plays [wild] and chooses $ncolr \003 Current Player: [nikclr $nplayer]\003"
}

# Show played wild draw four
proc botplaywildfour {who skipper chooser choice nplayer} {
 unomsg "[nikclr $who]\003 plays [wildf] [nikclr $skipper]\003 draws \002four cards\002 and is skipped. [nikclr $chooser]\003 chooses $choice\003 Current Player: [nikclr $nplayer]\003"
}

# Show a player what they drew
proc showdraw {idx crd} {
 global UnoIDX
 if {[uno_isrobot $idx]} {return}
 unontc [lindex $UnoIDX $idx] "Draw: $crd"
}

# Show Win 
proc showwin {who crd} {
 unomsg "[nikclr $who]\003 plays $crd \003and \002\00309W\00312i\00313n\00308s\002 [unoad]\003"
}

# Show Win by default
proc showwindefault {who} {
 unomsg "[nikclr $who] \002\00309W\00312i\00313n\00308s [unoad]\002\003 By Default \003"
}

# Player Has Uno
proc hasuno {who} {
 global UnoChan
 putquick "PRIVMSG $UnoChan :\001ACTION says [nikclr $who] \002\00309H\00312a\00313s \00309U\00312n\00313o\00308! \002\003\001"
}

#
# Utility Functions
#

# Check if a timer exists
proc unotimerexists {cmd} {
 foreach i [timers] {
  if {![string compare $cmd [lindex $i 1]]} then {
   return [lindex $i 2]
  }
 }
 return
}

# Sort Scores
proc UnoSortScores {s1 s2} {
 global unsortedscores
 if {$unsortedscores($s1) >  $unsortedscores($s2)} {return 1}
 if {$unsortedscores($s1) <  $unsortedscores($s2)} {return -1}
 if {$unsortedscores($s1) == $unsortedscores($s2)} {return 0}
}

# Calculate Game Running Time
proc game_time {} {
 global UnoStartTime
 set UnoCurrentTime [unixtime]
 set gt [expr ($UnoCurrentTime - $UnoStartTime)]
 return $gt
}

# Colorize Nickname
proc nikclr {nick} {
 global NickColor
 return "\003$NickColor($nick)$nick"
}
proc colornick {pnum} {
 global UnoNickColour
 set c [lindex $UnoNickColour [expr $pnum-1]]
 set nik [format "%02d" $c]
 return $nik
}

# Ratio Of Two Numbers
proc get_ratio {num den} {
 set n 0.0
 set d 0.0
 set n [expr $n +$num]
 set d [expr $d +$den]
 if {$d == 0} {return 0}
 set ratio [expr (($n /$d) *100.0)]
 return $ratio
}

# Name Of Last Month
proc UnoLastMonthName {month} {
 switch $month {
  00 {return "Dec"}
  01 {return "Jan"}
  02 {return "Feb"}
  03 {return "Mar"}
  04 {return "Apr"}
  05 {return "May"}
  06 {return "Jun"}
  07 {return "Jul"}
  08 {return "Aug"}
  09 {return "Sep"}
  10 {return "Oct"}
  11 {return "Nov"}
  default {return "???"}
 }
}

# String Pad
proc strpad {str len} {
 set slen [string length $str]
 if {$slen > $len} {return $str}
 while {$slen < $len} {
  append str " "
  incr slen
 }
 return $str
}

# Uno!
proc unoad {} {
 return "\002\0033U\00312N\00313O\00308!\002"
}

# Wild Card
proc wild {} {
 return " \0031,8 \002W\0030,3I \0030,4L\0030,12D\002 \003 "
}

# Wild Draw Four Card
proc wildf {} {
 return " \0031,8 \002W\0030,3I \0030,4L\0030,12D \0031,8D\0030,3r\0030,4a\0030,12w \0031,8F\0030,3o\0030,4u\0030,12r\002 \003 "
}

#
# Channel And DCC Messages
#

proc unomsg {what} {
 global UnoChan
 putquick "PRIVMSG $UnoChan :$what"
}

proc unontc {who what} {
 global UnoNTC
 putquick "$UnoNTC $who :$what"
}

proc unolog {who what} {
 putcmdlog "\[$who\] $what"
}

#
# DCC Routines
#

# Show All Players Cards
proc dccUnoHands {hand idx arg} {
 global UnoHand RoundRobin
 set n 0
 while {$n != [llength $RoundRobin]} {
  set un [lindex $RoundRobin $n]
  unolog $un $UnoHand($un)
  incr n
 }
}

# Rehash Configuration
proc dcc_unorehash {hand idx arg} {
 unolog "$hand" "Rehashing UNO Configuration"
 Uno_ReadCFG
 return
}

Uno_ReadCFG

UnoReadScores

putlog "Loaded Color Uno $UnoVersion (C) 2004 by GoodDay"
