1*906afcb8SAndy Fiddaman#!/usr/bin/ksh93 2*906afcb8SAndy Fiddaman 3*906afcb8SAndy Fiddaman# 4*906afcb8SAndy Fiddaman# CDDL HEADER START 5*906afcb8SAndy Fiddaman# 6*906afcb8SAndy Fiddaman# The contents of this file are subject to the terms of the 7*906afcb8SAndy Fiddaman# Common Development and Distribution License (the "License"). 8*906afcb8SAndy Fiddaman# You may not use this file except in compliance with the License. 9*906afcb8SAndy Fiddaman# 10*906afcb8SAndy Fiddaman# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11*906afcb8SAndy Fiddaman# or http://www.opensolaris.org/os/licensing. 12*906afcb8SAndy Fiddaman# See the License for the specific language governing permissions 13*906afcb8SAndy Fiddaman# and limitations under the License. 14*906afcb8SAndy Fiddaman# 15*906afcb8SAndy Fiddaman# When distributing Covered Code, include this CDDL HEADER in each 16*906afcb8SAndy Fiddaman# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17*906afcb8SAndy Fiddaman# If applicable, add the following below this CDDL HEADER, with the 18*906afcb8SAndy Fiddaman# fields enclosed by brackets "[]" replaced with your own identifying 19*906afcb8SAndy Fiddaman# information: Portions Copyright [yyyy] [name of copyright owner] 20*906afcb8SAndy Fiddaman# 21*906afcb8SAndy Fiddaman# CDDL HEADER END 22*906afcb8SAndy Fiddaman# 23*906afcb8SAndy Fiddaman 24*906afcb8SAndy Fiddaman# 25*906afcb8SAndy Fiddaman# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 26*906afcb8SAndy Fiddaman# 27*906afcb8SAndy Fiddaman 28*906afcb8SAndy Fiddaman# 29*906afcb8SAndy Fiddaman# gnaw - a simple ksh93 technology demo 30*906afcb8SAndy Fiddaman# 31*906afcb8SAndy Fiddaman# Note that this script has been written with the main idea to show 32*906afcb8SAndy Fiddaman# many of ksh93's new features (comparing to ksh88/bash) and not 33*906afcb8SAndy Fiddaman# as an example of efficient&&clean script code (much of the code 34*906afcb8SAndy Fiddaman# could be done more efficient using compound variables, this script 35*906afcb8SAndy Fiddaman# focus is the usage of associative arrays). 36*906afcb8SAndy Fiddaman# 37*906afcb8SAndy Fiddaman 38*906afcb8SAndy Fiddaman# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant 39*906afcb8SAndy Fiddamanexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin 40*906afcb8SAndy Fiddaman 41*906afcb8SAndy Fiddaman# Make sure all math stuff runs in the "C" locale to avoid problems 42*906afcb8SAndy Fiddaman# with alternative # radix point representations (e.g. ',' instead of 43*906afcb8SAndy Fiddaman# '.' in de_DE.*-locales). This needs to be set _before_ any 44*906afcb8SAndy Fiddaman# floating-point constants are defined in this script). 45*906afcb8SAndy Fiddamanif [[ "${LC_ALL}" != "" ]] ; then 46*906afcb8SAndy Fiddaman export \ 47*906afcb8SAndy Fiddaman LC_MONETARY="${LC_ALL}" \ 48*906afcb8SAndy Fiddaman LC_MESSAGES="${LC_ALL}" \ 49*906afcb8SAndy Fiddaman LC_COLLATE="${LC_ALL}" \ 50*906afcb8SAndy Fiddaman LC_CTYPE="${LC_ALL}" 51*906afcb8SAndy Fiddaman unset LC_ALL 52*906afcb8SAndy Fiddamanfi 53*906afcb8SAndy Fiddamanexport LC_NUMERIC=C 54*906afcb8SAndy Fiddaman 55*906afcb8SAndy Fiddamanfunction print_setcursorpos 56*906afcb8SAndy Fiddaman{ 57*906afcb8SAndy Fiddaman print -n -- "${vtcode[cup_${1}_${2}]}" 58*906afcb8SAndy Fiddaman} 59*906afcb8SAndy Fiddaman 60*906afcb8SAndy Fiddamanfunction beep 61*906afcb8SAndy Fiddaman{ 62*906afcb8SAndy Fiddaman ${quiet} || print -n -- "${vtcode["bel"]}" 63*906afcb8SAndy Fiddaman} 64*906afcb8SAndy Fiddaman 65*906afcb8SAndy Fiddamanfunction fatal_error 66*906afcb8SAndy Fiddaman{ 67*906afcb8SAndy Fiddaman print -u2 "${progname}: $*" 68*906afcb8SAndy Fiddaman exit 1 69*906afcb8SAndy Fiddaman} 70*906afcb8SAndy Fiddaman 71*906afcb8SAndy Fiddaman# Get terminal size and put values into a compound variable with the integer 72*906afcb8SAndy Fiddaman# members "columns" and "lines" 73*906afcb8SAndy Fiddamanfunction get_term_size 74*906afcb8SAndy Fiddaman{ 75*906afcb8SAndy Fiddaman nameref rect=$1 76*906afcb8SAndy Fiddaman 77*906afcb8SAndy Fiddaman rect.columns=${ tput cols ; } || return 1 78*906afcb8SAndy Fiddaman rect.lines=${ tput lines ; } || return 1 79*906afcb8SAndy Fiddaman 80*906afcb8SAndy Fiddaman return 0 81*906afcb8SAndy Fiddaman} 82*906afcb8SAndy Fiddaman 83*906afcb8SAndy Fiddamanfunction print_levelmap 84*906afcb8SAndy Fiddaman{ 85*906afcb8SAndy Fiddaman integer screen_y_offset=$1 86*906afcb8SAndy Fiddaman integer start_y_pos=$2 # start at this line in the map 87*906afcb8SAndy Fiddaman integer max_numlines=$3 # maximum lines we're allowed to render 88*906afcb8SAndy Fiddaman integer x 89*906afcb8SAndy Fiddaman integer y 90*906afcb8SAndy Fiddaman typeset line="" 91*906afcb8SAndy Fiddaman 92*906afcb8SAndy Fiddaman print_setcursorpos 0 ${screen_y_offset} 93*906afcb8SAndy Fiddaman 94*906afcb8SAndy Fiddaman for (( y=start_y_pos; (y-start_y_pos) < max_numlines && y < levelmap["max_y"] ; y++ )) ; do 95*906afcb8SAndy Fiddaman line="" 96*906afcb8SAndy Fiddaman for (( x=0 ; x < levelmap["max_x"] ; x++ )) ; do 97*906afcb8SAndy Fiddaman line+="${levelmap["${x}_${y}"]}" 98*906afcb8SAndy Fiddaman done 99*906afcb8SAndy Fiddaman 100*906afcb8SAndy Fiddaman print -- "${line} " 101*906afcb8SAndy Fiddaman done 102*906afcb8SAndy Fiddaman 103*906afcb8SAndy Fiddaman # print lines filled with spaces for each line not filled 104*906afcb8SAndy Fiddaman # by the level map 105*906afcb8SAndy Fiddaman line="${vtcode["spaceline"]:0:${levelmap["max_x"]}}" 106*906afcb8SAndy Fiddaman for (( ; (y-start_y_pos) < max_numlines ; y++ )) ; do 107*906afcb8SAndy Fiddaman print -- "${line} " 108*906afcb8SAndy Fiddaman done 109*906afcb8SAndy Fiddaman return 0 110*906afcb8SAndy Fiddaman} 111*906afcb8SAndy Fiddaman 112*906afcb8SAndy Fiddamanfunction level_completed 113*906afcb8SAndy Fiddaman{ 114*906afcb8SAndy Fiddaman integer i 115*906afcb8SAndy Fiddaman typeset dummy 116*906afcb8SAndy Fiddaman typeset render_buffer="$( 117*906afcb8SAndy Fiddaman print -n -- "${vtcode["clear"]}" 118*906afcb8SAndy Fiddaman cat <<ENDOFTEXT 119*906afcb8SAndy Fiddaman 120*906afcb8SAndy Fiddaman # ###### # # ###### # 121*906afcb8SAndy Fiddaman # # # # # # 122*906afcb8SAndy Fiddaman # ##### # # ##### # 123*906afcb8SAndy Fiddaman # # # # # # 124*906afcb8SAndy Fiddaman # # # # # # 125*906afcb8SAndy Fiddaman ###### ###### ## ###### ###### 126*906afcb8SAndy Fiddaman 127*906afcb8SAndy Fiddaman (Good job) 128*906afcb8SAndy Fiddaman 129*906afcb8SAndy Fiddaman ##### #### # # ###### 130*906afcb8SAndy Fiddaman # # # # ## # # 131*906afcb8SAndy Fiddaman # # # # # # # ##### 132*906afcb8SAndy Fiddaman # # # # # # # # 133*906afcb8SAndy Fiddaman # # # # # ## # 134*906afcb8SAndy Fiddaman ##### #### # # ###### 135*906afcb8SAndy Fiddaman 136*906afcb8SAndy Fiddaman 137*906afcb8SAndy FiddamanENDOFTEXT 138*906afcb8SAndy Fiddaman 139*906afcb8SAndy Fiddaman printf " SCORE: --> %s <--\n" "${player["score"]}" 140*906afcb8SAndy Fiddaman printf " LIVES: --> %s <--\n" "${player["lives"]}" 141*906afcb8SAndy Fiddaman )" 142*906afcb8SAndy Fiddaman print -- "${render_buffer}${end_of_frame}" 143*906afcb8SAndy Fiddaman 144*906afcb8SAndy Fiddaman # wait five seconds and swallow any user input 145*906afcb8SAndy Fiddaman for (( i=0 ; i < 50 ; i++ )) ; do 146*906afcb8SAndy Fiddaman read -r -t 0.1 -n 1 dummy 147*906afcb8SAndy Fiddaman done 148*906afcb8SAndy Fiddaman 149*906afcb8SAndy Fiddaman print "Press any key to continue...${end_of_frame}" 150*906afcb8SAndy Fiddaman # wait five secs or for a key 151*906afcb8SAndy Fiddaman read -r -t 5 -n 1 dummy 152*906afcb8SAndy Fiddaman return 0 153*906afcb8SAndy Fiddaman} 154*906afcb8SAndy Fiddaman 155*906afcb8SAndy Fiddamanfunction game_over 156*906afcb8SAndy Fiddaman{ 157*906afcb8SAndy Fiddaman typeset dummy 158*906afcb8SAndy Fiddaman typeset render_buffer="$( 159*906afcb8SAndy Fiddaman print -n -- "${vtcode["clear"]}" 160*906afcb8SAndy Fiddaman cat <<ENDOFTEXT 161*906afcb8SAndy Fiddaman 162*906afcb8SAndy Fiddaman #### ## # # ###### 163*906afcb8SAndy Fiddaman # # # # ## ## # 164*906afcb8SAndy Fiddaman # # # # ## # ##### 165*906afcb8SAndy Fiddaman # ### ###### # # # 166*906afcb8SAndy Fiddaman # # # # # # # 167*906afcb8SAndy Fiddaman #### # # # # ###### 168*906afcb8SAndy Fiddaman 169*906afcb8SAndy Fiddaman (LOSER!) 170*906afcb8SAndy Fiddaman 171*906afcb8SAndy Fiddaman #### # # ###### ##### 172*906afcb8SAndy Fiddaman # # # # # # # 173*906afcb8SAndy Fiddaman # # # # ##### # # 174*906afcb8SAndy Fiddaman # # # # # ##### 175*906afcb8SAndy Fiddaman # # # # # # # 176*906afcb8SAndy Fiddaman #### ## ###### # # 177*906afcb8SAndy Fiddaman 178*906afcb8SAndy FiddamanENDOFTEXT 179*906afcb8SAndy Fiddaman 180*906afcb8SAndy Fiddaman printf "\n SCORE: --> %s <--\n" "${player["score"]}" 181*906afcb8SAndy Fiddaman )" 182*906afcb8SAndy Fiddaman print -r -- "${render_buffer}${end_of_frame}" 183*906afcb8SAndy Fiddaman 184*906afcb8SAndy Fiddaman # wait five seconds and swallow any user input 185*906afcb8SAndy Fiddaman for (( i=0 ; i < 50 ; i++ )) ; do 186*906afcb8SAndy Fiddaman read -r -t 0.1 -n 1 dummy 187*906afcb8SAndy Fiddaman done 188*906afcb8SAndy Fiddaman 189*906afcb8SAndy Fiddaman print "Press any key to continue...${end_of_frame}" 190*906afcb8SAndy Fiddaman # wait five secs or for a key 191*906afcb8SAndy Fiddaman read -r -t 5 -n 1 dummy 192*906afcb8SAndy Fiddaman return 0 193*906afcb8SAndy Fiddaman} 194*906afcb8SAndy Fiddaman 195*906afcb8SAndy Fiddamanfunction run_logo 196*906afcb8SAndy Fiddaman{ 197*906afcb8SAndy Fiddaman typeset render_buffer="$( 198*906afcb8SAndy Fiddaman cat <<ENDOFTEXT 199*906afcb8SAndy Fiddaman 200*906afcb8SAndy Fiddaman ##### # # # # # ### 201*906afcb8SAndy Fiddaman# # ## # # # # # # ### 202*906afcb8SAndy Fiddaman# # # # # # # # # ### 203*906afcb8SAndy Fiddaman# #### # # # # # # # # # 204*906afcb8SAndy Fiddaman# # # # # ####### # # # 205*906afcb8SAndy Fiddaman# # # ## # # # # # ### 206*906afcb8SAndy Fiddaman ##### # # # # ## ## ### 207*906afcb8SAndy FiddamanENDOFTEXT 208*906afcb8SAndy Fiddaman )" 209*906afcb8SAndy Fiddaman print -- "${vtcode["clear"]}${render_buffer}" 210*906afcb8SAndy Fiddaman 211*906afcb8SAndy Fiddaman # wait two seconds and swallow any user input 212*906afcb8SAndy Fiddaman for (( i=0 ; i < 20 ; i++ )) ; do 213*906afcb8SAndy Fiddaman read -r -t 0.1 -n 1 dummy 214*906afcb8SAndy Fiddaman done 215*906afcb8SAndy Fiddaman 216*906afcb8SAndy Fiddaman print "\n (The KornShell 93 maze game)" 217*906afcb8SAndy Fiddaman 218*906afcb8SAndy Fiddaman attract_mode 219*906afcb8SAndy Fiddaman return 0 220*906afcb8SAndy Fiddaman} 221*906afcb8SAndy Fiddaman 222*906afcb8SAndy Fiddamanfunction attract_mode 223*906afcb8SAndy Fiddaman{ 224*906afcb8SAndy Fiddaman( 225*906afcb8SAndy Fiddaman # Now present some info, line-by-line in an endless loop 226*906afcb8SAndy Fiddaman # until the user presses a key (we turn the "magic" return 227*906afcb8SAndy Fiddaman # code for that) 228*906afcb8SAndy Fiddaman integer -r magic_return_code=69 229*906afcb8SAndy Fiddaman typeset line 230*906afcb8SAndy Fiddaman IFS='' ; # Make sure we do not swallow whitespaces 231*906afcb8SAndy Fiddaman 232*906afcb8SAndy Fiddaman while true ; do 233*906afcb8SAndy Fiddaman ( 234*906afcb8SAndy Fiddaman redirect 5<&0 235*906afcb8SAndy Fiddaman 236*906afcb8SAndy Fiddaman (cat <<ENDOFTEXT 237*906afcb8SAndy Fiddaman 238*906afcb8SAndy Fiddaman 239*906afcb8SAndy Fiddaman 240*906afcb8SAndy Fiddaman 241*906afcb8SAndy Fiddaman 242*906afcb8SAndy Fiddaman ################ 243*906afcb8SAndy Fiddaman ######################## 244*906afcb8SAndy Fiddaman ############################ 245*906afcb8SAndy Fiddaman ####### ###### ####### 246*906afcb8SAndy Fiddaman ###### ###### ######## 247*906afcb8SAndy Fiddaman ####### ###### ####### 248*906afcb8SAndy Fiddaman ############################## 249*906afcb8SAndy Fiddaman ############################## 250*906afcb8SAndy Fiddaman ############################## 251*906afcb8SAndy Fiddaman ############################## 252*906afcb8SAndy Fiddaman ############################## 253*906afcb8SAndy Fiddaman ######### ######## ######### 254*906afcb8SAndy Fiddaman # #### #### #### # 255*906afcb8SAndy Fiddaman 256*906afcb8SAndy Fiddaman 257*906afcb8SAndy Fiddaman 258*906afcb8SAndy Fiddaman 259*906afcb8SAndy Fiddaman 260*906afcb8SAndy Fiddaman 261*906afcb8SAndy Fiddaman Written by 262*906afcb8SAndy Fiddaman 263*906afcb8SAndy Fiddaman Roland Mainz 264*906afcb8SAndy Fiddaman (roland.mainz@nrubsig.org) 265*906afcb8SAndy Fiddaman 266*906afcb8SAndy Fiddaman 267*906afcb8SAndy Fiddaman 268*906afcb8SAndy Fiddaman 269*906afcb8SAndy Fiddaman 270*906afcb8SAndy Fiddaman 271*906afcb8SAndy Fiddaman ############## 272*906afcb8SAndy Fiddaman ######################## 273*906afcb8SAndy Fiddaman #################**############ 274*906afcb8SAndy Fiddaman ################################ 275*906afcb8SAndy Fiddaman ############################ 276*906afcb8SAndy Fiddaman ###################### 277*906afcb8SAndy Fiddaman ################ 278*906afcb8SAndy Fiddaman ###################### 279*906afcb8SAndy Fiddaman ############################ 280*906afcb8SAndy Fiddaman ################################ 281*906afcb8SAndy Fiddaman ############################## 282*906afcb8SAndy Fiddaman ######################## 283*906afcb8SAndy Fiddaman ############## 284*906afcb8SAndy Fiddaman 285*906afcb8SAndy Fiddaman 286*906afcb8SAndy Fiddaman 287*906afcb8SAndy Fiddaman 288*906afcb8SAndy Fiddaman 289*906afcb8SAndy Fiddaman 290*906afcb8SAndy Fiddaman 291*906afcb8SAndy Fiddaman High scores: 292*906afcb8SAndy Fiddaman 293*906afcb8SAndy Fiddaman * 'chin' 8200 pt 294*906afcb8SAndy Fiddaman * 'gisburn' 7900 pt 295*906afcb8SAndy Fiddaman * 'tpenta' 5520 pt 296*906afcb8SAndy Fiddaman * 'kupfer' 5510 pt 297*906afcb8SAndy Fiddaman * 'noname' 5000 pt 298*906afcb8SAndy Fiddaman * 'noname' 4000 pt 299*906afcb8SAndy Fiddaman * 'livad' 3120 pt 300*906afcb8SAndy Fiddaman * 'noname' 3000 pt 301*906afcb8SAndy Fiddaman * 'noname' 2000 pt 302*906afcb8SAndy Fiddaman * 'noname' 1000 pt 303*906afcb8SAndy Fiddaman 304*906afcb8SAndy FiddamanENDOFTEXT 305*906afcb8SAndy Fiddaman 306*906afcb8SAndy Fiddaman # clear screen, line-by-line 307*906afcb8SAndy Fiddaman for (( i=0 ; i < termsize.lines ; i++ )) ; do print "" ; done 308*906afcb8SAndy Fiddaman ) | (while read -r line ; do 309*906afcb8SAndy Fiddaman read -r -t 0.3 -n 1 c <&5 310*906afcb8SAndy Fiddaman [[ "$c" != "" ]] && exit ${magic_return_code} 311*906afcb8SAndy Fiddaman print -- "${line}" 312*906afcb8SAndy Fiddaman done) 313*906afcb8SAndy Fiddaman (( $? == magic_return_code )) && exit ${magic_return_code} 314*906afcb8SAndy Fiddaman ) 315*906afcb8SAndy Fiddaman (( $? == magic_return_code )) && return 0 316*906afcb8SAndy Fiddaman 317*906afcb8SAndy Fiddaman sleep 2 318*906afcb8SAndy Fiddaman done 319*906afcb8SAndy Fiddaman) 320*906afcb8SAndy Fiddaman} 321*906afcb8SAndy Fiddaman 322*906afcb8SAndy Fiddamanfunction run_menu 323*906afcb8SAndy Fiddaman{ 324*906afcb8SAndy Fiddaman integer numlevels=0 325*906afcb8SAndy Fiddaman integer selected_level=0 326*906afcb8SAndy Fiddaman typeset l 327*906afcb8SAndy Fiddaman 328*906afcb8SAndy Fiddaman # built list of available levels based on the "function levelmap_.*" 329*906afcb8SAndy Fiddaman # built into this script 330*906afcb8SAndy Fiddaman typeset -f | egrep "^function.*levelmap_.*" | sed 's/^function //' | 331*906afcb8SAndy Fiddaman while read -r l ; do 332*906afcb8SAndy Fiddaman levellist[numlevels]="$l" 333*906afcb8SAndy Fiddaman numlevels+=1 334*906afcb8SAndy Fiddaman done 335*906afcb8SAndy Fiddaman 336*906afcb8SAndy Fiddaman # swallow any queued user input (e.g. drain stdin) 337*906afcb8SAndy Fiddaman read -r -t 0.1 -n 100 dummy 338*906afcb8SAndy Fiddaman 339*906afcb8SAndy Fiddaman while true ; do 340*906afcb8SAndy Fiddaman # menu loop with timeout (which switches to "attract mode") 341*906afcb8SAndy Fiddaman while true ; do 342*906afcb8SAndy Fiddaman print -n -- "${vtcode["clear"]}" 343*906afcb8SAndy Fiddaman 344*906afcb8SAndy Fiddaman cat <<ENDOFTEXT 345*906afcb8SAndy Fiddaman>======================================\ 346*906afcb8SAndy Fiddaman> /-\ .--. | 347*906afcb8SAndy Fiddaman> | OO| / _.-' .-. .-. .-. .-. | 348*906afcb8SAndy Fiddaman> | | \ '-. '-' '-' '-' '-' | 349*906afcb8SAndy Fiddaman> ^^^^^ '--' | 350*906afcb8SAndy Fiddaman>======\ /================\ .-. | 351*906afcb8SAndy Fiddaman> | | | '-' | 352*906afcb8SAndy Fiddaman ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 353*906afcb8SAndy FiddamanENDOFTEXT 354*906afcb8SAndy Fiddaman print " GNAW - the ksh93 maze game" 355*906afcb8SAndy Fiddaman print "\n\tMenu:" 356*906afcb8SAndy Fiddaman 357*906afcb8SAndy Fiddaman print "\t - [L]evels:" 358*906afcb8SAndy Fiddaman for (( i=0 ; i < numlevels ; i++ )) ; do 359*906afcb8SAndy Fiddaman printf "\t %s %s \n" "$( (( i == selected_level )) && print -n "*" || print -n " ")" "${levellist[i]##levelmap_}" 360*906afcb8SAndy Fiddaman done 361*906afcb8SAndy Fiddaman 362*906afcb8SAndy Fiddaman print "\t - Rendering options:" 363*906afcb8SAndy Fiddaman printf "\t [%s] Use [U]nicode\n" "$( (( game_use_unicode == 1 )) && print -n "x" || print -n "_" )" 364*906afcb8SAndy Fiddaman printf "\t [%s] Use [C]olors\n" "$( (( game_use_colors == 1 )) && print -n "x" || print -n "_" )" 365*906afcb8SAndy Fiddaman 366*906afcb8SAndy Fiddaman print "\t - [S]tart - [Q]uit" 367*906afcb8SAndy Fiddaman 368*906afcb8SAndy Fiddaman # wait 30 secs (before we switch to "attract mode") 369*906afcb8SAndy Fiddaman c="" ; read -r -t 30 -n 1 c 370*906afcb8SAndy Fiddaman case "$c" in 371*906afcb8SAndy Fiddaman 'l') (( selected_level=(selected_level+numlevels+1) % numlevels )) ;; 372*906afcb8SAndy Fiddaman 'L') (( selected_level=(selected_level+numlevels-1) % numlevels )) ;; 373*906afcb8SAndy Fiddaman ~(Fi)s) 374*906afcb8SAndy Fiddaman (( game_use_colors == 1 )) && print -- "${vtcode["bg_black"]}" 375*906afcb8SAndy Fiddaman case "${game_use_colors}${game_use_unicode}" in 376*906afcb8SAndy Fiddaman "00") main_loop "${levellist[selected_level]}" ;; 377*906afcb8SAndy Fiddaman "01") main_loop "${levellist[selected_level]}" | map_filter 0 1 ;; 378*906afcb8SAndy Fiddaman "10") main_loop "${levellist[selected_level]}" | map_filter 1 0 ;; 379*906afcb8SAndy Fiddaman "11") main_loop "${levellist[selected_level]}" | map_filter 1 1 ;; 380*906afcb8SAndy Fiddaman esac 381*906afcb8SAndy Fiddaman print -- "${vtcode["vtreset"]}" 382*906afcb8SAndy Fiddaman ;; 383*906afcb8SAndy Fiddaman ~(Fi)q | $'\E') 384*906afcb8SAndy Fiddaman # make sure we do not exit on a cursor key (e.g. <esc>[A,B,C,D) 385*906afcb8SAndy Fiddaman read -r -t 0.01 -n 1 c 386*906afcb8SAndy Fiddaman if [[ "$c" == "[" ]] ; then 387*906afcb8SAndy Fiddaman # this was a cursor key sequence, just eat the 3rd charcater 388*906afcb8SAndy Fiddaman read -r -t 0.01 -n 1 c 389*906afcb8SAndy Fiddaman else 390*906afcb8SAndy Fiddaman exit 0 391*906afcb8SAndy Fiddaman fi 392*906afcb8SAndy Fiddaman ;; 393*906afcb8SAndy Fiddaman ~(Fi)u) (( game_use_unicode=(game_use_unicode+2+1) % 2)) ;; 394*906afcb8SAndy Fiddaman ~(Fi)c) (( game_use_colors=(game_use_colors+2+1) % 2)) ;; 395*906afcb8SAndy Fiddaman "") break ;; # timeout, switch to attract mode 396*906afcb8SAndy Fiddaman *) beep ;; 397*906afcb8SAndy Fiddaman esac 398*906afcb8SAndy Fiddaman done 399*906afcb8SAndy Fiddaman 400*906afcb8SAndy Fiddaman print -n -- "${vtcode["clear"]}" 401*906afcb8SAndy Fiddaman attract_mode 402*906afcb8SAndy Fiddaman done 403*906afcb8SAndy Fiddaman return 0 404*906afcb8SAndy Fiddaman} 405*906afcb8SAndy Fiddaman 406*906afcb8SAndy Fiddamanfunction levelmap_stripes 407*906afcb8SAndy Fiddaman{ 408*906afcb8SAndy Fiddamancat <<ENDOFLEVEL 409*906afcb8SAndy Fiddaman################################### 410*906afcb8SAndy Fiddaman#....... ............... P # 411*906afcb8SAndy Fiddaman#########..#################..### # 412*906afcb8SAndy Fiddaman#########..#################..### # 413*906afcb8SAndy Fiddaman#....... .. ..............# # 414*906afcb8SAndy Fiddaman############### ################ # 415*906afcb8SAndy Fiddaman############### ################ # 416*906afcb8SAndy Fiddaman#............. M ..............# # 417*906afcb8SAndy Fiddaman##..##################### ###### # 418*906afcb8SAndy Fiddaman##..##################### ###### # 419*906afcb8SAndy Fiddaman#....... ........... .......# # 420*906afcb8SAndy Fiddaman######## ############ ######### # 421*906afcb8SAndy Fiddaman# #### ############ ######### # 422*906afcb8SAndy Fiddaman# #.................. ......# # 423*906afcb8SAndy Fiddaman# ############################### # 424*906afcb8SAndy Fiddaman# # 425*906afcb8SAndy Fiddaman################################### 426*906afcb8SAndy FiddamanENDOFLEVEL 427*906afcb8SAndy Fiddaman return 0 428*906afcb8SAndy Fiddaman} 429*906afcb8SAndy Fiddaman 430*906afcb8SAndy Fiddamanfunction levelmap_livad 431*906afcb8SAndy Fiddaman{ 432*906afcb8SAndy Fiddamancat <<ENDOFLEVEL 433*906afcb8SAndy Fiddaman##################################################### 434*906afcb8SAndy Fiddaman# # 435*906afcb8SAndy Fiddaman# ############## ############### ################ # 436*906afcb8SAndy Fiddaman# #............ P ..............# # 437*906afcb8SAndy Fiddaman# .#############################################.# # 438*906afcb8SAndy Fiddaman# #.#.......... ............#. # 439*906afcb8SAndy Fiddaman# #.#.########## ############### ############.#.# # 440*906afcb8SAndy Fiddaman# #...#........ ..........#...# # 441*906afcb8SAndy Fiddaman# #...#.#####################################.#.#.# # 442*906afcb8SAndy Fiddaman# #...#.#...... ........#...#.# # 443*906afcb8SAndy Fiddaman# #.#.#...###### #########################.#.#.#.# # 444*906afcb8SAndy Fiddaman# .#.....#.... M ......#...#.#.# # 445*906afcb8SAndy Fiddaman# #.#.#...####################### ########.#.#.#.# # 446*906afcb8SAndy Fiddaman# #...#.#...... ........#...#.# # 447*906afcb8SAndy Fiddaman# #...#.######## ############### ##########.#.#.# # 448*906afcb8SAndy Fiddaman# #...#........ ..........#...# # 449*906afcb8SAndy Fiddaman# #.#.#########################################.#.# # 450*906afcb8SAndy Fiddaman# #.#.......... ............#. # 451*906afcb8SAndy Fiddaman# .############ ############### ##############.# # 452*906afcb8SAndy Fiddaman# #............ ..............# # 453*906afcb8SAndy Fiddaman# ################################################# # 454*906afcb8SAndy Fiddaman# # 455*906afcb8SAndy Fiddaman##################################################### 456*906afcb8SAndy FiddamanENDOFLEVEL 457*906afcb8SAndy Fiddaman return 0 458*906afcb8SAndy Fiddaman} 459*906afcb8SAndy Fiddaman 460*906afcb8SAndy Fiddamanfunction levelmap_classic1 461*906afcb8SAndy Fiddaman{ 462*906afcb8SAndy Fiddamancat <<ENDOFLEVEL 463*906afcb8SAndy Fiddaman######################### 464*906afcb8SAndy Fiddaman#.P.........#...........# 465*906afcb8SAndy Fiddaman#.####.####.#.####.####.# 466*906afcb8SAndy Fiddaman#.# #.# #.#.# #.# #.# 467*906afcb8SAndy Fiddaman#.# #.# #.#.# #.# #.# 468*906afcb8SAndy Fiddaman#.####.####.#.####.####.# 469*906afcb8SAndy Fiddaman#.......................# 470*906afcb8SAndy Fiddaman#.####.#.#######.#.####.# 471*906afcb8SAndy Fiddaman#.# #.#.# #.#.# #.# 472*906afcb8SAndy Fiddaman#.####.#.#######.#.####.# 473*906afcb8SAndy Fiddaman#......#....#....#......# 474*906afcb8SAndy Fiddaman######.####.#.####.###### 475*906afcb8SAndy Fiddaman###### # # ###### 476*906afcb8SAndy Fiddaman###### # ## ## # ###### 477*906afcb8SAndy Fiddaman###### # # # # ###### 478*906afcb8SAndy Fiddaman# # M # # 479*906afcb8SAndy Fiddaman###### # ####### # ###### 480*906afcb8SAndy Fiddaman###### # # ###### 481*906afcb8SAndy Fiddaman###### # ####### # ###### 482*906afcb8SAndy Fiddaman###### # # # # ###### 483*906afcb8SAndy Fiddaman######.#.#######.#.###### 484*906afcb8SAndy Fiddaman#...........#...........# 485*906afcb8SAndy Fiddaman#.###.###...#...###.###.# 486*906afcb8SAndy Fiddaman#...#...............#...# 487*906afcb8SAndy Fiddaman###.#....#######....#.### 488*906afcb8SAndy Fiddaman# #.#..#.# #.#..#.# # 489*906afcb8SAndy Fiddaman###....#.#######.#....### 490*906afcb8SAndy Fiddaman#......#....#....#......# 491*906afcb8SAndy Fiddaman#.#########.#.#########.# 492*906afcb8SAndy Fiddaman#.......................# 493*906afcb8SAndy Fiddaman######################### 494*906afcb8SAndy FiddamanENDOFLEVEL 495*906afcb8SAndy Fiddaman return 0 496*906afcb8SAndy Fiddaman} 497*906afcb8SAndy Fiddaman 498*906afcb8SAndy Fiddamanfunction levelmap_classic2 499*906afcb8SAndy Fiddaman{ 500*906afcb8SAndy Fiddamancat <<ENDOFLEVEL 501*906afcb8SAndy Fiddaman####################### 502*906afcb8SAndy Fiddaman#.P...#.........#.....# 503*906afcb8SAndy Fiddaman#.###.#.#######.#.###.# 504*906afcb8SAndy Fiddaman#.....................# 505*906afcb8SAndy Fiddaman###.#.####.#.####.#.### 506*906afcb8SAndy Fiddaman###.#......#......#.### 507*906afcb8SAndy Fiddaman###.###.#######.###.### 508*906afcb8SAndy Fiddaman###.................### 509*906afcb8SAndy Fiddaman###.###.### ###.###.### 510*906afcb8SAndy Fiddaman###.#...#M #...#.### 511*906afcb8SAndy Fiddaman###.#.#.#######.#.#.### 512*906afcb8SAndy Fiddaman#.....#.........#.....# 513*906afcb8SAndy Fiddaman###.#####..#..#####.### 514*906afcb8SAndy Fiddaman###........#........### 515*906afcb8SAndy Fiddaman###.###.#######.###.### 516*906afcb8SAndy Fiddaman#.....................# 517*906afcb8SAndy Fiddaman#.###.####.#.####.###.# 518*906afcb8SAndy Fiddaman#.###.#....#....#.###.# 519*906afcb8SAndy Fiddaman#.###.#.#######.#.###.# 520*906afcb8SAndy Fiddaman#.....................# 521*906afcb8SAndy Fiddaman####################### 522*906afcb8SAndy FiddamanENDOFLEVEL 523*906afcb8SAndy Fiddaman return 0 524*906afcb8SAndy Fiddaman} 525*906afcb8SAndy Fiddaman 526*906afcb8SAndy Fiddamanfunction levelmap_easy 527*906afcb8SAndy Fiddaman{ 528*906afcb8SAndy Fiddamancat <<ENDOFLEVEL 529*906afcb8SAndy Fiddaman################## 530*906afcb8SAndy Fiddaman# .............. # 531*906afcb8SAndy Fiddaman# . ###### # 532*906afcb8SAndy Fiddaman# . # M # # 533*906afcb8SAndy Fiddaman# . # # # 534*906afcb8SAndy Fiddaman# . ### ## # 535*906afcb8SAndy Fiddaman# . # # 536*906afcb8SAndy Fiddaman# . ### # 537*906afcb8SAndy Fiddaman# . # 538*906afcb8SAndy Fiddaman# .......... # 539*906afcb8SAndy Fiddaman# .......... P # 540*906afcb8SAndy Fiddaman################## 541*906afcb8SAndy FiddamanENDOFLEVEL 542*906afcb8SAndy Fiddaman return 0 543*906afcb8SAndy Fiddaman} 544*906afcb8SAndy Fiddaman 545*906afcb8SAndy Fiddamanfunction levelmap_sunsolaristext 546*906afcb8SAndy Fiddaman{ 547*906afcb8SAndy Fiddamancat <<ENDOFLEVEL 548*906afcb8SAndy Fiddaman################################################ 549*906afcb8SAndy Fiddaman# .#### . # #....# # 550*906afcb8SAndy Fiddaman# # # # #....# # 551*906afcb8SAndy Fiddaman# #### # # #.#..# M # 552*906afcb8SAndy Fiddaman# # # # #..#.# # 553*906afcb8SAndy Fiddaman# # # # # #...## # 554*906afcb8SAndy Fiddaman# #### #### #....# # 555*906afcb8SAndy Fiddaman# # 556*906afcb8SAndy Fiddaman# #### #### # ## ##### # #### # 557*906afcb8SAndy Fiddaman# # #. .# # # # #....# # # # 558*906afcb8SAndy Fiddaman# #### # # # # P # #....# # #### # 559*906afcb8SAndy Fiddaman# # # ### #.#### #.### # # # 560*906afcb8SAndy Fiddaman# # .# #. .. # # #...# # # # # 561*906afcb8SAndy Fiddaman# #### #### ###### . # ....# # ####. # 562*906afcb8SAndy Fiddaman################################################ 563*906afcb8SAndy FiddamanENDOFLEVEL 564*906afcb8SAndy Fiddaman return 0 565*906afcb8SAndy Fiddaman} 566*906afcb8SAndy Fiddaman 567*906afcb8SAndy Fiddamanfunction read_levelmap 568*906afcb8SAndy Fiddaman{ 569*906afcb8SAndy Fiddaman typeset map="$( $1 )" 570*906afcb8SAndy Fiddaman 571*906afcb8SAndy Fiddaman integer y=0 572*906afcb8SAndy Fiddaman integer x=0 573*906afcb8SAndy Fiddaman integer maxx=0 574*906afcb8SAndy Fiddaman integer numdots=0 575*906afcb8SAndy Fiddaman typeset line 576*906afcb8SAndy Fiddaman typeset c 577*906afcb8SAndy Fiddaman 578*906afcb8SAndy Fiddaman while read -r line ; do 579*906afcb8SAndy Fiddaman for (( x=0 ; x < ${#line} ; x++ )) ; do 580*906afcb8SAndy Fiddaman c="${line:x:1}" 581*906afcb8SAndy Fiddaman 582*906afcb8SAndy Fiddaman case $c in 583*906afcb8SAndy Fiddaman ".") numdots+=1 ;; 584*906afcb8SAndy Fiddaman "M") 585*906afcb8SAndy Fiddaman # log start position of monsters 586*906afcb8SAndy Fiddaman levelmap["monsterstartpos_x"]="$x" 587*906afcb8SAndy Fiddaman levelmap["monsterstartpos_y"]="$y" 588*906afcb8SAndy Fiddaman c=" " 589*906afcb8SAndy Fiddaman ;; 590*906afcb8SAndy Fiddaman "P") 591*906afcb8SAndy Fiddaman # log start position of player 592*906afcb8SAndy Fiddaman levelmap["playerstartpos_x"]="$x" 593*906afcb8SAndy Fiddaman levelmap["playerstartpos_y"]="$y" 594*906afcb8SAndy Fiddaman c=" " 595*906afcb8SAndy Fiddaman ;; 596*906afcb8SAndy Fiddaman esac 597*906afcb8SAndy Fiddaman 598*906afcb8SAndy Fiddaman levelmap["${x}_${y}"]="$c" 599*906afcb8SAndy Fiddaman done 600*906afcb8SAndy Fiddaman (( maxx=x , y++ )) 601*906afcb8SAndy Fiddaman done <<<"${map}" 602*906afcb8SAndy Fiddaman 603*906afcb8SAndy Fiddaman levelmap["max_x"]=${maxx} 604*906afcb8SAndy Fiddaman levelmap["max_y"]=${y} 605*906afcb8SAndy Fiddaman levelmap["numdots"]=${numdots} 606*906afcb8SAndy Fiddaman 607*906afcb8SAndy Fiddaman # consistency checks 608*906afcb8SAndy Fiddaman if [[ "${levelmap["monsterstartpos_x"]}" == "" ]] ; then 609*906afcb8SAndy Fiddaman fatal_error "read_levelmap: monsterstartpos_x is empty." 610*906afcb8SAndy Fiddaman fi 611*906afcb8SAndy Fiddaman if [[ "${levelmap["playerstartpos_x"]}" == "" ]] ; then 612*906afcb8SAndy Fiddaman fatal_error "read_levelmap: playerstartpos_x is empty." 613*906afcb8SAndy Fiddaman fi 614*906afcb8SAndy Fiddaman 615*906afcb8SAndy Fiddaman return 0 616*906afcb8SAndy Fiddaman} 617*906afcb8SAndy Fiddaman 618*906afcb8SAndy Fiddamanfunction player.set 619*906afcb8SAndy Fiddaman{ 620*906afcb8SAndy Fiddaman case "${.sh.subscript}" in 621*906afcb8SAndy Fiddaman pos_y) 622*906afcb8SAndy Fiddaman if [[ "${levelmap["${player["pos_x"]}_${.sh.value}"]}" == "#" ]] ; then 623*906afcb8SAndy Fiddaman .sh.value=${player["pos_y"]} 624*906afcb8SAndy Fiddaman beep 625*906afcb8SAndy Fiddaman fi 626*906afcb8SAndy Fiddaman ;; 627*906afcb8SAndy Fiddaman 628*906afcb8SAndy Fiddaman pos_x) 629*906afcb8SAndy Fiddaman if [[ "${levelmap["${.sh.value}_${player["pos_y"]}"]}" == "#" ]] ; then 630*906afcb8SAndy Fiddaman .sh.value=${player["pos_x"]} 631*906afcb8SAndy Fiddaman beep 632*906afcb8SAndy Fiddaman fi 633*906afcb8SAndy Fiddaman ;; 634*906afcb8SAndy Fiddaman esac 635*906afcb8SAndy Fiddaman return 0 636*906afcb8SAndy Fiddaman} 637*906afcb8SAndy Fiddaman 638*906afcb8SAndy Fiddamanfunction monster.set 639*906afcb8SAndy Fiddaman{ 640*906afcb8SAndy Fiddaman case "${.sh.subscript}" in 641*906afcb8SAndy Fiddaman *_pos_y) 642*906afcb8SAndy Fiddaman if [[ "${levelmap["${monster[${currmonster}_"pos_x"]}_${.sh.value}"]}" == "#" ]] ; then 643*906afcb8SAndy Fiddaman .sh.value=${monster[${currmonster}_"pos_y"]} 644*906afcb8SAndy Fiddaman # turn homing off when the monster hit a wall 645*906afcb8SAndy Fiddaman monster[${currmonster}_"homing"]=0 646*906afcb8SAndy Fiddaman fi 647*906afcb8SAndy Fiddaman ;; 648*906afcb8SAndy Fiddaman 649*906afcb8SAndy Fiddaman *_pos_x) 650*906afcb8SAndy Fiddaman if [[ "${levelmap["${.sh.value}_${monster[${currmonster}_"pos_y"]}"]}" == "#" ]] ; then 651*906afcb8SAndy Fiddaman .sh.value=${monster[${currmonster}_"pos_x"]} 652*906afcb8SAndy Fiddaman # turn homing off when the monster hit a wall 653*906afcb8SAndy Fiddaman monster[${currmonster}_"homing"]=0 654*906afcb8SAndy Fiddaman fi 655*906afcb8SAndy Fiddaman ;; 656*906afcb8SAndy Fiddaman esac 657*906afcb8SAndy Fiddaman return 0 658*906afcb8SAndy Fiddaman} 659*906afcb8SAndy Fiddaman 660*906afcb8SAndy Fiddamanfunction render_game 661*906afcb8SAndy Fiddaman{ 662*906afcb8SAndy Fiddaman # render_buffer is some kind of "background buffer" to "double buffer" 663*906afcb8SAndy Fiddaman # all output and combine it in one write to reduce flickering in the 664*906afcb8SAndy Fiddaman # terminal 665*906afcb8SAndy Fiddaman typeset render_buffer="$( 666*906afcb8SAndy Fiddaman integer screen_y_offset=1 667*906afcb8SAndy Fiddaman integer start_y_pos=0 668*906afcb8SAndy Fiddaman integer render_num_lines=${levelmap["max_y"]} 669*906afcb8SAndy Fiddaman 670*906afcb8SAndy Fiddaman if (( (termsize.lines-3) < levelmap["max_y"] )) ; then 671*906afcb8SAndy Fiddaman (( start_y_pos=player["pos_y"] / 2)) 672*906afcb8SAndy Fiddaman (( render_num_lines=termsize.lines-5)) 673*906afcb8SAndy Fiddaman fi 674*906afcb8SAndy Fiddaman 675*906afcb8SAndy Fiddaman #print -n -- "${vtcode["clear"]}" 676*906afcb8SAndy Fiddaman print_setcursorpos 0 0 677*906afcb8SAndy Fiddaman 678*906afcb8SAndy Fiddaman # print score (note the " " around "%d" are neccesary to clean up cruft 679*906afcb8SAndy Fiddaman # when we overwrite the level 680*906afcb8SAndy Fiddaman printf "SCORE: %05d DOTS: %.3d LIVES: %2.d " "${player["score"]}" "${levelmap["numdots"]}" "${player["lives"]}" 681*906afcb8SAndy Fiddaman print_levelmap ${screen_y_offset} ${start_y_pos} ${render_num_lines} 682*906afcb8SAndy Fiddaman 683*906afcb8SAndy Fiddaman # render player 684*906afcb8SAndy Fiddaman print_setcursorpos ${player["pos_x"]} $((player["pos_y"]+screen_y_offset-start_y_pos)) 685*906afcb8SAndy Fiddaman print -n "@" 686*906afcb8SAndy Fiddaman 687*906afcb8SAndy Fiddaman # render monsters 688*906afcb8SAndy Fiddaman for currmonster in ${monsterlist} ; do 689*906afcb8SAndy Fiddaman (( m_pos_x=monster[${currmonster}_"pos_x"] )) 690*906afcb8SAndy Fiddaman (( m_pos_y=monster[${currmonster}_"pos_y"]+screen_y_offset-start_y_pos )) 691*906afcb8SAndy Fiddaman 692*906afcb8SAndy Fiddaman if (( m_pos_y >= screen_y_offset && m_pos_y < render_num_lines )) ; then 693*906afcb8SAndy Fiddaman print_setcursorpos ${m_pos_x} ${m_pos_y} 694*906afcb8SAndy Fiddaman print -n "x" 695*906afcb8SAndy Fiddaman fi 696*906afcb8SAndy Fiddaman done 697*906afcb8SAndy Fiddaman 698*906afcb8SAndy Fiddaman # status block 699*906afcb8SAndy Fiddaman print_setcursorpos 0 $((render_num_lines+screen_y_offset)) 700*906afcb8SAndy Fiddaman emptyline=" " 701*906afcb8SAndy Fiddaman print -n " >> ${player["message"]} <<${emptyline:0:${#emptyline}-${#player["message"]}}" 702*906afcb8SAndy Fiddaman )" 703*906afcb8SAndy Fiddaman print -r -- "${render_buffer}${end_of_frame}" 704*906afcb8SAndy Fiddaman# print "renderbuffersize=$(print "${render_buffer}" | wc -c) ${end_of_frame}" 705*906afcb8SAndy Fiddaman return 0 706*906afcb8SAndy Fiddaman} 707*906afcb8SAndy Fiddaman 708*906afcb8SAndy Fiddamanfunction main_loop 709*906afcb8SAndy Fiddaman{ 710*906afcb8SAndy Fiddaman float sleep_per_cycle=0.2 711*906afcb8SAndy Fiddaman float seconds_before_read 712*906afcb8SAndy Fiddaman integer num_cycles=0 713*906afcb8SAndy Fiddaman float rs 714*906afcb8SAndy Fiddaman 715*906afcb8SAndy Fiddaman print -n -- "${vtcode["clear"]}" 716*906afcb8SAndy Fiddaman 717*906afcb8SAndy Fiddaman read_levelmap "$1" 718*906afcb8SAndy Fiddaman 719*906afcb8SAndy Fiddaman # player init 720*906afcb8SAndy Fiddaman player["pos_x"]=${levelmap["playerstartpos_x"]} 721*906afcb8SAndy Fiddaman player["pos_y"]=${levelmap["playerstartpos_y"]} 722*906afcb8SAndy Fiddaman player["score"]=0 # player score 723*906afcb8SAndy Fiddaman player["lives"]=5 # number of lives 724*906afcb8SAndy Fiddaman player["invulnerable"]=10 # cycles how long the player remains invulnerable 725*906afcb8SAndy Fiddaman player["message"]="Go..." 726*906afcb8SAndy Fiddaman 727*906afcb8SAndy Fiddaman monsterlist="maw claw jitterbug tentacle grendel" 728*906afcb8SAndy Fiddaman 729*906afcb8SAndy Fiddaman for currmonster in ${monsterlist} ; do 730*906afcb8SAndy Fiddaman monster[${currmonster}_"pos_x"]=${levelmap["monsterstartpos_x"]} 731*906afcb8SAndy Fiddaman monster[${currmonster}_"pos_y"]=${levelmap["monsterstartpos_y"]} 732*906afcb8SAndy Fiddaman monster[${currmonster}_"xstep"]=0 733*906afcb8SAndy Fiddaman monster[${currmonster}_"ystep"]=0 734*906afcb8SAndy Fiddaman monster[${currmonster}_"homing"]=0 735*906afcb8SAndy Fiddaman done 736*906afcb8SAndy Fiddaman 737*906afcb8SAndy Fiddaman # main game cycle loop 738*906afcb8SAndy Fiddaman while true ; do 739*906afcb8SAndy Fiddaman num_cycles+=1 740*906afcb8SAndy Fiddaman seconds_before_read=${SECONDS} 741*906afcb8SAndy Fiddaman c="" ; read -r -t ${sleep_per_cycle} -n 1 c 742*906afcb8SAndy Fiddaman 743*906afcb8SAndy Fiddaman if [[ "$c" != "" ]] ; then 744*906afcb8SAndy Fiddaman # special case handling for cursor keys which are usually composed 745*906afcb8SAndy Fiddaman # of three characters (e.g. "<ESC>[D"). If only <ESC> is hit we 746*906afcb8SAndy Fiddaman # quicky exit 747*906afcb8SAndy Fiddaman if [[ "$c" == $'\E' ]] ; then 748*906afcb8SAndy Fiddaman read -r -t 0.1 -n 1 c 749*906afcb8SAndy Fiddaman if [[ "$c" != "[" ]] ; then 750*906afcb8SAndy Fiddaman return 0 751*906afcb8SAndy Fiddaman fi 752*906afcb8SAndy Fiddaman 753*906afcb8SAndy Fiddaman # we assume the user is using the cursor keys, this |read| 754*906afcb8SAndy Fiddaman # should fetch the 3rd byte of the three-character sequence 755*906afcb8SAndy Fiddaman # for the cursor keys 756*906afcb8SAndy Fiddaman read -r -t 0.1 -n 1 c 757*906afcb8SAndy Fiddaman fi 758*906afcb8SAndy Fiddaman 759*906afcb8SAndy Fiddaman # if the user hit a key the "read" above was interrupted 760*906afcb8SAndy Fiddaman # and didn't wait exactly |sleep_per_cycle| seconds. 761*906afcb8SAndy Fiddaman # We wait here some moments (|rs|="remaining seconds") to 762*906afcb8SAndy Fiddaman # avoid that the game gets "faster" when more user input 763*906afcb8SAndy Fiddaman # is given. 764*906afcb8SAndy Fiddaman (( rs=sleep_per_cycle-(SECONDS-seconds_before_read) )) 765*906afcb8SAndy Fiddaman (( rs > 0.001 )) && sleep ${rs} 766*906afcb8SAndy Fiddaman 767*906afcb8SAndy Fiddaman player["message"]="" 768*906afcb8SAndy Fiddaman 769*906afcb8SAndy Fiddaman case "$c" in 770*906afcb8SAndy Fiddaman j|D|4) (( player["pos_x"]-=1 )) ;; 771*906afcb8SAndy Fiddaman k|C|6) (( player["pos_x"]+=1 )) ;; 772*906afcb8SAndy Fiddaman i|A|8) (( player["pos_y"]-=1 )) ;; 773*906afcb8SAndy Fiddaman m|B|2) (( player["pos_y"]+=1 )) ;; 774*906afcb8SAndy Fiddaman 775*906afcb8SAndy Fiddaman q) return 0 ;; 776*906afcb8SAndy Fiddaman esac 777*906afcb8SAndy Fiddaman 778*906afcb8SAndy Fiddaman if [[ "${levelmap["${player["pos_x"]}_${player["pos_y"]}"]}" == "." ]] ; then 779*906afcb8SAndy Fiddaman levelmap["${player["pos_x"]}_${player["pos_y"]}"]=" " 780*906afcb8SAndy Fiddaman (( levelmap["numdots"]-=1 )) 781*906afcb8SAndy Fiddaman 782*906afcb8SAndy Fiddaman (( player["score"]+=10 )) 783*906afcb8SAndy Fiddaman player["message"]='GNAW!!' 784*906afcb8SAndy Fiddaman 785*906afcb8SAndy Fiddaman if (( levelmap["numdots"] <= 0 )) ; then 786*906afcb8SAndy Fiddaman level_completed 787*906afcb8SAndy Fiddaman return 0 788*906afcb8SAndy Fiddaman fi 789*906afcb8SAndy Fiddaman fi 790*906afcb8SAndy Fiddaman fi 791*906afcb8SAndy Fiddaman 792*906afcb8SAndy Fiddaman # generic player status change 793*906afcb8SAndy Fiddaman if (( player["invulnerable"] > 0 )) ; then 794*906afcb8SAndy Fiddaman (( player["invulnerable"]-=1 )) 795*906afcb8SAndy Fiddaman fi 796*906afcb8SAndy Fiddaman if (( player["lives"] <= 0 )) ; then 797*906afcb8SAndy Fiddaman game_over 798*906afcb8SAndy Fiddaman return 0 799*906afcb8SAndy Fiddaman fi 800*906afcb8SAndy Fiddaman 801*906afcb8SAndy Fiddaman # move monsters 802*906afcb8SAndy Fiddaman for currmonster in ${monsterlist} ; do 803*906afcb8SAndy Fiddaman # make monster as half as slow then the others when it is following the user 804*906afcb8SAndy Fiddaman if (( monster[${currmonster}_"homing"] > 0 )) ; then 805*906afcb8SAndy Fiddaman (( (num_cycles%2) > 0 )) && continue 806*906afcb8SAndy Fiddaman fi 807*906afcb8SAndy Fiddaman 808*906afcb8SAndy Fiddaman if [[ ${monster[${currmonster}_"pos_x"]} == ${player["pos_x"]} ]] ; then 809*906afcb8SAndy Fiddaman if (( (monster[${currmonster}_"pos_y"]-player["pos_y"]) > 0 )) ; then 810*906afcb8SAndy Fiddaman (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=-1 )) 811*906afcb8SAndy Fiddaman else 812*906afcb8SAndy Fiddaman (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+1 )) 813*906afcb8SAndy Fiddaman fi 814*906afcb8SAndy Fiddaman monster[${currmonster}_"homing"]=1 815*906afcb8SAndy Fiddaman if (( player["invulnerable"] <= 0 )) ; then 816*906afcb8SAndy Fiddaman player["message"]="Attention: ${currmonster} is chasing you" 817*906afcb8SAndy Fiddaman fi 818*906afcb8SAndy Fiddaman elif (( monster[${currmonster}_"pos_y"] == player["pos_y"] )) ; then 819*906afcb8SAndy Fiddaman if (( (monster[${currmonster}_"pos_x"]-player["pos_x"]) > 0 )) ; then 820*906afcb8SAndy Fiddaman (( monster[${currmonster}_"xstep"]=-1 , monster[${currmonster}_"ystep"]=-0 )) 821*906afcb8SAndy Fiddaman else 822*906afcb8SAndy Fiddaman (( monster[${currmonster}_"xstep"]=+1 , monster[${currmonster}_"ystep"]=+0 )) 823*906afcb8SAndy Fiddaman fi 824*906afcb8SAndy Fiddaman monster[${currmonster}_"homing"]=1 825*906afcb8SAndy Fiddaman if (( player["invulnerable"] <= 0 )) ; then 826*906afcb8SAndy Fiddaman player["message"]="Attention: ${currmonster} is chasing you" 827*906afcb8SAndy Fiddaman fi 828*906afcb8SAndy Fiddaman else 829*906afcb8SAndy Fiddaman if (( monster[${currmonster}_"homing"] == 0 )) ; then 830*906afcb8SAndy Fiddaman case $((SECONDS % 6 + RANDOM % 4)) in 831*906afcb8SAndy Fiddaman 0) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+0 )) ;; 832*906afcb8SAndy Fiddaman 2) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+1 )) ;; 833*906afcb8SAndy Fiddaman 3) (( monster[${currmonster}_"xstep"]=+1 , monster[${currmonster}_"ystep"]=+0 )) ;; 834*906afcb8SAndy Fiddaman 5) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=-1 )) ;; 835*906afcb8SAndy Fiddaman 6) (( monster[${currmonster}_"xstep"]=-1 , monster[${currmonster}_"ystep"]=+0 )) ;; 836*906afcb8SAndy Fiddaman esac 837*906afcb8SAndy Fiddaman fi 838*906afcb8SAndy Fiddaman fi 839*906afcb8SAndy Fiddaman 840*906afcb8SAndy Fiddaman (( monster[${currmonster}_"pos_x"]=monster[${currmonster}_"pos_x"]+monster[${currmonster}_"xstep"] )) 841*906afcb8SAndy Fiddaman (( monster[${currmonster}_"pos_y"]=monster[${currmonster}_"pos_y"]+monster[${currmonster}_"ystep"] )) 842*906afcb8SAndy Fiddaman 843*906afcb8SAndy Fiddaman # check if a monster hit the player 844*906afcb8SAndy Fiddaman if (( player["invulnerable"] <= 0 )) ; then 845*906afcb8SAndy Fiddaman if (( monster[${currmonster}_"pos_x"] == player["pos_x"] && \ 846*906afcb8SAndy Fiddaman monster[${currmonster}_"pos_y"] == player["pos_y"] )) ; then 847*906afcb8SAndy Fiddaman # if player was hit by a monster take one life and 848*906afcb8SAndy Fiddaman # make him invulnerable for 10 cycles to avoid that 849*906afcb8SAndy Fiddaman # the next cycle steals more lives 850*906afcb8SAndy Fiddaman player["message"]="Ouuuchhhh" 851*906afcb8SAndy Fiddaman player["invulnerable"]=10 852*906afcb8SAndy Fiddaman (( player["lives"]-=1 )) 853*906afcb8SAndy Fiddaman 854*906afcb8SAndy Fiddaman beep ; beep ; sleep 0.2 ; beep ; beep 855*906afcb8SAndy Fiddaman fi 856*906afcb8SAndy Fiddaman fi 857*906afcb8SAndy Fiddaman done 858*906afcb8SAndy Fiddaman 859*906afcb8SAndy Fiddaman render_game 860*906afcb8SAndy Fiddaman done 861*906afcb8SAndy Fiddaman return 0 862*906afcb8SAndy Fiddaman} 863*906afcb8SAndy Fiddaman 864*906afcb8SAndy Fiddamanfunction map_filter 865*906afcb8SAndy Fiddaman{ 866*906afcb8SAndy Fiddaman typeset ch_player ch_monster ch_wall var 867*906afcb8SAndy Fiddaman 868*906afcb8SAndy Fiddaman if (( $1 == 1 )) ; then 869*906afcb8SAndy Fiddaman ch_player="${vtcode["fg_yellow"]}" 870*906afcb8SAndy Fiddaman ch_monster="${vtcode["fg_red"]}" 871*906afcb8SAndy Fiddaman ch_wall="${vtcode["fg_blue"]}" 872*906afcb8SAndy Fiddaman else 873*906afcb8SAndy Fiddaman ch_player="" 874*906afcb8SAndy Fiddaman ch_monster="" 875*906afcb8SAndy Fiddaman ch_wall="" 876*906afcb8SAndy Fiddaman fi 877*906afcb8SAndy Fiddaman 878*906afcb8SAndy Fiddaman if (( $2 == 1 )) ; then 879*906afcb8SAndy Fiddaman # unicode map 880*906afcb8SAndy Fiddaman ch_player+="$(printf '\u[24d2]')" 881*906afcb8SAndy Fiddaman ch_monster+="$(printf '\u[2605]')" 882*906afcb8SAndy Fiddaman ch_wall+="$(printf '\u[25a6]')" 883*906afcb8SAndy Fiddaman else 884*906afcb8SAndy Fiddaman # ascii map 885*906afcb8SAndy Fiddaman ch_player+="@" 886*906afcb8SAndy Fiddaman ch_monster+="x" 887*906afcb8SAndy Fiddaman ch_wall+="#" 888*906afcb8SAndy Fiddaman fi 889*906afcb8SAndy Fiddaman 890*906afcb8SAndy Fiddaman # note that this filter currently defeats the "double-buffering" 891*906afcb8SAndy Fiddaman while IFS='' read -r -d "${end_of_frame}" var ; do 892*906afcb8SAndy Fiddaman var="${var// /${vtcode["fg_grey"]} }" 893*906afcb8SAndy Fiddaman var="${var//\./${vtcode["fg_lightred"]}.}" 894*906afcb8SAndy Fiddaman var="${var//@/${ch_player}}" 895*906afcb8SAndy Fiddaman var="${var//x/${ch_monster}}" 896*906afcb8SAndy Fiddaman var="${var//#/${ch_wall}}" 897*906afcb8SAndy Fiddaman 898*906afcb8SAndy Fiddaman print -r -- "${var}" 899*906afcb8SAndy Fiddaman done 900*906afcb8SAndy Fiddaman return 0 901*906afcb8SAndy Fiddaman} 902*906afcb8SAndy Fiddaman 903*906afcb8SAndy Fiddamanfunction exit_trap 904*906afcb8SAndy Fiddaman{ 905*906afcb8SAndy Fiddaman # restore stty settings 906*906afcb8SAndy Fiddaman stty ${saved_stty} 907*906afcb8SAndy Fiddaman 908*906afcb8SAndy Fiddaman print "bye." 909*906afcb8SAndy Fiddaman return 0 910*906afcb8SAndy Fiddaman} 911*906afcb8SAndy Fiddaman 912*906afcb8SAndy Fiddamanfunction usage 913*906afcb8SAndy Fiddaman{ 914*906afcb8SAndy Fiddaman OPTIND=0 915*906afcb8SAndy Fiddaman getopts -a "${progname}" "${gnaw_usage}" OPT '-?' 916*906afcb8SAndy Fiddaman exit 2 917*906afcb8SAndy Fiddaman} 918*906afcb8SAndy Fiddaman 919*906afcb8SAndy Fiddaman# program start 920*906afcb8SAndy Fiddaman# make sure we use the ksh93 "cat" builtin which supports the "-u" option 921*906afcb8SAndy Fiddamanbuiltin basename 922*906afcb8SAndy Fiddamanbuiltin cat 923*906afcb8SAndy Fiddamanbuiltin wc 924*906afcb8SAndy Fiddaman 925*906afcb8SAndy Fiddamantypeset progname="${ basename "${0}" ; }" 926*906afcb8SAndy Fiddaman 927*906afcb8SAndy Fiddaman# terminal size rect 928*906afcb8SAndy Fiddamancompound termsize=( 929*906afcb8SAndy Fiddaman integer columns=-1 930*906afcb8SAndy Fiddaman integer lines=-1 931*906afcb8SAndy Fiddaman) 932*906afcb8SAndy Fiddaman 933*906afcb8SAndy Fiddaman# global variables 934*906afcb8SAndy Fiddamantypeset quiet=false 935*906afcb8SAndy Fiddaman 936*906afcb8SAndy Fiddamantypeset -A levelmap 937*906afcb8SAndy Fiddamantypeset -A player 938*906afcb8SAndy Fiddamantypeset -A monster 939*906afcb8SAndy Fiddaman# global rendering options 940*906afcb8SAndy Fiddamaninteger game_use_colors=0 941*906afcb8SAndy Fiddamaninteger game_use_unicode=0 942*906afcb8SAndy Fiddaman 943*906afcb8SAndy Fiddamantypeset -r gnaw_usage=$'+ 944*906afcb8SAndy Fiddaman[-?\n@(#)\$Id: gnaw (Roland Mainz) 2009-05-09 \$\n] 945*906afcb8SAndy Fiddaman[-author?Roland Mainz <roland.mainz@nrubsig.org>] 946*906afcb8SAndy Fiddaman[+NAME?gnaw - maze game written in ksh93] 947*906afcb8SAndy Fiddaman[+DESCRIPTION?\bgnaw\b is a maze game. 948*906afcb8SAndy Fiddaman The player maneuvers a yellow "@" sign to navigate a maze while eating 949*906afcb8SAndy Fiddaman small dots. A level is finished when all the dots are eaten. Five monsters 950*906afcb8SAndy Fiddaman (maw, claw, jitterbug, tentacle and grendel) also wander the maze in an attempt 951*906afcb8SAndy Fiddaman to catch the "@". Each level begins with all ghosts in their home, and "@" near 952*906afcb8SAndy Fiddaman the bottom of the maze. The monsters are released from the home one by one at the 953*906afcb8SAndy Fiddaman start of each level and start their rentless hunt after the player.] 954*906afcb8SAndy Fiddaman[q:quiet?Disable use of terminal bell.] 955*906afcb8SAndy Fiddaman[+SEE ALSO?\bksh93\b(1)] 956*906afcb8SAndy Fiddaman' 957*906afcb8SAndy Fiddaman 958*906afcb8SAndy Fiddamanwhile getopts -a "${progname}" "${gnaw_usage}" OPT ; do 959*906afcb8SAndy Fiddaman# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" 960*906afcb8SAndy Fiddaman case ${OPT} in 961*906afcb8SAndy Fiddaman q) quiet=true ;; 962*906afcb8SAndy Fiddaman +q) quiet=false ;; 963*906afcb8SAndy Fiddaman *) usage ;; 964*906afcb8SAndy Fiddaman esac 965*906afcb8SAndy Fiddamandone 966*906afcb8SAndy Fiddamanshift $((OPTIND-1)) 967*906afcb8SAndy Fiddaman 968*906afcb8SAndy Fiddaman# save stty values and register the exit trap which restores these values on exit 969*906afcb8SAndy Fiddamansaved_stty="$(stty -g)" 970*906afcb8SAndy Fiddamantrap exit_trap EXIT 971*906afcb8SAndy Fiddaman 972*906afcb8SAndy Fiddamanprint "Loading..." 973*906afcb8SAndy Fiddaman 974*906afcb8SAndy Fiddaman# set stty values, "-icanon min 1 time 0 -inpck" should improve input latency, 975*906afcb8SAndy Fiddaman# "-echo" turns the terminal echo off 976*906afcb8SAndy Fiddamanstty -icanon min 1 time 0 -inpck -echo 977*906afcb8SAndy Fiddaman 978*906afcb8SAndy Fiddamanget_term_size termsize || fatal_error "Could not get terminal size." 979*906afcb8SAndy Fiddaman 980*906afcb8SAndy Fiddaman# prechecks 981*906afcb8SAndy Fiddaman(( termsize.columns < 60 )) && fatal_error "Terminal width must be larger than 60 columns (currently ${termsize.columns})." 982*906afcb8SAndy Fiddaman 983*906afcb8SAndy Fiddamantypeset -A vtcode 984*906afcb8SAndy Fiddaman# color values taken from http://frexx.de/xterm-256-notes/, other 985*906afcb8SAndy Fiddaman# codes from http://vt100.net/docs/vt100-tm/ 986*906afcb8SAndy Fiddamanvtcode=( 987*906afcb8SAndy Fiddaman ["bg_black"]="$(print -n "\E[40m")" 988*906afcb8SAndy Fiddaman ["fg_black"]="$(print -n "\E[30m")" 989*906afcb8SAndy Fiddaman ["fg_red"]="$(print -n "\E[31m")" 990*906afcb8SAndy Fiddaman ["fg_lightred"]="$(print -n "\E[1;31m")" 991*906afcb8SAndy Fiddaman ["fg_green"]="$(print -n "\E[32m")" 992*906afcb8SAndy Fiddaman ["fg_lightgreen"]="$(print -n "\E[1;32m")" 993*906afcb8SAndy Fiddaman ["fg_yellow"]="$(print -n "\E[33m")" 994*906afcb8SAndy Fiddaman ["fg_lightyellow"]="$(print -n "\E[1;33m")" 995*906afcb8SAndy Fiddaman ["fg_blue"]="$(print -n "\E[34m")" 996*906afcb8SAndy Fiddaman ["fg_lightblue"]="$(print -n "\E[1;34m")" 997*906afcb8SAndy Fiddaman ["fg_grey"]="$(print -n "\E[1;37m")" 998*906afcb8SAndy Fiddaman ["fg_white"]="$(print -n "\E[37m")" 999*906afcb8SAndy Fiddaman 1000*906afcb8SAndy Fiddaman # misc other vt stuff 1001*906afcb8SAndy Fiddaman ["vtreset"]="$(tput reset)" 1002*906afcb8SAndy Fiddaman ["clear"]="$(tput clear)" 1003*906afcb8SAndy Fiddaman ["bel"]="$(tput bel)" 1004*906afcb8SAndy Fiddaman ["spaceline"]="$(for (( i=0 ; i < termsize.columns ; i++ )) ; do print -n " " ; done)" 1005*906afcb8SAndy Fiddaman) 1006*906afcb8SAndy Fiddaman 1007*906afcb8SAndy Fiddaman# character used to as marker that a single frame ends at this point - this 1008*906afcb8SAndy Fiddaman# is used by the "double buffering" code to make sure the "read" builtin 1009*906afcb8SAndy Fiddaman# can read a whole "frame" instead of reading stuff line-by-line 1010*906afcb8SAndy Fiddamantypeset -r end_of_frame=$'\t' 1011*906afcb8SAndy Fiddaman 1012*906afcb8SAndy Fiddaman# get terminal sequence to move cursor to position x,y 1013*906afcb8SAndy Fiddaman# (see http://vt100.net/docs/vt100-ug/chapter3.html#CPR) 1014*906afcb8SAndy Fiddamancase ${TERM} in 1015*906afcb8SAndy Fiddaman xterm | xterm-color | vt100 | vt220 | dtterm | sun | sun-color) 1016*906afcb8SAndy Fiddaman cup="$(infocmp -1 | \ 1017*906afcb8SAndy Fiddaman egrep '^[[:space:]]*cup=' | \ 1018*906afcb8SAndy Fiddaman sed -e 's/.*cup=//' \ 1019*906afcb8SAndy Fiddaman -e 's/%[%id]*p1[%id]*/%2\\\$d/g' \ 1020*906afcb8SAndy Fiddaman -e 's/%[%id]*p2[%id]*/%1\\\$d/g' \ 1021*906afcb8SAndy Fiddaman -e 's/,$//')" 1022*906afcb8SAndy Fiddaman for (( x=0 ; x < termsize.columns ; x++ )) ; do 1023*906afcb8SAndy Fiddaman for (( y=0 ; y < termsize.lines ; y++ )) ; do 1024*906afcb8SAndy Fiddaman vtcode[cup_${x}_${y}]="$(printf "${cup}" $((x + 1)) $((y + 1)) )" 1025*906afcb8SAndy Fiddaman done 1026*906afcb8SAndy Fiddaman done 1027*906afcb8SAndy Fiddaman ;; 1028*906afcb8SAndy Fiddaman *) 1029*906afcb8SAndy Fiddaman printf "# Unrecognised terminal type '%s', fetching %dx%d items from terminfo database, please wait...\n" "${TERM}" "${termsize.columns}" "${termsize.lines}" 1030*906afcb8SAndy Fiddaman for (( x=0 ; x < termsize.columns ; x++ )) ; do 1031*906afcb8SAndy Fiddaman for (( y=0 ; y < termsize.lines ; y++ )) ; do 1032*906afcb8SAndy Fiddaman vtcode[cup_${x}_${y}]="$(tput cup ${y} ${x})" 1033*906afcb8SAndy Fiddaman done 1034*906afcb8SAndy Fiddaman done 1035*906afcb8SAndy Fiddaman ;; 1036*906afcb8SAndy Fiddamanesac 1037*906afcb8SAndy Fiddaman 1038*906afcb8SAndy Fiddamanprint -- "${vtcode["vtreset"]}" 1039*906afcb8SAndy Fiddaman 1040*906afcb8SAndy Fiddamanrun_logo 1041*906afcb8SAndy Fiddamanrun_menu 1042*906afcb8SAndy Fiddaman 1043*906afcb8SAndy Fiddamanexit 0 1044*906afcb8SAndy Fiddaman# EOF. 1045