18462SApril.Chin@Sun.COM#!/usr/bin/ksh93 28462SApril.Chin@Sun.COM 38462SApril.Chin@Sun.COM# 48462SApril.Chin@Sun.COM# CDDL HEADER START 58462SApril.Chin@Sun.COM# 68462SApril.Chin@Sun.COM# The contents of this file are subject to the terms of the 78462SApril.Chin@Sun.COM# Common Development and Distribution License (the "License"). 88462SApril.Chin@Sun.COM# You may not use this file except in compliance with the License. 98462SApril.Chin@Sun.COM# 108462SApril.Chin@Sun.COM# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 118462SApril.Chin@Sun.COM# or http://www.opensolaris.org/os/licensing. 128462SApril.Chin@Sun.COM# See the License for the specific language governing permissions 138462SApril.Chin@Sun.COM# and limitations under the License. 148462SApril.Chin@Sun.COM# 158462SApril.Chin@Sun.COM# When distributing Covered Code, include this CDDL HEADER in each 168462SApril.Chin@Sun.COM# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 178462SApril.Chin@Sun.COM# If applicable, add the following below this CDDL HEADER, with the 188462SApril.Chin@Sun.COM# fields enclosed by brackets "[]" replaced with your own identifying 198462SApril.Chin@Sun.COM# information: Portions Copyright [yyyy] [name of copyright owner] 208462SApril.Chin@Sun.COM# 218462SApril.Chin@Sun.COM# CDDL HEADER END 228462SApril.Chin@Sun.COM# 238462SApril.Chin@Sun.COM 248462SApril.Chin@Sun.COM# 25*12068SRoger.Faulkner@Oracle.COM# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 268462SApril.Chin@Sun.COM# 278462SApril.Chin@Sun.COM 288462SApril.Chin@Sun.COM# 298462SApril.Chin@Sun.COM# gnaw - a simple ksh93 technology demo 308462SApril.Chin@Sun.COM# 318462SApril.Chin@Sun.COM# Note that this script has been written with the main idea to show 328462SApril.Chin@Sun.COM# many of ksh93's new features (comparing to ksh88/bash) and not 338462SApril.Chin@Sun.COM# as an example of efficient&&clean script code (much of the code 348462SApril.Chin@Sun.COM# could be done more efficient using compound variables, this script 358462SApril.Chin@Sun.COM# focus is the usage of associative arrays). 368462SApril.Chin@Sun.COM# 378462SApril.Chin@Sun.COM 388462SApril.Chin@Sun.COM# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant 398462SApril.Chin@Sun.COMexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin 408462SApril.Chin@Sun.COM 418462SApril.Chin@Sun.COM# Make sure all math stuff runs in the "C" locale to avoid problems 428462SApril.Chin@Sun.COM# with alternative # radix point representations (e.g. ',' instead of 438462SApril.Chin@Sun.COM# '.' in de_DE.*-locales). This needs to be set _before_ any 448462SApril.Chin@Sun.COM# floating-point constants are defined in this script). 458462SApril.Chin@Sun.COMif [[ "${LC_ALL}" != "" ]] ; then 468462SApril.Chin@Sun.COM export \ 478462SApril.Chin@Sun.COM LC_MONETARY="${LC_ALL}" \ 488462SApril.Chin@Sun.COM LC_MESSAGES="${LC_ALL}" \ 498462SApril.Chin@Sun.COM LC_COLLATE="${LC_ALL}" \ 508462SApril.Chin@Sun.COM LC_CTYPE="${LC_ALL}" 518462SApril.Chin@Sun.COM unset LC_ALL 528462SApril.Chin@Sun.COMfi 538462SApril.Chin@Sun.COMexport LC_NUMERIC=C 548462SApril.Chin@Sun.COM 558462SApril.Chin@Sun.COMfunction print_setcursorpos 568462SApril.Chin@Sun.COM{ 578462SApril.Chin@Sun.COM print -n -- "${vtcode[cup_${1}_${2}]}" 588462SApril.Chin@Sun.COM} 598462SApril.Chin@Sun.COM 608462SApril.Chin@Sun.COMfunction beep 618462SApril.Chin@Sun.COM{ 628462SApril.Chin@Sun.COM ${quiet} || print -n -- "${vtcode["bel"]}" 638462SApril.Chin@Sun.COM} 648462SApril.Chin@Sun.COM 658462SApril.Chin@Sun.COMfunction fatal_error 668462SApril.Chin@Sun.COM{ 678462SApril.Chin@Sun.COM print -u2 "${progname}: $*" 688462SApril.Chin@Sun.COM exit 1 698462SApril.Chin@Sun.COM} 708462SApril.Chin@Sun.COM 718462SApril.Chin@Sun.COM# Get terminal size and put values into a compound variable with the integer 728462SApril.Chin@Sun.COM# members "columns" and "lines" 738462SApril.Chin@Sun.COMfunction get_term_size 748462SApril.Chin@Sun.COM{ 758462SApril.Chin@Sun.COM nameref rect=$1 768462SApril.Chin@Sun.COM 778462SApril.Chin@Sun.COM rect.columns=${ tput cols ; } || return 1 788462SApril.Chin@Sun.COM rect.lines=${ tput lines ; } || return 1 798462SApril.Chin@Sun.COM 808462SApril.Chin@Sun.COM return 0 818462SApril.Chin@Sun.COM} 828462SApril.Chin@Sun.COM 838462SApril.Chin@Sun.COMfunction print_levelmap 848462SApril.Chin@Sun.COM{ 858462SApril.Chin@Sun.COM integer screen_y_offset=$1 868462SApril.Chin@Sun.COM integer start_y_pos=$2 # start at this line in the map 878462SApril.Chin@Sun.COM integer max_numlines=$3 # maximum lines we're allowed to render 888462SApril.Chin@Sun.COM integer x 898462SApril.Chin@Sun.COM integer y 908462SApril.Chin@Sun.COM typeset line="" 918462SApril.Chin@Sun.COM 928462SApril.Chin@Sun.COM print_setcursorpos 0 ${screen_y_offset} 938462SApril.Chin@Sun.COM 948462SApril.Chin@Sun.COM for (( y=start_y_pos; (y-start_y_pos) < max_numlines && y < levelmap["max_y"] ; y++ )) ; do 958462SApril.Chin@Sun.COM line="" 968462SApril.Chin@Sun.COM for (( x=0 ; x < levelmap["max_x"] ; x++ )) ; do 978462SApril.Chin@Sun.COM line+="${levelmap["${x}_${y}"]}" 988462SApril.Chin@Sun.COM done 998462SApril.Chin@Sun.COM 1008462SApril.Chin@Sun.COM print -- "${line} " 1018462SApril.Chin@Sun.COM done 1028462SApril.Chin@Sun.COM 1038462SApril.Chin@Sun.COM # print lines filled with spaces for each line not filled 1048462SApril.Chin@Sun.COM # by the level map 1058462SApril.Chin@Sun.COM line="${vtcode["spaceline"]:0:${levelmap["max_x"]}}" 1068462SApril.Chin@Sun.COM for (( ; (y-start_y_pos) < max_numlines ; y++ )) ; do 1078462SApril.Chin@Sun.COM print -- "${line} " 1088462SApril.Chin@Sun.COM done 1098462SApril.Chin@Sun.COM return 0 1108462SApril.Chin@Sun.COM} 1118462SApril.Chin@Sun.COM 1128462SApril.Chin@Sun.COMfunction level_completed 1138462SApril.Chin@Sun.COM{ 1148462SApril.Chin@Sun.COM integer i 1158462SApril.Chin@Sun.COM typeset dummy 1168462SApril.Chin@Sun.COM typeset render_buffer="$( 1178462SApril.Chin@Sun.COM print -n -- "${vtcode["clear"]}" 1188462SApril.Chin@Sun.COM cat <<ENDOFTEXT 1198462SApril.Chin@Sun.COM 1208462SApril.Chin@Sun.COM # ###### # # ###### # 1218462SApril.Chin@Sun.COM # # # # # # 1228462SApril.Chin@Sun.COM # ##### # # ##### # 1238462SApril.Chin@Sun.COM # # # # # # 1248462SApril.Chin@Sun.COM # # # # # # 1258462SApril.Chin@Sun.COM ###### ###### ## ###### ###### 1268462SApril.Chin@Sun.COM 1278462SApril.Chin@Sun.COM (Good job) 1288462SApril.Chin@Sun.COM 1298462SApril.Chin@Sun.COM ##### #### # # ###### 1308462SApril.Chin@Sun.COM # # # # ## # # 1318462SApril.Chin@Sun.COM # # # # # # # ##### 1328462SApril.Chin@Sun.COM # # # # # # # # 1338462SApril.Chin@Sun.COM # # # # # ## # 1348462SApril.Chin@Sun.COM ##### #### # # ###### 1358462SApril.Chin@Sun.COM 1368462SApril.Chin@Sun.COM 1378462SApril.Chin@Sun.COMENDOFTEXT 1388462SApril.Chin@Sun.COM 1398462SApril.Chin@Sun.COM printf " SCORE: --> %s <--\n" "${player["score"]}" 1408462SApril.Chin@Sun.COM printf " LIVES: --> %s <--\n" "${player["lives"]}" 1418462SApril.Chin@Sun.COM )" 1428462SApril.Chin@Sun.COM print -- "${render_buffer}${end_of_frame}" 1438462SApril.Chin@Sun.COM 1448462SApril.Chin@Sun.COM # wait five seconds and swallow any user input 1458462SApril.Chin@Sun.COM for (( i=0 ; i < 50 ; i++ )) ; do 1468462SApril.Chin@Sun.COM read -r -t 0.1 -n 1 dummy 1478462SApril.Chin@Sun.COM done 1488462SApril.Chin@Sun.COM 1498462SApril.Chin@Sun.COM print "Press any key to continue...${end_of_frame}" 1508462SApril.Chin@Sun.COM # wait five secs or for a key 1518462SApril.Chin@Sun.COM read -r -t 5 -n 1 dummy 1528462SApril.Chin@Sun.COM return 0 1538462SApril.Chin@Sun.COM} 1548462SApril.Chin@Sun.COM 1558462SApril.Chin@Sun.COMfunction game_over 1568462SApril.Chin@Sun.COM{ 1578462SApril.Chin@Sun.COM typeset dummy 1588462SApril.Chin@Sun.COM typeset render_buffer="$( 1598462SApril.Chin@Sun.COM print -n -- "${vtcode["clear"]}" 1608462SApril.Chin@Sun.COM cat <<ENDOFTEXT 1618462SApril.Chin@Sun.COM 1628462SApril.Chin@Sun.COM #### ## # # ###### 1638462SApril.Chin@Sun.COM # # # # ## ## # 1648462SApril.Chin@Sun.COM # # # # ## # ##### 1658462SApril.Chin@Sun.COM # ### ###### # # # 1668462SApril.Chin@Sun.COM # # # # # # # 1678462SApril.Chin@Sun.COM #### # # # # ###### 1688462SApril.Chin@Sun.COM 1698462SApril.Chin@Sun.COM (LOSER!) 1708462SApril.Chin@Sun.COM 1718462SApril.Chin@Sun.COM #### # # ###### ##### 1728462SApril.Chin@Sun.COM # # # # # # # 1738462SApril.Chin@Sun.COM # # # # ##### # # 1748462SApril.Chin@Sun.COM # # # # # ##### 1758462SApril.Chin@Sun.COM # # # # # # # 1768462SApril.Chin@Sun.COM #### ## ###### # # 1778462SApril.Chin@Sun.COM 1788462SApril.Chin@Sun.COMENDOFTEXT 1798462SApril.Chin@Sun.COM 1808462SApril.Chin@Sun.COM printf "\n SCORE: --> %s <--\n" "${player["score"]}" 1818462SApril.Chin@Sun.COM )" 1828462SApril.Chin@Sun.COM print -r -- "${render_buffer}${end_of_frame}" 1838462SApril.Chin@Sun.COM 1848462SApril.Chin@Sun.COM # wait five seconds and swallow any user input 1858462SApril.Chin@Sun.COM for (( i=0 ; i < 50 ; i++ )) ; do 1868462SApril.Chin@Sun.COM read -r -t 0.1 -n 1 dummy 1878462SApril.Chin@Sun.COM done 1888462SApril.Chin@Sun.COM 1898462SApril.Chin@Sun.COM print "Press any key to continue...${end_of_frame}" 1908462SApril.Chin@Sun.COM # wait five secs or for a key 1918462SApril.Chin@Sun.COM read -r -t 5 -n 1 dummy 1928462SApril.Chin@Sun.COM return 0 1938462SApril.Chin@Sun.COM} 1948462SApril.Chin@Sun.COM 1958462SApril.Chin@Sun.COMfunction run_logo 1968462SApril.Chin@Sun.COM{ 1978462SApril.Chin@Sun.COM typeset render_buffer="$( 1988462SApril.Chin@Sun.COM cat <<ENDOFTEXT 1998462SApril.Chin@Sun.COM 2008462SApril.Chin@Sun.COM ##### # # # # # ### 2018462SApril.Chin@Sun.COM# # ## # # # # # # ### 2028462SApril.Chin@Sun.COM# # # # # # # # # ### 2038462SApril.Chin@Sun.COM# #### # # # # # # # # # 2048462SApril.Chin@Sun.COM# # # # # ####### # # # 2058462SApril.Chin@Sun.COM# # # ## # # # # # ### 2068462SApril.Chin@Sun.COM ##### # # # # ## ## ### 2078462SApril.Chin@Sun.COMENDOFTEXT 2088462SApril.Chin@Sun.COM )" 2098462SApril.Chin@Sun.COM print -- "${vtcode["clear"]}${render_buffer}" 2108462SApril.Chin@Sun.COM 2118462SApril.Chin@Sun.COM # wait two seconds and swallow any user input 2128462SApril.Chin@Sun.COM for (( i=0 ; i < 20 ; i++ )) ; do 2138462SApril.Chin@Sun.COM read -r -t 0.1 -n 1 dummy 2148462SApril.Chin@Sun.COM done 2158462SApril.Chin@Sun.COM 2168462SApril.Chin@Sun.COM print "\n (The KornShell 93 maze game)" 2178462SApril.Chin@Sun.COM 2188462SApril.Chin@Sun.COM attract_mode 2198462SApril.Chin@Sun.COM return 0 2208462SApril.Chin@Sun.COM} 2218462SApril.Chin@Sun.COM 2228462SApril.Chin@Sun.COMfunction attract_mode 2238462SApril.Chin@Sun.COM{ 2248462SApril.Chin@Sun.COM( 2258462SApril.Chin@Sun.COM # Now present some info, line-by-line in an endless loop 2268462SApril.Chin@Sun.COM # until the user presses a key (we turn the "magic" return 2278462SApril.Chin@Sun.COM # code for that) 2288462SApril.Chin@Sun.COM integer -r magic_return_code=69 2298462SApril.Chin@Sun.COM typeset line 2308462SApril.Chin@Sun.COM IFS='' ; # Make sure we do not swallow whitespaces 2318462SApril.Chin@Sun.COM 2328462SApril.Chin@Sun.COM while true ; do 2338462SApril.Chin@Sun.COM ( 2348462SApril.Chin@Sun.COM redirect 5<&0 2358462SApril.Chin@Sun.COM 2368462SApril.Chin@Sun.COM (cat <<ENDOFTEXT 2378462SApril.Chin@Sun.COM 2388462SApril.Chin@Sun.COM 2398462SApril.Chin@Sun.COM 2408462SApril.Chin@Sun.COM 2418462SApril.Chin@Sun.COM 2428462SApril.Chin@Sun.COM ################ 2438462SApril.Chin@Sun.COM ######################## 2448462SApril.Chin@Sun.COM ############################ 2458462SApril.Chin@Sun.COM ####### ###### ####### 2468462SApril.Chin@Sun.COM ###### ###### ######## 2478462SApril.Chin@Sun.COM ####### ###### ####### 2488462SApril.Chin@Sun.COM ############################## 2498462SApril.Chin@Sun.COM ############################## 2508462SApril.Chin@Sun.COM ############################## 2518462SApril.Chin@Sun.COM ############################## 2528462SApril.Chin@Sun.COM ############################## 2538462SApril.Chin@Sun.COM ######### ######## ######### 2548462SApril.Chin@Sun.COM # #### #### #### # 2558462SApril.Chin@Sun.COM 2568462SApril.Chin@Sun.COM 2578462SApril.Chin@Sun.COM 2588462SApril.Chin@Sun.COM 2598462SApril.Chin@Sun.COM 2608462SApril.Chin@Sun.COM 2618462SApril.Chin@Sun.COM Written by 2628462SApril.Chin@Sun.COM 2638462SApril.Chin@Sun.COM Roland Mainz 2648462SApril.Chin@Sun.COM (roland.mainz@nrubsig.org) 2658462SApril.Chin@Sun.COM 2668462SApril.Chin@Sun.COM 2678462SApril.Chin@Sun.COM 2688462SApril.Chin@Sun.COM 2698462SApril.Chin@Sun.COM 2708462SApril.Chin@Sun.COM 2718462SApril.Chin@Sun.COM ############## 2728462SApril.Chin@Sun.COM ######################## 2738462SApril.Chin@Sun.COM #################**############ 2748462SApril.Chin@Sun.COM ################################ 2758462SApril.Chin@Sun.COM ############################ 2768462SApril.Chin@Sun.COM ###################### 2778462SApril.Chin@Sun.COM ################ 2788462SApril.Chin@Sun.COM ###################### 2798462SApril.Chin@Sun.COM ############################ 2808462SApril.Chin@Sun.COM ################################ 2818462SApril.Chin@Sun.COM ############################## 2828462SApril.Chin@Sun.COM ######################## 2838462SApril.Chin@Sun.COM ############## 2848462SApril.Chin@Sun.COM 2858462SApril.Chin@Sun.COM 2868462SApril.Chin@Sun.COM 2878462SApril.Chin@Sun.COM 2888462SApril.Chin@Sun.COM 2898462SApril.Chin@Sun.COM 2908462SApril.Chin@Sun.COM 2918462SApril.Chin@Sun.COM High scores: 2928462SApril.Chin@Sun.COM 2938462SApril.Chin@Sun.COM * 'chin' 8200 pt 2948462SApril.Chin@Sun.COM * 'gisburn' 7900 pt 2958462SApril.Chin@Sun.COM * 'tpenta' 5520 pt 2968462SApril.Chin@Sun.COM * 'kupfer' 5510 pt 2978462SApril.Chin@Sun.COM * 'noname' 5000 pt 2988462SApril.Chin@Sun.COM * 'noname' 4000 pt 2998462SApril.Chin@Sun.COM * 'livad' 3120 pt 3008462SApril.Chin@Sun.COM * 'noname' 3000 pt 3018462SApril.Chin@Sun.COM * 'noname' 2000 pt 3028462SApril.Chin@Sun.COM * 'noname' 1000 pt 3038462SApril.Chin@Sun.COM 3048462SApril.Chin@Sun.COMENDOFTEXT 3058462SApril.Chin@Sun.COM 3068462SApril.Chin@Sun.COM # clear screen, line-by-line 3078462SApril.Chin@Sun.COM for (( i=0 ; i < termsize.lines ; i++ )) ; do print "" ; done 3088462SApril.Chin@Sun.COM ) | (while read -r line ; do 3098462SApril.Chin@Sun.COM read -r -t 0.3 -n 1 c <&5 3108462SApril.Chin@Sun.COM [[ "$c" != "" ]] && exit ${magic_return_code} 3118462SApril.Chin@Sun.COM print -- "${line}" 3128462SApril.Chin@Sun.COM done) 3138462SApril.Chin@Sun.COM (( $? == magic_return_code )) && exit ${magic_return_code} 3148462SApril.Chin@Sun.COM ) 3158462SApril.Chin@Sun.COM (( $? == magic_return_code )) && return 0 3168462SApril.Chin@Sun.COM 3178462SApril.Chin@Sun.COM sleep 2 3188462SApril.Chin@Sun.COM done 3198462SApril.Chin@Sun.COM) 3208462SApril.Chin@Sun.COM} 3218462SApril.Chin@Sun.COM 3228462SApril.Chin@Sun.COMfunction run_menu 3238462SApril.Chin@Sun.COM{ 3248462SApril.Chin@Sun.COM integer numlevels=0 3258462SApril.Chin@Sun.COM integer selected_level=0 3268462SApril.Chin@Sun.COM typeset l 3278462SApril.Chin@Sun.COM 3288462SApril.Chin@Sun.COM # built list of available levels based on the "function levelmap_.*" 3298462SApril.Chin@Sun.COM # built into this script 3308462SApril.Chin@Sun.COM typeset -f | egrep "^function.*levelmap_.*" | sed 's/^function //' | 3318462SApril.Chin@Sun.COM while read -r l ; do 3328462SApril.Chin@Sun.COM levellist[numlevels]="$l" 3338462SApril.Chin@Sun.COM numlevels+=1 3348462SApril.Chin@Sun.COM done 3358462SApril.Chin@Sun.COM 3368462SApril.Chin@Sun.COM # swallow any queued user input (e.g. drain stdin) 3378462SApril.Chin@Sun.COM read -r -t 0.1 -n 100 dummy 3388462SApril.Chin@Sun.COM 3398462SApril.Chin@Sun.COM while true ; do 3408462SApril.Chin@Sun.COM # menu loop with timeout (which switches to "attract mode") 3418462SApril.Chin@Sun.COM while true ; do 3428462SApril.Chin@Sun.COM print -n -- "${vtcode["clear"]}" 3438462SApril.Chin@Sun.COM 3448462SApril.Chin@Sun.COM cat <<ENDOFTEXT 3458462SApril.Chin@Sun.COM>======================================\ 3468462SApril.Chin@Sun.COM> /-\ .--. | 3478462SApril.Chin@Sun.COM> | OO| / _.-' .-. .-. .-. .-. | 3488462SApril.Chin@Sun.COM> | | \ '-. '-' '-' '-' '-' | 3498462SApril.Chin@Sun.COM> ^^^^^ '--' | 3508462SApril.Chin@Sun.COM>======\ /================\ .-. | 3518462SApril.Chin@Sun.COM> | | | '-' | 3528462SApril.Chin@Sun.COM ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3538462SApril.Chin@Sun.COMENDOFTEXT 3548462SApril.Chin@Sun.COM print " GNAW - the ksh93 maze game" 3558462SApril.Chin@Sun.COM print "\n\tMenu:" 3568462SApril.Chin@Sun.COM 3578462SApril.Chin@Sun.COM print "\t - [L]evels:" 3588462SApril.Chin@Sun.COM for (( i=0 ; i < numlevels ; i++ )) ; do 3598462SApril.Chin@Sun.COM printf "\t %s %s \n" "$( (( i == selected_level )) && print -n "*" || print -n " ")" "${levellist[i]##levelmap_}" 3608462SApril.Chin@Sun.COM done 3618462SApril.Chin@Sun.COM 3628462SApril.Chin@Sun.COM print "\t - Rendering options:" 3638462SApril.Chin@Sun.COM printf "\t [%s] Use [U]nicode\n" "$( (( game_use_unicode == 1 )) && print -n "x" || print -n "_" )" 3648462SApril.Chin@Sun.COM printf "\t [%s] Use [C]olors\n" "$( (( game_use_colors == 1 )) && print -n "x" || print -n "_" )" 3658462SApril.Chin@Sun.COM 3668462SApril.Chin@Sun.COM print "\t - [S]tart - [Q]uit" 3678462SApril.Chin@Sun.COM 3688462SApril.Chin@Sun.COM # wait 30 secs (before we switch to "attract mode") 3698462SApril.Chin@Sun.COM c="" ; read -r -t 30 -n 1 c 3708462SApril.Chin@Sun.COM case "$c" in 3718462SApril.Chin@Sun.COM 'l') (( selected_level=(selected_level+numlevels+1) % numlevels )) ;; 3728462SApril.Chin@Sun.COM 'L') (( selected_level=(selected_level+numlevels-1) % numlevels )) ;; 3738462SApril.Chin@Sun.COM ~(Fi)s) 3748462SApril.Chin@Sun.COM (( game_use_colors == 1 )) && print -- "${vtcode["bg_black"]}" 3758462SApril.Chin@Sun.COM case "${game_use_colors}${game_use_unicode}" in 3768462SApril.Chin@Sun.COM "00") main_loop "${levellist[selected_level]}" ;; 3778462SApril.Chin@Sun.COM "01") main_loop "${levellist[selected_level]}" | map_filter 0 1 ;; 3788462SApril.Chin@Sun.COM "10") main_loop "${levellist[selected_level]}" | map_filter 1 0 ;; 3798462SApril.Chin@Sun.COM "11") main_loop "${levellist[selected_level]}" | map_filter 1 1 ;; 3808462SApril.Chin@Sun.COM esac 3818462SApril.Chin@Sun.COM print -- "${vtcode["vtreset"]}" 3828462SApril.Chin@Sun.COM ;; 3838462SApril.Chin@Sun.COM ~(Fi)q | $'\E') 3848462SApril.Chin@Sun.COM # make sure we do not exit on a cursor key (e.g. <esc>[A,B,C,D) 3858462SApril.Chin@Sun.COM read -r -t 0.01 -n 1 c 3868462SApril.Chin@Sun.COM if [[ "$c" == "[" ]] ; then 3878462SApril.Chin@Sun.COM # this was a cursor key sequence, just eat the 3rd charcater 3888462SApril.Chin@Sun.COM read -r -t 0.01 -n 1 c 3898462SApril.Chin@Sun.COM else 3908462SApril.Chin@Sun.COM exit 0 3918462SApril.Chin@Sun.COM fi 3928462SApril.Chin@Sun.COM ;; 3938462SApril.Chin@Sun.COM ~(Fi)u) (( game_use_unicode=(game_use_unicode+2+1) % 2)) ;; 3948462SApril.Chin@Sun.COM ~(Fi)c) (( game_use_colors=(game_use_colors+2+1) % 2)) ;; 3958462SApril.Chin@Sun.COM "") break ;; # timeout, switch to attract mode 3968462SApril.Chin@Sun.COM *) beep ;; 3978462SApril.Chin@Sun.COM esac 3988462SApril.Chin@Sun.COM done 3998462SApril.Chin@Sun.COM 4008462SApril.Chin@Sun.COM print -n -- "${vtcode["clear"]}" 4018462SApril.Chin@Sun.COM attract_mode 4028462SApril.Chin@Sun.COM done 4038462SApril.Chin@Sun.COM return 0 4048462SApril.Chin@Sun.COM} 4058462SApril.Chin@Sun.COM 4068462SApril.Chin@Sun.COMfunction levelmap_stripes 4078462SApril.Chin@Sun.COM{ 4088462SApril.Chin@Sun.COMcat <<ENDOFLEVEL 4098462SApril.Chin@Sun.COM################################### 4108462SApril.Chin@Sun.COM#....... ............... P # 4118462SApril.Chin@Sun.COM#########..#################..### # 4128462SApril.Chin@Sun.COM#########..#################..### # 4138462SApril.Chin@Sun.COM#....... .. ..............# # 4148462SApril.Chin@Sun.COM############### ################ # 4158462SApril.Chin@Sun.COM############### ################ # 4168462SApril.Chin@Sun.COM#............. M ..............# # 4178462SApril.Chin@Sun.COM##..##################### ###### # 4188462SApril.Chin@Sun.COM##..##################### ###### # 4198462SApril.Chin@Sun.COM#....... ........... .......# # 4208462SApril.Chin@Sun.COM######## ############ ######### # 4218462SApril.Chin@Sun.COM# #### ############ ######### # 4228462SApril.Chin@Sun.COM# #.................. ......# # 4238462SApril.Chin@Sun.COM# ############################### # 4248462SApril.Chin@Sun.COM# # 4258462SApril.Chin@Sun.COM################################### 4268462SApril.Chin@Sun.COMENDOFLEVEL 4278462SApril.Chin@Sun.COM return 0 4288462SApril.Chin@Sun.COM} 4298462SApril.Chin@Sun.COM 4308462SApril.Chin@Sun.COMfunction levelmap_livad 4318462SApril.Chin@Sun.COM{ 4328462SApril.Chin@Sun.COMcat <<ENDOFLEVEL 4338462SApril.Chin@Sun.COM##################################################### 4348462SApril.Chin@Sun.COM# # 4358462SApril.Chin@Sun.COM# ############## ############### ################ # 4368462SApril.Chin@Sun.COM# #............ P ..............# # 4378462SApril.Chin@Sun.COM# .#############################################.# # 4388462SApril.Chin@Sun.COM# #.#.......... ............#. # 4398462SApril.Chin@Sun.COM# #.#.########## ############### ############.#.# # 4408462SApril.Chin@Sun.COM# #...#........ ..........#...# # 4418462SApril.Chin@Sun.COM# #...#.#####################################.#.#.# # 4428462SApril.Chin@Sun.COM# #...#.#...... ........#...#.# # 4438462SApril.Chin@Sun.COM# #.#.#...###### #########################.#.#.#.# # 4448462SApril.Chin@Sun.COM# .#.....#.... M ......#...#.#.# # 4458462SApril.Chin@Sun.COM# #.#.#...####################### ########.#.#.#.# # 4468462SApril.Chin@Sun.COM# #...#.#...... ........#...#.# # 4478462SApril.Chin@Sun.COM# #...#.######## ############### ##########.#.#.# # 4488462SApril.Chin@Sun.COM# #...#........ ..........#...# # 4498462SApril.Chin@Sun.COM# #.#.#########################################.#.# # 4508462SApril.Chin@Sun.COM# #.#.......... ............#. # 4518462SApril.Chin@Sun.COM# .############ ############### ##############.# # 4528462SApril.Chin@Sun.COM# #............ ..............# # 4538462SApril.Chin@Sun.COM# ################################################# # 4548462SApril.Chin@Sun.COM# # 4558462SApril.Chin@Sun.COM##################################################### 4568462SApril.Chin@Sun.COMENDOFLEVEL 4578462SApril.Chin@Sun.COM return 0 4588462SApril.Chin@Sun.COM} 4598462SApril.Chin@Sun.COM 4608462SApril.Chin@Sun.COMfunction levelmap_classic1 4618462SApril.Chin@Sun.COM{ 4628462SApril.Chin@Sun.COMcat <<ENDOFLEVEL 4638462SApril.Chin@Sun.COM######################### 4648462SApril.Chin@Sun.COM#.P.........#...........# 4658462SApril.Chin@Sun.COM#.####.####.#.####.####.# 4668462SApril.Chin@Sun.COM#.# #.# #.#.# #.# #.# 4678462SApril.Chin@Sun.COM#.# #.# #.#.# #.# #.# 4688462SApril.Chin@Sun.COM#.####.####.#.####.####.# 4698462SApril.Chin@Sun.COM#.......................# 4708462SApril.Chin@Sun.COM#.####.#.#######.#.####.# 4718462SApril.Chin@Sun.COM#.# #.#.# #.#.# #.# 4728462SApril.Chin@Sun.COM#.####.#.#######.#.####.# 4738462SApril.Chin@Sun.COM#......#....#....#......# 4748462SApril.Chin@Sun.COM######.####.#.####.###### 4758462SApril.Chin@Sun.COM###### # # ###### 4768462SApril.Chin@Sun.COM###### # ## ## # ###### 4778462SApril.Chin@Sun.COM###### # # # # ###### 4788462SApril.Chin@Sun.COM# # M # # 4798462SApril.Chin@Sun.COM###### # ####### # ###### 4808462SApril.Chin@Sun.COM###### # # ###### 4818462SApril.Chin@Sun.COM###### # ####### # ###### 4828462SApril.Chin@Sun.COM###### # # # # ###### 4838462SApril.Chin@Sun.COM######.#.#######.#.###### 4848462SApril.Chin@Sun.COM#...........#...........# 4858462SApril.Chin@Sun.COM#.###.###...#...###.###.# 4868462SApril.Chin@Sun.COM#...#...............#...# 4878462SApril.Chin@Sun.COM###.#....#######....#.### 4888462SApril.Chin@Sun.COM# #.#..#.# #.#..#.# # 4898462SApril.Chin@Sun.COM###....#.#######.#....### 4908462SApril.Chin@Sun.COM#......#....#....#......# 4918462SApril.Chin@Sun.COM#.#########.#.#########.# 4928462SApril.Chin@Sun.COM#.......................# 4938462SApril.Chin@Sun.COM######################### 4948462SApril.Chin@Sun.COMENDOFLEVEL 4958462SApril.Chin@Sun.COM return 0 4968462SApril.Chin@Sun.COM} 4978462SApril.Chin@Sun.COM 4988462SApril.Chin@Sun.COMfunction levelmap_classic2 4998462SApril.Chin@Sun.COM{ 5008462SApril.Chin@Sun.COMcat <<ENDOFLEVEL 5018462SApril.Chin@Sun.COM####################### 5028462SApril.Chin@Sun.COM#.P...#.........#.....# 5038462SApril.Chin@Sun.COM#.###.#.#######.#.###.# 5048462SApril.Chin@Sun.COM#.....................# 5058462SApril.Chin@Sun.COM###.#.####.#.####.#.### 5068462SApril.Chin@Sun.COM###.#......#......#.### 5078462SApril.Chin@Sun.COM###.###.#######.###.### 5088462SApril.Chin@Sun.COM###.................### 5098462SApril.Chin@Sun.COM###.###.### ###.###.### 5108462SApril.Chin@Sun.COM###.#...#M #...#.### 5118462SApril.Chin@Sun.COM###.#.#.#######.#.#.### 5128462SApril.Chin@Sun.COM#.....#.........#.....# 5138462SApril.Chin@Sun.COM###.#####..#..#####.### 5148462SApril.Chin@Sun.COM###........#........### 5158462SApril.Chin@Sun.COM###.###.#######.###.### 5168462SApril.Chin@Sun.COM#.....................# 5178462SApril.Chin@Sun.COM#.###.####.#.####.###.# 5188462SApril.Chin@Sun.COM#.###.#....#....#.###.# 5198462SApril.Chin@Sun.COM#.###.#.#######.#.###.# 5208462SApril.Chin@Sun.COM#.....................# 5218462SApril.Chin@Sun.COM####################### 5228462SApril.Chin@Sun.COMENDOFLEVEL 5238462SApril.Chin@Sun.COM return 0 5248462SApril.Chin@Sun.COM} 5258462SApril.Chin@Sun.COM 5268462SApril.Chin@Sun.COMfunction levelmap_easy 5278462SApril.Chin@Sun.COM{ 5288462SApril.Chin@Sun.COMcat <<ENDOFLEVEL 5298462SApril.Chin@Sun.COM################## 5308462SApril.Chin@Sun.COM# .............. # 5318462SApril.Chin@Sun.COM# . ###### # 5328462SApril.Chin@Sun.COM# . # M # # 5338462SApril.Chin@Sun.COM# . # # # 5348462SApril.Chin@Sun.COM# . ### ## # 5358462SApril.Chin@Sun.COM# . # # 5368462SApril.Chin@Sun.COM# . ### # 5378462SApril.Chin@Sun.COM# . # 5388462SApril.Chin@Sun.COM# .......... # 5398462SApril.Chin@Sun.COM# .......... P # 5408462SApril.Chin@Sun.COM################## 5418462SApril.Chin@Sun.COMENDOFLEVEL 5428462SApril.Chin@Sun.COM return 0 5438462SApril.Chin@Sun.COM} 5448462SApril.Chin@Sun.COM 5458462SApril.Chin@Sun.COMfunction levelmap_sunsolaristext 5468462SApril.Chin@Sun.COM{ 5478462SApril.Chin@Sun.COMcat <<ENDOFLEVEL 5488462SApril.Chin@Sun.COM################################################ 5498462SApril.Chin@Sun.COM# .#### . # #....# # 5508462SApril.Chin@Sun.COM# # # # #....# # 5518462SApril.Chin@Sun.COM# #### # # #.#..# M # 5528462SApril.Chin@Sun.COM# # # # #..#.# # 5538462SApril.Chin@Sun.COM# # # # # #...## # 5548462SApril.Chin@Sun.COM# #### #### #....# # 5558462SApril.Chin@Sun.COM# # 5568462SApril.Chin@Sun.COM# #### #### # ## ##### # #### # 5578462SApril.Chin@Sun.COM# # #. .# # # # #....# # # # 5588462SApril.Chin@Sun.COM# #### # # # # P # #....# # #### # 5598462SApril.Chin@Sun.COM# # # ### #.#### #.### # # # 5608462SApril.Chin@Sun.COM# # .# #. .. # # #...# # # # # 5618462SApril.Chin@Sun.COM# #### #### ###### . # ....# # ####. # 5628462SApril.Chin@Sun.COM################################################ 5638462SApril.Chin@Sun.COMENDOFLEVEL 5648462SApril.Chin@Sun.COM return 0 5658462SApril.Chin@Sun.COM} 5668462SApril.Chin@Sun.COM 5678462SApril.Chin@Sun.COMfunction read_levelmap 5688462SApril.Chin@Sun.COM{ 5698462SApril.Chin@Sun.COM typeset map="$( $1 )" 5708462SApril.Chin@Sun.COM 5718462SApril.Chin@Sun.COM integer y=0 5728462SApril.Chin@Sun.COM integer x=0 5738462SApril.Chin@Sun.COM integer maxx=0 5748462SApril.Chin@Sun.COM integer numdots=0 5758462SApril.Chin@Sun.COM typeset line 5768462SApril.Chin@Sun.COM typeset c 5778462SApril.Chin@Sun.COM 5788462SApril.Chin@Sun.COM while read -r line ; do 5798462SApril.Chin@Sun.COM for (( x=0 ; x < ${#line} ; x++ )) ; do 5808462SApril.Chin@Sun.COM c="${line:x:1}" 5818462SApril.Chin@Sun.COM 5828462SApril.Chin@Sun.COM case $c in 5838462SApril.Chin@Sun.COM ".") numdots+=1 ;; 5848462SApril.Chin@Sun.COM "M") 5858462SApril.Chin@Sun.COM # log start position of monsters 5868462SApril.Chin@Sun.COM levelmap["monsterstartpos_x"]="$x" 5878462SApril.Chin@Sun.COM levelmap["monsterstartpos_y"]="$y" 5888462SApril.Chin@Sun.COM c=" " 5898462SApril.Chin@Sun.COM ;; 5908462SApril.Chin@Sun.COM "P") 5918462SApril.Chin@Sun.COM # log start position of player 5928462SApril.Chin@Sun.COM levelmap["playerstartpos_x"]="$x" 5938462SApril.Chin@Sun.COM levelmap["playerstartpos_y"]="$y" 5948462SApril.Chin@Sun.COM c=" " 5958462SApril.Chin@Sun.COM ;; 5968462SApril.Chin@Sun.COM esac 5978462SApril.Chin@Sun.COM 5988462SApril.Chin@Sun.COM levelmap["${x}_${y}"]="$c" 5998462SApril.Chin@Sun.COM done 6008462SApril.Chin@Sun.COM (( maxx=x , y++ )) 6018462SApril.Chin@Sun.COM done <<<"${map}" 6028462SApril.Chin@Sun.COM 6038462SApril.Chin@Sun.COM levelmap["max_x"]=${maxx} 6048462SApril.Chin@Sun.COM levelmap["max_y"]=${y} 6058462SApril.Chin@Sun.COM levelmap["numdots"]=${numdots} 6068462SApril.Chin@Sun.COM 6078462SApril.Chin@Sun.COM # consistency checks 6088462SApril.Chin@Sun.COM if [[ "${levelmap["monsterstartpos_x"]}" == "" ]] ; then 6098462SApril.Chin@Sun.COM fatal_error "read_levelmap: monsterstartpos_x is empty." 6108462SApril.Chin@Sun.COM fi 6118462SApril.Chin@Sun.COM if [[ "${levelmap["playerstartpos_x"]}" == "" ]] ; then 6128462SApril.Chin@Sun.COM fatal_error "read_levelmap: playerstartpos_x is empty." 6138462SApril.Chin@Sun.COM fi 6148462SApril.Chin@Sun.COM 6158462SApril.Chin@Sun.COM return 0 6168462SApril.Chin@Sun.COM} 6178462SApril.Chin@Sun.COM 6188462SApril.Chin@Sun.COMfunction player.set 6198462SApril.Chin@Sun.COM{ 6208462SApril.Chin@Sun.COM case "${.sh.subscript}" in 6218462SApril.Chin@Sun.COM pos_y) 6228462SApril.Chin@Sun.COM if [[ "${levelmap["${player["pos_x"]}_${.sh.value}"]}" == "#" ]] ; then 6238462SApril.Chin@Sun.COM .sh.value=${player["pos_y"]} 6248462SApril.Chin@Sun.COM beep 6258462SApril.Chin@Sun.COM fi 6268462SApril.Chin@Sun.COM ;; 6278462SApril.Chin@Sun.COM 6288462SApril.Chin@Sun.COM pos_x) 6298462SApril.Chin@Sun.COM if [[ "${levelmap["${.sh.value}_${player["pos_y"]}"]}" == "#" ]] ; then 6308462SApril.Chin@Sun.COM .sh.value=${player["pos_x"]} 6318462SApril.Chin@Sun.COM beep 6328462SApril.Chin@Sun.COM fi 6338462SApril.Chin@Sun.COM ;; 6348462SApril.Chin@Sun.COM esac 6358462SApril.Chin@Sun.COM return 0 6368462SApril.Chin@Sun.COM} 6378462SApril.Chin@Sun.COM 6388462SApril.Chin@Sun.COMfunction monster.set 6398462SApril.Chin@Sun.COM{ 6408462SApril.Chin@Sun.COM case "${.sh.subscript}" in 6418462SApril.Chin@Sun.COM *_pos_y) 6428462SApril.Chin@Sun.COM if [[ "${levelmap["${monster[${currmonster}_"pos_x"]}_${.sh.value}"]}" == "#" ]] ; then 6438462SApril.Chin@Sun.COM .sh.value=${monster[${currmonster}_"pos_y"]} 6448462SApril.Chin@Sun.COM # turn homing off when the monster hit a wall 6458462SApril.Chin@Sun.COM monster[${currmonster}_"homing"]=0 6468462SApril.Chin@Sun.COM fi 6478462SApril.Chin@Sun.COM ;; 6488462SApril.Chin@Sun.COM 6498462SApril.Chin@Sun.COM *_pos_x) 6508462SApril.Chin@Sun.COM if [[ "${levelmap["${.sh.value}_${monster[${currmonster}_"pos_y"]}"]}" == "#" ]] ; then 6518462SApril.Chin@Sun.COM .sh.value=${monster[${currmonster}_"pos_x"]} 6528462SApril.Chin@Sun.COM # turn homing off when the monster hit a wall 6538462SApril.Chin@Sun.COM monster[${currmonster}_"homing"]=0 6548462SApril.Chin@Sun.COM fi 6558462SApril.Chin@Sun.COM ;; 6568462SApril.Chin@Sun.COM esac 6578462SApril.Chin@Sun.COM return 0 6588462SApril.Chin@Sun.COM} 6598462SApril.Chin@Sun.COM 6608462SApril.Chin@Sun.COMfunction render_game 6618462SApril.Chin@Sun.COM{ 6628462SApril.Chin@Sun.COM # render_buffer is some kind of "background buffer" to "double buffer" 6638462SApril.Chin@Sun.COM # all output and combine it in one write to reduce flickering in the 6648462SApril.Chin@Sun.COM # terminal 6658462SApril.Chin@Sun.COM typeset render_buffer="$( 6668462SApril.Chin@Sun.COM integer screen_y_offset=1 6678462SApril.Chin@Sun.COM integer start_y_pos=0 6688462SApril.Chin@Sun.COM integer render_num_lines=${levelmap["max_y"]} 6698462SApril.Chin@Sun.COM 6708462SApril.Chin@Sun.COM if (( (termsize.lines-3) < levelmap["max_y"] )) ; then 6718462SApril.Chin@Sun.COM (( start_y_pos=player["pos_y"] / 2)) 6728462SApril.Chin@Sun.COM (( render_num_lines=termsize.lines-5)) 6738462SApril.Chin@Sun.COM fi 6748462SApril.Chin@Sun.COM 6758462SApril.Chin@Sun.COM #print -n -- "${vtcode["clear"]}" 6768462SApril.Chin@Sun.COM print_setcursorpos 0 0 6778462SApril.Chin@Sun.COM 6788462SApril.Chin@Sun.COM # print score (note the " " around "%d" are neccesary to clean up cruft 6798462SApril.Chin@Sun.COM # when we overwrite the level 6808462SApril.Chin@Sun.COM printf "SCORE: %05d DOTS: %.3d LIVES: %2.d " "${player["score"]}" "${levelmap["numdots"]}" "${player["lives"]}" 6818462SApril.Chin@Sun.COM print_levelmap ${screen_y_offset} ${start_y_pos} ${render_num_lines} 6828462SApril.Chin@Sun.COM 6838462SApril.Chin@Sun.COM # render player 6848462SApril.Chin@Sun.COM print_setcursorpos ${player["pos_x"]} $((player["pos_y"]+screen_y_offset-start_y_pos)) 6858462SApril.Chin@Sun.COM print -n "@" 6868462SApril.Chin@Sun.COM 6878462SApril.Chin@Sun.COM # render monsters 6888462SApril.Chin@Sun.COM for currmonster in ${monsterlist} ; do 6898462SApril.Chin@Sun.COM (( m_pos_x=monster[${currmonster}_"pos_x"] )) 6908462SApril.Chin@Sun.COM (( m_pos_y=monster[${currmonster}_"pos_y"]+screen_y_offset-start_y_pos )) 6918462SApril.Chin@Sun.COM 6928462SApril.Chin@Sun.COM if (( m_pos_y >= screen_y_offset && m_pos_y < render_num_lines )) ; then 6938462SApril.Chin@Sun.COM print_setcursorpos ${m_pos_x} ${m_pos_y} 6948462SApril.Chin@Sun.COM print -n "x" 6958462SApril.Chin@Sun.COM fi 6968462SApril.Chin@Sun.COM done 6978462SApril.Chin@Sun.COM 6988462SApril.Chin@Sun.COM # status block 6998462SApril.Chin@Sun.COM print_setcursorpos 0 $((render_num_lines+screen_y_offset)) 7008462SApril.Chin@Sun.COM emptyline=" " 7018462SApril.Chin@Sun.COM print -n " >> ${player["message"]} <<${emptyline:0:${#emptyline}-${#player["message"]}}" 7028462SApril.Chin@Sun.COM )" 7038462SApril.Chin@Sun.COM print -r -- "${render_buffer}${end_of_frame}" 7048462SApril.Chin@Sun.COM# print "renderbuffersize=$(print "${render_buffer}" | wc -c) ${end_of_frame}" 7058462SApril.Chin@Sun.COM return 0 7068462SApril.Chin@Sun.COM} 7078462SApril.Chin@Sun.COM 7088462SApril.Chin@Sun.COMfunction main_loop 7098462SApril.Chin@Sun.COM{ 7108462SApril.Chin@Sun.COM float sleep_per_cycle=0.2 7118462SApril.Chin@Sun.COM float seconds_before_read 7128462SApril.Chin@Sun.COM integer num_cycles=0 7138462SApril.Chin@Sun.COM float rs 7148462SApril.Chin@Sun.COM 7158462SApril.Chin@Sun.COM print -n -- "${vtcode["clear"]}" 7168462SApril.Chin@Sun.COM 7178462SApril.Chin@Sun.COM read_levelmap "$1" 7188462SApril.Chin@Sun.COM 7198462SApril.Chin@Sun.COM # player init 7208462SApril.Chin@Sun.COM player["pos_x"]=${levelmap["playerstartpos_x"]} 7218462SApril.Chin@Sun.COM player["pos_y"]=${levelmap["playerstartpos_y"]} 7228462SApril.Chin@Sun.COM player["score"]=0 # player score 7238462SApril.Chin@Sun.COM player["lives"]=5 # number of lives 7248462SApril.Chin@Sun.COM player["invulnerable"]=10 # cycles how long the player remains invulnerable 7258462SApril.Chin@Sun.COM player["message"]="Go..." 7268462SApril.Chin@Sun.COM 7278462SApril.Chin@Sun.COM monsterlist="maw claw jitterbug tentacle grendel" 7288462SApril.Chin@Sun.COM 7298462SApril.Chin@Sun.COM for currmonster in ${monsterlist} ; do 7308462SApril.Chin@Sun.COM monster[${currmonster}_"pos_x"]=${levelmap["monsterstartpos_x"]} 7318462SApril.Chin@Sun.COM monster[${currmonster}_"pos_y"]=${levelmap["monsterstartpos_y"]} 7328462SApril.Chin@Sun.COM monster[${currmonster}_"xstep"]=0 7338462SApril.Chin@Sun.COM monster[${currmonster}_"ystep"]=0 7348462SApril.Chin@Sun.COM monster[${currmonster}_"homing"]=0 7358462SApril.Chin@Sun.COM done 7368462SApril.Chin@Sun.COM 7378462SApril.Chin@Sun.COM # main game cycle loop 7388462SApril.Chin@Sun.COM while true ; do 7398462SApril.Chin@Sun.COM num_cycles+=1 7408462SApril.Chin@Sun.COM seconds_before_read=${SECONDS} 7418462SApril.Chin@Sun.COM c="" ; read -r -t ${sleep_per_cycle} -n 1 c 7428462SApril.Chin@Sun.COM 7438462SApril.Chin@Sun.COM if [[ "$c" != "" ]] ; then 7448462SApril.Chin@Sun.COM # special case handling for cursor keys which are usually composed 7458462SApril.Chin@Sun.COM # of three characters (e.g. "<ESC>[D"). If only <ESC> is hit we 7468462SApril.Chin@Sun.COM # quicky exit 7478462SApril.Chin@Sun.COM if [[ "$c" == $'\E' ]] ; then 7488462SApril.Chin@Sun.COM read -r -t 0.1 -n 1 c 7498462SApril.Chin@Sun.COM if [[ "$c" != "[" ]] ; then 7508462SApril.Chin@Sun.COM return 0 7518462SApril.Chin@Sun.COM fi 7528462SApril.Chin@Sun.COM 7538462SApril.Chin@Sun.COM # we assume the user is using the cursor keys, this |read| 7548462SApril.Chin@Sun.COM # should fetch the 3rd byte of the three-character sequence 7558462SApril.Chin@Sun.COM # for the cursor keys 7568462SApril.Chin@Sun.COM read -r -t 0.1 -n 1 c 7578462SApril.Chin@Sun.COM fi 7588462SApril.Chin@Sun.COM 7598462SApril.Chin@Sun.COM # if the user hit a key the "read" above was interrupted 7608462SApril.Chin@Sun.COM # and didn't wait exactly |sleep_per_cycle| seconds. 7618462SApril.Chin@Sun.COM # We wait here some moments (|rs|="remaining seconds") to 7628462SApril.Chin@Sun.COM # avoid that the game gets "faster" when more user input 7638462SApril.Chin@Sun.COM # is given. 7648462SApril.Chin@Sun.COM (( rs=sleep_per_cycle-(SECONDS-seconds_before_read) )) 7658462SApril.Chin@Sun.COM (( rs > 0.001 )) && sleep ${rs} 7668462SApril.Chin@Sun.COM 7678462SApril.Chin@Sun.COM player["message"]="" 7688462SApril.Chin@Sun.COM 7698462SApril.Chin@Sun.COM case "$c" in 7708462SApril.Chin@Sun.COM j|D|4) (( player["pos_x"]-=1 )) ;; 7718462SApril.Chin@Sun.COM k|C|6) (( player["pos_x"]+=1 )) ;; 7728462SApril.Chin@Sun.COM i|A|8) (( player["pos_y"]-=1 )) ;; 7738462SApril.Chin@Sun.COM m|B|2) (( player["pos_y"]+=1 )) ;; 7748462SApril.Chin@Sun.COM 7758462SApril.Chin@Sun.COM q) return 0 ;; 7768462SApril.Chin@Sun.COM esac 7778462SApril.Chin@Sun.COM 7788462SApril.Chin@Sun.COM if [[ "${levelmap["${player["pos_x"]}_${player["pos_y"]}"]}" == "." ]] ; then 7798462SApril.Chin@Sun.COM levelmap["${player["pos_x"]}_${player["pos_y"]}"]=" " 7808462SApril.Chin@Sun.COM (( levelmap["numdots"]-=1 )) 7818462SApril.Chin@Sun.COM 7828462SApril.Chin@Sun.COM (( player["score"]+=10 )) 7838462SApril.Chin@Sun.COM player["message"]='GNAW!!' 7848462SApril.Chin@Sun.COM 7858462SApril.Chin@Sun.COM if (( levelmap["numdots"] <= 0 )) ; then 7868462SApril.Chin@Sun.COM level_completed 7878462SApril.Chin@Sun.COM return 0 7888462SApril.Chin@Sun.COM fi 7898462SApril.Chin@Sun.COM fi 7908462SApril.Chin@Sun.COM fi 7918462SApril.Chin@Sun.COM 7928462SApril.Chin@Sun.COM # generic player status change 7938462SApril.Chin@Sun.COM if (( player["invulnerable"] > 0 )) ; then 7948462SApril.Chin@Sun.COM (( player["invulnerable"]-=1 )) 7958462SApril.Chin@Sun.COM fi 7968462SApril.Chin@Sun.COM if (( player["lives"] <= 0 )) ; then 7978462SApril.Chin@Sun.COM game_over 7988462SApril.Chin@Sun.COM return 0 7998462SApril.Chin@Sun.COM fi 8008462SApril.Chin@Sun.COM 8018462SApril.Chin@Sun.COM # move monsters 8028462SApril.Chin@Sun.COM for currmonster in ${monsterlist} ; do 8038462SApril.Chin@Sun.COM # make monster as half as slow then the others when it is following the user 8048462SApril.Chin@Sun.COM if (( monster[${currmonster}_"homing"] > 0 )) ; then 8058462SApril.Chin@Sun.COM (( (num_cycles%2) > 0 )) && continue 8068462SApril.Chin@Sun.COM fi 8078462SApril.Chin@Sun.COM 8088462SApril.Chin@Sun.COM if [[ ${monster[${currmonster}_"pos_x"]} == ${player["pos_x"]} ]] ; then 8098462SApril.Chin@Sun.COM if (( (monster[${currmonster}_"pos_y"]-player["pos_y"]) > 0 )) ; then 8108462SApril.Chin@Sun.COM (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=-1 )) 8118462SApril.Chin@Sun.COM else 8128462SApril.Chin@Sun.COM (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+1 )) 8138462SApril.Chin@Sun.COM fi 8148462SApril.Chin@Sun.COM monster[${currmonster}_"homing"]=1 8158462SApril.Chin@Sun.COM if (( player["invulnerable"] <= 0 )) ; then 8168462SApril.Chin@Sun.COM player["message"]="Attention: ${currmonster} is chasing you" 8178462SApril.Chin@Sun.COM fi 8188462SApril.Chin@Sun.COM elif (( monster[${currmonster}_"pos_y"] == player["pos_y"] )) ; then 8198462SApril.Chin@Sun.COM if (( (monster[${currmonster}_"pos_x"]-player["pos_x"]) > 0 )) ; then 8208462SApril.Chin@Sun.COM (( monster[${currmonster}_"xstep"]=-1 , monster[${currmonster}_"ystep"]=-0 )) 8218462SApril.Chin@Sun.COM else 8228462SApril.Chin@Sun.COM (( monster[${currmonster}_"xstep"]=+1 , monster[${currmonster}_"ystep"]=+0 )) 8238462SApril.Chin@Sun.COM fi 8248462SApril.Chin@Sun.COM monster[${currmonster}_"homing"]=1 8258462SApril.Chin@Sun.COM if (( player["invulnerable"] <= 0 )) ; then 8268462SApril.Chin@Sun.COM player["message"]="Attention: ${currmonster} is chasing you" 8278462SApril.Chin@Sun.COM fi 8288462SApril.Chin@Sun.COM else 8298462SApril.Chin@Sun.COM if (( monster[${currmonster}_"homing"] == 0 )) ; then 8308462SApril.Chin@Sun.COM case $((SECONDS % 6 + RANDOM % 4)) in 8318462SApril.Chin@Sun.COM 0) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+0 )) ;; 8328462SApril.Chin@Sun.COM 2) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+1 )) ;; 8338462SApril.Chin@Sun.COM 3) (( monster[${currmonster}_"xstep"]=+1 , monster[${currmonster}_"ystep"]=+0 )) ;; 8348462SApril.Chin@Sun.COM 5) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=-1 )) ;; 8358462SApril.Chin@Sun.COM 6) (( monster[${currmonster}_"xstep"]=-1 , monster[${currmonster}_"ystep"]=+0 )) ;; 8368462SApril.Chin@Sun.COM esac 8378462SApril.Chin@Sun.COM fi 8388462SApril.Chin@Sun.COM fi 8398462SApril.Chin@Sun.COM 8408462SApril.Chin@Sun.COM (( monster[${currmonster}_"pos_x"]=monster[${currmonster}_"pos_x"]+monster[${currmonster}_"xstep"] )) 8418462SApril.Chin@Sun.COM (( monster[${currmonster}_"pos_y"]=monster[${currmonster}_"pos_y"]+monster[${currmonster}_"ystep"] )) 8428462SApril.Chin@Sun.COM 8438462SApril.Chin@Sun.COM # check if a monster hit the player 8448462SApril.Chin@Sun.COM if (( player["invulnerable"] <= 0 )) ; then 8458462SApril.Chin@Sun.COM if (( monster[${currmonster}_"pos_x"] == player["pos_x"] && \ 8468462SApril.Chin@Sun.COM monster[${currmonster}_"pos_y"] == player["pos_y"] )) ; then 8478462SApril.Chin@Sun.COM # if player was hit by a monster take one life and 8488462SApril.Chin@Sun.COM # make him invulnerable for 10 cycles to avoid that 8498462SApril.Chin@Sun.COM # the next cycle steals more lives 8508462SApril.Chin@Sun.COM player["message"]="Ouuuchhhh" 8518462SApril.Chin@Sun.COM player["invulnerable"]=10 8528462SApril.Chin@Sun.COM (( player["lives"]-=1 )) 8538462SApril.Chin@Sun.COM 8548462SApril.Chin@Sun.COM beep ; beep ; sleep 0.2 ; beep ; beep 8558462SApril.Chin@Sun.COM fi 8568462SApril.Chin@Sun.COM fi 8578462SApril.Chin@Sun.COM done 8588462SApril.Chin@Sun.COM 8598462SApril.Chin@Sun.COM render_game 8608462SApril.Chin@Sun.COM done 8618462SApril.Chin@Sun.COM return 0 8628462SApril.Chin@Sun.COM} 8638462SApril.Chin@Sun.COM 8648462SApril.Chin@Sun.COMfunction map_filter 8658462SApril.Chin@Sun.COM{ 8668462SApril.Chin@Sun.COM typeset ch_player ch_monster ch_wall var 8678462SApril.Chin@Sun.COM 8688462SApril.Chin@Sun.COM if (( $1 == 1 )) ; then 8698462SApril.Chin@Sun.COM ch_player="${vtcode["fg_yellow"]}" 8708462SApril.Chin@Sun.COM ch_monster="${vtcode["fg_red"]}" 8718462SApril.Chin@Sun.COM ch_wall="${vtcode["fg_blue"]}" 8728462SApril.Chin@Sun.COM else 8738462SApril.Chin@Sun.COM ch_player="" 8748462SApril.Chin@Sun.COM ch_monster="" 8758462SApril.Chin@Sun.COM ch_wall="" 8768462SApril.Chin@Sun.COM fi 8778462SApril.Chin@Sun.COM 8788462SApril.Chin@Sun.COM if (( $2 == 1 )) ; then 8798462SApril.Chin@Sun.COM # unicode map 8808462SApril.Chin@Sun.COM ch_player+="$(printf '\u[24d2]')" 8818462SApril.Chin@Sun.COM ch_monster+="$(printf '\u[2605]')" 8828462SApril.Chin@Sun.COM ch_wall+="$(printf '\u[25a6]')" 8838462SApril.Chin@Sun.COM else 8848462SApril.Chin@Sun.COM # ascii map 8858462SApril.Chin@Sun.COM ch_player+="@" 8868462SApril.Chin@Sun.COM ch_monster+="x" 8878462SApril.Chin@Sun.COM ch_wall+="#" 8888462SApril.Chin@Sun.COM fi 8898462SApril.Chin@Sun.COM 8908462SApril.Chin@Sun.COM # note that this filter currently defeats the "double-buffering" 8918462SApril.Chin@Sun.COM while IFS='' read -r -d "${end_of_frame}" var ; do 8928462SApril.Chin@Sun.COM var="${var// /${vtcode["fg_grey"]} }" 8938462SApril.Chin@Sun.COM var="${var//\./${vtcode["fg_lightred"]}.}" 8948462SApril.Chin@Sun.COM var="${var//@/${ch_player}}" 8958462SApril.Chin@Sun.COM var="${var//x/${ch_monster}}" 8968462SApril.Chin@Sun.COM var="${var//#/${ch_wall}}" 8978462SApril.Chin@Sun.COM 8988462SApril.Chin@Sun.COM print -r -- "${var}" 8998462SApril.Chin@Sun.COM done 9008462SApril.Chin@Sun.COM return 0 9018462SApril.Chin@Sun.COM} 9028462SApril.Chin@Sun.COM 9038462SApril.Chin@Sun.COMfunction exit_trap 9048462SApril.Chin@Sun.COM{ 9058462SApril.Chin@Sun.COM # restore stty settings 9068462SApril.Chin@Sun.COM stty ${saved_stty} 9078462SApril.Chin@Sun.COM 9088462SApril.Chin@Sun.COM print "bye." 9098462SApril.Chin@Sun.COM return 0 9108462SApril.Chin@Sun.COM} 9118462SApril.Chin@Sun.COM 9128462SApril.Chin@Sun.COMfunction usage 9138462SApril.Chin@Sun.COM{ 9148462SApril.Chin@Sun.COM OPTIND=0 9158462SApril.Chin@Sun.COM getopts -a "${progname}" "${gnaw_usage}" OPT '-?' 9168462SApril.Chin@Sun.COM exit 2 9178462SApril.Chin@Sun.COM} 9188462SApril.Chin@Sun.COM 9198462SApril.Chin@Sun.COM# program start 9208462SApril.Chin@Sun.COM# make sure we use the ksh93 "cat" builtin which supports the "-u" option 9218462SApril.Chin@Sun.COMbuiltin basename 9228462SApril.Chin@Sun.COMbuiltin cat 9238462SApril.Chin@Sun.COMbuiltin wc 9248462SApril.Chin@Sun.COM 9258462SApril.Chin@Sun.COMtypeset progname="${ basename "${0}" ; }" 9268462SApril.Chin@Sun.COM 9278462SApril.Chin@Sun.COM# terminal size rect 92810898Sroland.mainz@nrubsig.orgcompound termsize=( 9298462SApril.Chin@Sun.COM integer columns=-1 9308462SApril.Chin@Sun.COM integer lines=-1 9318462SApril.Chin@Sun.COM) 9328462SApril.Chin@Sun.COM 9338462SApril.Chin@Sun.COM# global variables 9348462SApril.Chin@Sun.COMtypeset quiet=false 9358462SApril.Chin@Sun.COM 9368462SApril.Chin@Sun.COMtypeset -A levelmap 9378462SApril.Chin@Sun.COMtypeset -A player 9388462SApril.Chin@Sun.COMtypeset -A monster 9398462SApril.Chin@Sun.COM# global rendering options 9408462SApril.Chin@Sun.COMinteger game_use_colors=0 9418462SApril.Chin@Sun.COMinteger game_use_unicode=0 9428462SApril.Chin@Sun.COM 9438462SApril.Chin@Sun.COMtypeset -r gnaw_usage=$'+ 94410898Sroland.mainz@nrubsig.org[-?\n@(#)\$Id: gnaw (Roland Mainz) 2009-05-09 \$\n] 9458462SApril.Chin@Sun.COM[-author?Roland Mainz <roland.mainz@nrubsig.org>] 9468462SApril.Chin@Sun.COM[+NAME?gnaw - maze game written in ksh93] 9478462SApril.Chin@Sun.COM[+DESCRIPTION?\bgnaw\b is a maze game. 9488462SApril.Chin@Sun.COM The player maneuvers a yellow "@" sign to navigate a maze while eating 9498462SApril.Chin@Sun.COM small dots. A level is finished when all the dots are eaten. Five monsters 9508462SApril.Chin@Sun.COM (maw, claw, jitterbug, tentacle and grendel) also wander the maze in an attempt 9518462SApril.Chin@Sun.COM to catch the "@". Each level begins with all ghosts in their home, and "@" near 9528462SApril.Chin@Sun.COM the bottom of the maze. The monsters are released from the home one by one at the 9538462SApril.Chin@Sun.COM start of each level and start their rentless hunt after the player.] 9548462SApril.Chin@Sun.COM[q:quiet?Disable use of terminal bell.] 9558462SApril.Chin@Sun.COM[+SEE ALSO?\bksh93\b(1)] 9568462SApril.Chin@Sun.COM' 9578462SApril.Chin@Sun.COM 9588462SApril.Chin@Sun.COMwhile getopts -a "${progname}" "${gnaw_usage}" OPT ; do 9598462SApril.Chin@Sun.COM# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" 9608462SApril.Chin@Sun.COM case ${OPT} in 9618462SApril.Chin@Sun.COM q) quiet=true ;; 9628462SApril.Chin@Sun.COM +q) quiet=false ;; 9638462SApril.Chin@Sun.COM *) usage ;; 9648462SApril.Chin@Sun.COM esac 9658462SApril.Chin@Sun.COMdone 9668462SApril.Chin@Sun.COMshift $((OPTIND-1)) 9678462SApril.Chin@Sun.COM 9688462SApril.Chin@Sun.COM# save stty values and register the exit trap which restores these values on exit 9698462SApril.Chin@Sun.COMsaved_stty="$(stty -g)" 9708462SApril.Chin@Sun.COMtrap exit_trap EXIT 9718462SApril.Chin@Sun.COM 9728462SApril.Chin@Sun.COMprint "Loading..." 9738462SApril.Chin@Sun.COM 9748462SApril.Chin@Sun.COM# set stty values, "-icanon min 1 time 0 -inpck" should improve input latency, 9758462SApril.Chin@Sun.COM# "-echo" turns the terminal echo off 9768462SApril.Chin@Sun.COMstty -icanon min 1 time 0 -inpck -echo 9778462SApril.Chin@Sun.COM 9788462SApril.Chin@Sun.COMget_term_size termsize || fatal_error "Could not get terminal size." 9798462SApril.Chin@Sun.COM 9808462SApril.Chin@Sun.COM# prechecks 9818462SApril.Chin@Sun.COM(( termsize.columns < 60 )) && fatal_error "Terminal width must be larger than 60 columns (currently ${termsize.columns})." 9828462SApril.Chin@Sun.COM 9838462SApril.Chin@Sun.COMtypeset -A vtcode 9848462SApril.Chin@Sun.COM# color values taken from http://frexx.de/xterm-256-notes/, other 9858462SApril.Chin@Sun.COM# codes from http://vt100.net/docs/vt100-tm/ 9868462SApril.Chin@Sun.COMvtcode=( 9878462SApril.Chin@Sun.COM ["bg_black"]="$(print -n "\E[40m")" 9888462SApril.Chin@Sun.COM ["fg_black"]="$(print -n "\E[30m")" 9898462SApril.Chin@Sun.COM ["fg_red"]="$(print -n "\E[31m")" 9908462SApril.Chin@Sun.COM ["fg_lightred"]="$(print -n "\E[1;31m")" 9918462SApril.Chin@Sun.COM ["fg_green"]="$(print -n "\E[32m")" 9928462SApril.Chin@Sun.COM ["fg_lightgreen"]="$(print -n "\E[1;32m")" 9938462SApril.Chin@Sun.COM ["fg_yellow"]="$(print -n "\E[33m")" 9948462SApril.Chin@Sun.COM ["fg_lightyellow"]="$(print -n "\E[1;33m")" 9958462SApril.Chin@Sun.COM ["fg_blue"]="$(print -n "\E[34m")" 9968462SApril.Chin@Sun.COM ["fg_lightblue"]="$(print -n "\E[1;34m")" 9978462SApril.Chin@Sun.COM ["fg_grey"]="$(print -n "\E[1;37m")" 9988462SApril.Chin@Sun.COM ["fg_white"]="$(print -n "\E[37m")" 9998462SApril.Chin@Sun.COM 10008462SApril.Chin@Sun.COM # misc other vt stuff 10018462SApril.Chin@Sun.COM ["vtreset"]="$(tput reset)" 10028462SApril.Chin@Sun.COM ["clear"]="$(tput clear)" 10038462SApril.Chin@Sun.COM ["bel"]="$(tput bel)" 10048462SApril.Chin@Sun.COM ["spaceline"]="$(for (( i=0 ; i < termsize.columns ; i++ )) ; do print -n " " ; done)" 10058462SApril.Chin@Sun.COM) 10068462SApril.Chin@Sun.COM 10078462SApril.Chin@Sun.COM# character used to as marker that a single frame ends at this point - this 10088462SApril.Chin@Sun.COM# is used by the "double buffering" code to make sure the "read" builtin 10098462SApril.Chin@Sun.COM# can read a whole "frame" instead of reading stuff line-by-line 10108462SApril.Chin@Sun.COMtypeset -r end_of_frame=$'\t' 10118462SApril.Chin@Sun.COM 10128462SApril.Chin@Sun.COM# get terminal sequence to move cursor to position x,y 10138462SApril.Chin@Sun.COM# (see http://vt100.net/docs/vt100-ug/chapter3.html#CPR) 10148462SApril.Chin@Sun.COMcase ${TERM} in 10158462SApril.Chin@Sun.COM xterm | xterm-color | vt100 | vt220 | dtterm | sun | sun-color) 10168462SApril.Chin@Sun.COM cup="$(infocmp -1 | \ 10178462SApril.Chin@Sun.COM egrep '^[[:space:]]*cup=' | \ 10188462SApril.Chin@Sun.COM sed -e 's/.*cup=//' \ 10198462SApril.Chin@Sun.COM -e 's/%[%id]*p1[%id]*/%2\\\$d/g' \ 10208462SApril.Chin@Sun.COM -e 's/%[%id]*p2[%id]*/%1\\\$d/g' \ 10218462SApril.Chin@Sun.COM -e 's/,$//')" 10228462SApril.Chin@Sun.COM for (( x=0 ; x < termsize.columns ; x++ )) ; do 10238462SApril.Chin@Sun.COM for (( y=0 ; y < termsize.lines ; y++ )) ; do 10248462SApril.Chin@Sun.COM vtcode[cup_${x}_${y}]="$(printf "${cup}" $((x + 1)) $((y + 1)) )" 10258462SApril.Chin@Sun.COM done 10268462SApril.Chin@Sun.COM done 10278462SApril.Chin@Sun.COM ;; 10288462SApril.Chin@Sun.COM *) 10298462SApril.Chin@Sun.COM printf "# Unrecognised terminal type '%s', fetching %dx%d items from terminfo database, please wait...\n" "${TERM}" "${termsize.columns}" "${termsize.lines}" 10308462SApril.Chin@Sun.COM for (( x=0 ; x < termsize.columns ; x++ )) ; do 10318462SApril.Chin@Sun.COM for (( y=0 ; y < termsize.lines ; y++ )) ; do 10328462SApril.Chin@Sun.COM vtcode[cup_${x}_${y}]="$(tput cup ${y} ${x})" 10338462SApril.Chin@Sun.COM done 10348462SApril.Chin@Sun.COM done 10358462SApril.Chin@Sun.COM ;; 10368462SApril.Chin@Sun.COMesac 10378462SApril.Chin@Sun.COM 10388462SApril.Chin@Sun.COMprint -- "${vtcode["vtreset"]}" 10398462SApril.Chin@Sun.COM 10408462SApril.Chin@Sun.COMrun_logo 10418462SApril.Chin@Sun.COMrun_menu 10428462SApril.Chin@Sun.COM 10438462SApril.Chin@Sun.COMexit 0 10448462SApril.Chin@Sun.COM# EOF. 1045