#!/usr/bin/env jimsh # Scoundrel roguelike solitaire game port to Jim Tcl # Created by Luxferre in 2026, released into the public domain # helpers proc shuffle list { set n [llength $list] loop i 1 $n { set j $(int(rand() * $n)) set temp [lindex $list $i] lset list $i [lindex $list $j] lset list $j $temp } return $list } proc get_valid_choice {prompt pat} { set c -- puts -nonewline [format "%s " $prompt] stdout flush stdin tty input raw while {$c ni $pat} { set c [string tolower [stdin read 1]] } stdin tty input cooked return $c } # variables and states set score -208 set hp 20 set can_run 1 set engaged 0 set drank 0 set weapon 0 set durability 0 set rooms_clrd 0 set last_potion_val 0 # deck and room set deck [shuffle [concat [range 1 14] [range 1 32]]] set room {} # game logic functions proc game_field_display {} { global hp weapon durability room deck can_run engaged puts "--------------------------" puts [format "H%02d | W%02d | D%02d | Deck: %02d" $hp $weapon $durability [llength $deck]] puts "--------------------------" foreach x $room { if $($x < 14) { puts -nonewline [format "M%02d " $($x + 1)] } elseif $($x < 23) { puts -nonewline [format "W%02d " $($x - 12)] } else { puts -nonewline [format "H%02d " $($x - 21)] } } puts -nonewline "\n 1 2 3 4" if {$can_run == 1 && $engaged == 0} {puts -nonewline " r)un->"} } # monster handling logic (adds monster value to the score) proc handle_monster {val} { global weapon durability hp score set healthlost $val puts [format "You encounter a monster of strength %d." $val] if {$weapon > 0 && $durability >= $val} { if {[get_valid_choice "Use weapon? (y/n)" "y n"] == "y"} { set healthlost $($val - $weapon) if {$healthlost < 0} {set healthlost 0} puts [format "\nYou fight the monster with your %d-level weapon." $weapon] set durability $($val - 1) if {$durability < 2} { set healthlost 0 set weapon 0 puts "Your weapon fully breaks!" } } else {puts "\nYou fight the monster barehanded."} } else {puts "You fight the monster barehanded."} set hp $($hp - $healthlost) if {$hp < 0} {set hp 0} puts [format "Lost %d HP. New HP: %d" $healthlost $hp] incr score $val } # weapon handling logic proc handle_weapon {val} { global weapon durability set weapon $val set durability 14 puts [format "Equipped a %d-level weapon." $weapon] } # potion handling logic proc handle_potion {val} { global hp drank deck room if {$drank > 0} { puts "Already drank a potion here! Discarding..." } else { if {[llength $deck] == 0 && [llength $room] == 0} {set last_potion_val $val} incr hp $val if {$hp > 20} {set hp 20} set drank 1 puts [format "Drank a %d-level potion. New HP: %d" $val $hp] } } # game banner puts "----- Scoundrel 2026 -----" puts " Jim Tcl port by Luxferre" puts " Good luck!" # main game loop while {([llength $deck] + [llength $room]) > 0 && $hp > 0} { if {$engaged == 0} { while {[llength $deck] > 0 && [llength $room] < 4} { lappend room [lindex $deck 0] set deck [lreplace $deck 0 0] } } game_field_display set chs {1 2 3 4 q} if {$can_run == 1 && $engaged == 0} {set chs {1 2 3 4 q r}} set ch [get_valid_choice {} $chs] puts {} if {$ch == "q"} { if {[get_valid_choice "Really quit? (y/n)" "y n"] == "y"} { puts "\nQuitting!" exit } } elseif {$ch == "r"} { set can_run 0 while {[llength $room] > 0} { set idx [rand 0 [llength $room]] lappend deck [lindex $room $idx] set room [lreplace $room $idx $idx] } puts "You run from the room." } else { incr ch -1 set item [lindex $room $ch] if {$item > 0} { set engaged 1 set room [lreplace $room $ch $ch] if {$item < 14} { handle_monster $($item + 1) } elseif {$item < 23} { handle_weapon $($item - 12) } else {handle_potion $($item - 21)} if {[llength $deck] > 0 && [llength $room] == 1} { set can_run 1 set engaged 0 set drank 0 incr rooms_clrd } } } } # now score and output the game result if {$hp > 0} { set score $hp if {$hp == 20} {incr score $last_potion_val} incr rooms_clrd puts -nonewline "You win!" } else { puts -nonewline "You lose!" } puts [format " Your score: %d. Rooms cleared: %d" $score $rooms_clrd]