173 lines
4.4 KiB
Tcl
Executable File
173 lines
4.4 KiB
Tcl
Executable File
#!/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]
|