17c2fbfb3SApril Chin#!/usr/bin/ksh93 27c2fbfb3SApril Chin 37c2fbfb3SApril Chin# 47c2fbfb3SApril Chin# CDDL HEADER START 57c2fbfb3SApril Chin# 67c2fbfb3SApril Chin# The contents of this file are subject to the terms of the 77c2fbfb3SApril Chin# Common Development and Distribution License (the "License"). 87c2fbfb3SApril Chin# You may not use this file except in compliance with the License. 97c2fbfb3SApril Chin# 107c2fbfb3SApril Chin# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 117c2fbfb3SApril Chin# or http://www.opensolaris.org/os/licensing. 127c2fbfb3SApril Chin# See the License for the specific language governing permissions 137c2fbfb3SApril Chin# and limitations under the License. 147c2fbfb3SApril Chin# 157c2fbfb3SApril Chin# When distributing Covered Code, include this CDDL HEADER in each 167c2fbfb3SApril Chin# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 177c2fbfb3SApril Chin# If applicable, add the following below this CDDL HEADER, with the 187c2fbfb3SApril Chin# fields enclosed by brackets "[]" replaced with your own identifying 197c2fbfb3SApril Chin# information: Portions Copyright [yyyy] [name of copyright owner] 207c2fbfb3SApril Chin# 217c2fbfb3SApril Chin# CDDL HEADER END 227c2fbfb3SApril Chin# 237c2fbfb3SApril Chin 247c2fbfb3SApril Chin# 25*3e14f97fSRoger A. Faulkner# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 267c2fbfb3SApril Chin# 277c2fbfb3SApril Chin 287c2fbfb3SApril Chin# 297c2fbfb3SApril Chin# gnaw - a simple ksh93 technology demo 307c2fbfb3SApril Chin# 317c2fbfb3SApril Chin# Note that this script has been written with the main idea to show 327c2fbfb3SApril Chin# many of ksh93's new features (comparing to ksh88/bash) and not 337c2fbfb3SApril Chin# as an example of efficient&&clean script code (much of the code 347c2fbfb3SApril Chin# could be done more efficient using compound variables, this script 357c2fbfb3SApril Chin# focus is the usage of associative arrays). 367c2fbfb3SApril Chin# 377c2fbfb3SApril Chin 387c2fbfb3SApril Chin# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant 397c2fbfb3SApril Chinexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin 407c2fbfb3SApril Chin 417c2fbfb3SApril Chin# Make sure all math stuff runs in the "C" locale to avoid problems 427c2fbfb3SApril Chin# with alternative # radix point representations (e.g. ',' instead of 437c2fbfb3SApril Chin# '.' in de_DE.*-locales). This needs to be set _before_ any 447c2fbfb3SApril Chin# floating-point constants are defined in this script). 457c2fbfb3SApril Chinif [[ "${LC_ALL}" != "" ]] ; then 467c2fbfb3SApril Chin export \ 477c2fbfb3SApril Chin LC_MONETARY="${LC_ALL}" \ 487c2fbfb3SApril Chin LC_MESSAGES="${LC_ALL}" \ 497c2fbfb3SApril Chin LC_COLLATE="${LC_ALL}" \ 507c2fbfb3SApril Chin LC_CTYPE="${LC_ALL}" 517c2fbfb3SApril Chin unset LC_ALL 527c2fbfb3SApril Chinfi 537c2fbfb3SApril Chinexport LC_NUMERIC=C 547c2fbfb3SApril Chin 557c2fbfb3SApril Chinfunction print_setcursorpos 567c2fbfb3SApril Chin{ 577c2fbfb3SApril Chin print -n -- "${vtcode[cup_${1}_${2}]}" 587c2fbfb3SApril Chin} 597c2fbfb3SApril Chin 607c2fbfb3SApril Chinfunction beep 617c2fbfb3SApril Chin{ 627c2fbfb3SApril Chin ${quiet} || print -n -- "${vtcode["bel"]}" 637c2fbfb3SApril Chin} 647c2fbfb3SApril Chin 657c2fbfb3SApril Chinfunction fatal_error 667c2fbfb3SApril Chin{ 677c2fbfb3SApril Chin print -u2 "${progname}: $*" 687c2fbfb3SApril Chin exit 1 697c2fbfb3SApril Chin} 707c2fbfb3SApril Chin 717c2fbfb3SApril Chin# Get terminal size and put values into a compound variable with the integer 727c2fbfb3SApril Chin# members "columns" and "lines" 737c2fbfb3SApril Chinfunction get_term_size 747c2fbfb3SApril Chin{ 757c2fbfb3SApril Chin nameref rect=$1 767c2fbfb3SApril Chin 777c2fbfb3SApril Chin rect.columns=${ tput cols ; } || return 1 787c2fbfb3SApril Chin rect.lines=${ tput lines ; } || return 1 797c2fbfb3SApril Chin 807c2fbfb3SApril Chin return 0 817c2fbfb3SApril Chin} 827c2fbfb3SApril Chin 837c2fbfb3SApril Chinfunction print_levelmap 847c2fbfb3SApril Chin{ 857c2fbfb3SApril Chin integer screen_y_offset=$1 867c2fbfb3SApril Chin integer start_y_pos=$2 # start at this line in the map 877c2fbfb3SApril Chin integer max_numlines=$3 # maximum lines we're allowed to render 887c2fbfb3SApril Chin integer x 897c2fbfb3SApril Chin integer y 907c2fbfb3SApril Chin typeset line="" 917c2fbfb3SApril Chin 927c2fbfb3SApril Chin print_setcursorpos 0 ${screen_y_offset} 937c2fbfb3SApril Chin 947c2fbfb3SApril Chin for (( y=start_y_pos; (y-start_y_pos) < max_numlines && y < levelmap["max_y"] ; y++ )) ; do 957c2fbfb3SApril Chin line="" 967c2fbfb3SApril Chin for (( x=0 ; x < levelmap["max_x"] ; x++ )) ; do 977c2fbfb3SApril Chin line+="${levelmap["${x}_${y}"]}" 987c2fbfb3SApril Chin done 997c2fbfb3SApril Chin 1007c2fbfb3SApril Chin print -- "${line} " 1017c2fbfb3SApril Chin done 1027c2fbfb3SApril Chin 1037c2fbfb3SApril Chin # print lines filled with spaces for each line not filled 1047c2fbfb3SApril Chin # by the level map 1057c2fbfb3SApril Chin line="${vtcode["spaceline"]:0:${levelmap["max_x"]}}" 1067c2fbfb3SApril Chin for (( ; (y-start_y_pos) < max_numlines ; y++ )) ; do 1077c2fbfb3SApril Chin print -- "${line} " 1087c2fbfb3SApril Chin done 1097c2fbfb3SApril Chin return 0 1107c2fbfb3SApril Chin} 1117c2fbfb3SApril Chin 1127c2fbfb3SApril Chinfunction level_completed 1137c2fbfb3SApril Chin{ 1147c2fbfb3SApril Chin integer i 1157c2fbfb3SApril Chin typeset dummy 1167c2fbfb3SApril Chin typeset render_buffer="$( 1177c2fbfb3SApril Chin print -n -- "${vtcode["clear"]}" 1187c2fbfb3SApril Chin cat <<ENDOFTEXT 1197c2fbfb3SApril Chin 1207c2fbfb3SApril Chin # ###### # # ###### # 1217c2fbfb3SApril Chin # # # # # # 1227c2fbfb3SApril Chin # ##### # # ##### # 1237c2fbfb3SApril Chin # # # # # # 1247c2fbfb3SApril Chin # # # # # # 1257c2fbfb3SApril Chin ###### ###### ## ###### ###### 1267c2fbfb3SApril Chin 1277c2fbfb3SApril Chin (Good job) 1287c2fbfb3SApril Chin 1297c2fbfb3SApril Chin ##### #### # # ###### 1307c2fbfb3SApril Chin # # # # ## # # 1317c2fbfb3SApril Chin # # # # # # # ##### 1327c2fbfb3SApril Chin # # # # # # # # 1337c2fbfb3SApril Chin # # # # # ## # 1347c2fbfb3SApril Chin ##### #### # # ###### 1357c2fbfb3SApril Chin 1367c2fbfb3SApril Chin 1377c2fbfb3SApril ChinENDOFTEXT 1387c2fbfb3SApril Chin 1397c2fbfb3SApril Chin printf " SCORE: --> %s <--\n" "${player["score"]}" 1407c2fbfb3SApril Chin printf " LIVES: --> %s <--\n" "${player["lives"]}" 1417c2fbfb3SApril Chin )" 1427c2fbfb3SApril Chin print -- "${render_buffer}${end_of_frame}" 1437c2fbfb3SApril Chin 1447c2fbfb3SApril Chin # wait five seconds and swallow any user input 1457c2fbfb3SApril Chin for (( i=0 ; i < 50 ; i++ )) ; do 1467c2fbfb3SApril Chin read -r -t 0.1 -n 1 dummy 1477c2fbfb3SApril Chin done 1487c2fbfb3SApril Chin 1497c2fbfb3SApril Chin print "Press any key to continue...${end_of_frame}" 1507c2fbfb3SApril Chin # wait five secs or for a key 1517c2fbfb3SApril Chin read -r -t 5 -n 1 dummy 1527c2fbfb3SApril Chin return 0 1537c2fbfb3SApril Chin} 1547c2fbfb3SApril Chin 1557c2fbfb3SApril Chinfunction game_over 1567c2fbfb3SApril Chin{ 1577c2fbfb3SApril Chin typeset dummy 1587c2fbfb3SApril Chin typeset render_buffer="$( 1597c2fbfb3SApril Chin print -n -- "${vtcode["clear"]}" 1607c2fbfb3SApril Chin cat <<ENDOFTEXT 1617c2fbfb3SApril Chin 1627c2fbfb3SApril Chin #### ## # # ###### 1637c2fbfb3SApril Chin # # # # ## ## # 1647c2fbfb3SApril Chin # # # # ## # ##### 1657c2fbfb3SApril Chin # ### ###### # # # 1667c2fbfb3SApril Chin # # # # # # # 1677c2fbfb3SApril Chin #### # # # # ###### 1687c2fbfb3SApril Chin 1697c2fbfb3SApril Chin (LOSER!) 1707c2fbfb3SApril Chin 1717c2fbfb3SApril Chin #### # # ###### ##### 1727c2fbfb3SApril Chin # # # # # # # 1737c2fbfb3SApril Chin # # # # ##### # # 1747c2fbfb3SApril Chin # # # # # ##### 1757c2fbfb3SApril Chin # # # # # # # 1767c2fbfb3SApril Chin #### ## ###### # # 1777c2fbfb3SApril Chin 1787c2fbfb3SApril ChinENDOFTEXT 1797c2fbfb3SApril Chin 1807c2fbfb3SApril Chin printf "\n SCORE: --> %s <--\n" "${player["score"]}" 1817c2fbfb3SApril Chin )" 1827c2fbfb3SApril Chin print -r -- "${render_buffer}${end_of_frame}" 1837c2fbfb3SApril Chin 1847c2fbfb3SApril Chin # wait five seconds and swallow any user input 1857c2fbfb3SApril Chin for (( i=0 ; i < 50 ; i++ )) ; do 1867c2fbfb3SApril Chin read -r -t 0.1 -n 1 dummy 1877c2fbfb3SApril Chin done 1887c2fbfb3SApril Chin 1897c2fbfb3SApril Chin print "Press any key to continue...${end_of_frame}" 1907c2fbfb3SApril Chin # wait five secs or for a key 1917c2fbfb3SApril Chin read -r -t 5 -n 1 dummy 1927c2fbfb3SApril Chin return 0 1937c2fbfb3SApril Chin} 1947c2fbfb3SApril Chin 1957c2fbfb3SApril Chinfunction run_logo 1967c2fbfb3SApril Chin{ 1977c2fbfb3SApril Chin typeset render_buffer="$( 1987c2fbfb3SApril Chin cat <<ENDOFTEXT 1997c2fbfb3SApril Chin 2007c2fbfb3SApril Chin ##### # # # # # ### 2017c2fbfb3SApril Chin# # ## # # # # # # ### 2027c2fbfb3SApril Chin# # # # # # # # # ### 2037c2fbfb3SApril Chin# #### # # # # # # # # # 2047c2fbfb3SApril Chin# # # # # ####### # # # 2057c2fbfb3SApril Chin# # # ## # # # # # ### 2067c2fbfb3SApril Chin ##### # # # # ## ## ### 2077c2fbfb3SApril ChinENDOFTEXT 2087c2fbfb3SApril Chin )" 2097c2fbfb3SApril Chin print -- "${vtcode["clear"]}${render_buffer}" 2107c2fbfb3SApril Chin 2117c2fbfb3SApril Chin # wait two seconds and swallow any user input 2127c2fbfb3SApril Chin for (( i=0 ; i < 20 ; i++ )) ; do 2137c2fbfb3SApril Chin read -r -t 0.1 -n 1 dummy 2147c2fbfb3SApril Chin done 2157c2fbfb3SApril Chin 2167c2fbfb3SApril Chin print "\n (The KornShell 93 maze game)" 2177c2fbfb3SApril Chin 2187c2fbfb3SApril Chin attract_mode 2197c2fbfb3SApril Chin return 0 2207c2fbfb3SApril Chin} 2217c2fbfb3SApril Chin 2227c2fbfb3SApril Chinfunction attract_mode 2237c2fbfb3SApril Chin{ 2247c2fbfb3SApril Chin( 2257c2fbfb3SApril Chin # Now present some info, line-by-line in an endless loop 2267c2fbfb3SApril Chin # until the user presses a key (we turn the "magic" return 2277c2fbfb3SApril Chin # code for that) 2287c2fbfb3SApril Chin integer -r magic_return_code=69 2297c2fbfb3SApril Chin typeset line 2307c2fbfb3SApril Chin IFS='' ; # Make sure we do not swallow whitespaces 2317c2fbfb3SApril Chin 2327c2fbfb3SApril Chin while true ; do 2337c2fbfb3SApril Chin ( 2347c2fbfb3SApril Chin redirect 5<&0 2357c2fbfb3SApril Chin 2367c2fbfb3SApril Chin (cat <<ENDOFTEXT 2377c2fbfb3SApril Chin 2387c2fbfb3SApril Chin 2397c2fbfb3SApril Chin 2407c2fbfb3SApril Chin 2417c2fbfb3SApril Chin 2427c2fbfb3SApril Chin ################ 2437c2fbfb3SApril Chin ######################## 2447c2fbfb3SApril Chin ############################ 2457c2fbfb3SApril Chin ####### ###### ####### 2467c2fbfb3SApril Chin ###### ###### ######## 2477c2fbfb3SApril Chin ####### ###### ####### 2487c2fbfb3SApril Chin ############################## 2497c2fbfb3SApril Chin ############################## 2507c2fbfb3SApril Chin ############################## 2517c2fbfb3SApril Chin ############################## 2527c2fbfb3SApril Chin ############################## 2537c2fbfb3SApril Chin ######### ######## ######### 2547c2fbfb3SApril Chin # #### #### #### # 2557c2fbfb3SApril Chin 2567c2fbfb3SApril Chin 2577c2fbfb3SApril Chin 2587c2fbfb3SApril Chin 2597c2fbfb3SApril Chin 2607c2fbfb3SApril Chin 2617c2fbfb3SApril Chin Written by 2627c2fbfb3SApril Chin 2637c2fbfb3SApril Chin Roland Mainz 2647c2fbfb3SApril Chin (roland.mainz@nrubsig.org) 2657c2fbfb3SApril Chin 2667c2fbfb3SApril Chin 2677c2fbfb3SApril Chin 2687c2fbfb3SApril Chin 2697c2fbfb3SApril Chin 2707c2fbfb3SApril Chin 2717c2fbfb3SApril Chin ############## 2727c2fbfb3SApril Chin ######################## 2737c2fbfb3SApril Chin #################**############ 2747c2fbfb3SApril Chin ################################ 2757c2fbfb3SApril Chin ############################ 2767c2fbfb3SApril Chin ###################### 2777c2fbfb3SApril Chin ################ 2787c2fbfb3SApril Chin ###################### 2797c2fbfb3SApril Chin ############################ 2807c2fbfb3SApril Chin ################################ 2817c2fbfb3SApril Chin ############################## 2827c2fbfb3SApril Chin ######################## 2837c2fbfb3SApril Chin ############## 2847c2fbfb3SApril Chin 2857c2fbfb3SApril Chin 2867c2fbfb3SApril Chin 2877c2fbfb3SApril Chin 2887c2fbfb3SApril Chin 2897c2fbfb3SApril Chin 2907c2fbfb3SApril Chin 2917c2fbfb3SApril Chin High scores: 2927c2fbfb3SApril Chin 2937c2fbfb3SApril Chin * 'chin' 8200 pt 2947c2fbfb3SApril Chin * 'gisburn' 7900 pt 2957c2fbfb3SApril Chin * 'tpenta' 5520 pt 2967c2fbfb3SApril Chin * 'kupfer' 5510 pt 2977c2fbfb3SApril Chin * 'noname' 5000 pt 2987c2fbfb3SApril Chin * 'noname' 4000 pt 2997c2fbfb3SApril Chin * 'livad' 3120 pt 3007c2fbfb3SApril Chin * 'noname' 3000 pt 3017c2fbfb3SApril Chin * 'noname' 2000 pt 3027c2fbfb3SApril Chin * 'noname' 1000 pt 3037c2fbfb3SApril Chin 3047c2fbfb3SApril ChinENDOFTEXT 3057c2fbfb3SApril Chin 3067c2fbfb3SApril Chin # clear screen, line-by-line 3077c2fbfb3SApril Chin for (( i=0 ; i < termsize.lines ; i++ )) ; do print "" ; done 3087c2fbfb3SApril Chin ) | (while read -r line ; do 3097c2fbfb3SApril Chin read -r -t 0.3 -n 1 c <&5 3107c2fbfb3SApril Chin [[ "$c" != "" ]] && exit ${magic_return_code} 3117c2fbfb3SApril Chin print -- "${line}" 3127c2fbfb3SApril Chin done) 3137c2fbfb3SApril Chin (( $? == magic_return_code )) && exit ${magic_return_code} 3147c2fbfb3SApril Chin ) 3157c2fbfb3SApril Chin (( $? == magic_return_code )) && return 0 3167c2fbfb3SApril Chin 3177c2fbfb3SApril Chin sleep 2 3187c2fbfb3SApril Chin done 3197c2fbfb3SApril Chin) 3207c2fbfb3SApril Chin} 3217c2fbfb3SApril Chin 3227c2fbfb3SApril Chinfunction run_menu 3237c2fbfb3SApril Chin{ 3247c2fbfb3SApril Chin integer numlevels=0 3257c2fbfb3SApril Chin integer selected_level=0 3267c2fbfb3SApril Chin typeset l 3277c2fbfb3SApril Chin 3287c2fbfb3SApril Chin # built list of available levels based on the "function levelmap_.*" 3297c2fbfb3SApril Chin # built into this script 3307c2fbfb3SApril Chin typeset -f | egrep "^function.*levelmap_.*" | sed 's/^function //' | 3317c2fbfb3SApril Chin while read -r l ; do 3327c2fbfb3SApril Chin levellist[numlevels]="$l" 3337c2fbfb3SApril Chin numlevels+=1 3347c2fbfb3SApril Chin done 3357c2fbfb3SApril Chin 3367c2fbfb3SApril Chin # swallow any queued user input (e.g. drain stdin) 3377c2fbfb3SApril Chin read -r -t 0.1 -n 100 dummy 3387c2fbfb3SApril Chin 3397c2fbfb3SApril Chin while true ; do 3407c2fbfb3SApril Chin # menu loop with timeout (which switches to "attract mode") 3417c2fbfb3SApril Chin while true ; do 3427c2fbfb3SApril Chin print -n -- "${vtcode["clear"]}" 3437c2fbfb3SApril Chin 3447c2fbfb3SApril Chin cat <<ENDOFTEXT 3457c2fbfb3SApril Chin>======================================\ 3467c2fbfb3SApril Chin> /-\ .--. | 3477c2fbfb3SApril Chin> | OO| / _.-' .-. .-. .-. .-. | 3487c2fbfb3SApril Chin> | | \ '-. '-' '-' '-' '-' | 3497c2fbfb3SApril Chin> ^^^^^ '--' | 3507c2fbfb3SApril Chin>======\ /================\ .-. | 3517c2fbfb3SApril Chin> | | | '-' | 3527c2fbfb3SApril Chin ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3537c2fbfb3SApril ChinENDOFTEXT 3547c2fbfb3SApril Chin print " GNAW - the ksh93 maze game" 3557c2fbfb3SApril Chin print "\n\tMenu:" 3567c2fbfb3SApril Chin 3577c2fbfb3SApril Chin print "\t - [L]evels:" 3587c2fbfb3SApril Chin for (( i=0 ; i < numlevels ; i++ )) ; do 3597c2fbfb3SApril Chin printf "\t %s %s \n" "$( (( i == selected_level )) && print -n "*" || print -n " ")" "${levellist[i]##levelmap_}" 3607c2fbfb3SApril Chin done 3617c2fbfb3SApril Chin 3627c2fbfb3SApril Chin print "\t - Rendering options:" 3637c2fbfb3SApril Chin printf "\t [%s] Use [U]nicode\n" "$( (( game_use_unicode == 1 )) && print -n "x" || print -n "_" )" 3647c2fbfb3SApril Chin printf "\t [%s] Use [C]olors\n" "$( (( game_use_colors == 1 )) && print -n "x" || print -n "_" )" 3657c2fbfb3SApril Chin 3667c2fbfb3SApril Chin print "\t - [S]tart - [Q]uit" 3677c2fbfb3SApril Chin 3687c2fbfb3SApril Chin # wait 30 secs (before we switch to "attract mode") 3697c2fbfb3SApril Chin c="" ; read -r -t 30 -n 1 c 3707c2fbfb3SApril Chin case "$c" in 3717c2fbfb3SApril Chin 'l') (( selected_level=(selected_level+numlevels+1) % numlevels )) ;; 3727c2fbfb3SApril Chin 'L') (( selected_level=(selected_level+numlevels-1) % numlevels )) ;; 3737c2fbfb3SApril Chin ~(Fi)s) 3747c2fbfb3SApril Chin (( game_use_colors == 1 )) && print -- "${vtcode["bg_black"]}" 3757c2fbfb3SApril Chin case "${game_use_colors}${game_use_unicode}" in 3767c2fbfb3SApril Chin "00") main_loop "${levellist[selected_level]}" ;; 3777c2fbfb3SApril Chin "01") main_loop "${levellist[selected_level]}" | map_filter 0 1 ;; 3787c2fbfb3SApril Chin "10") main_loop "${levellist[selected_level]}" | map_filter 1 0 ;; 3797c2fbfb3SApril Chin "11") main_loop "${levellist[selected_level]}" | map_filter 1 1 ;; 3807c2fbfb3SApril Chin esac 3817c2fbfb3SApril Chin print -- "${vtcode["vtreset"]}" 3827c2fbfb3SApril Chin ;; 3837c2fbfb3SApril Chin ~(Fi)q | $'\E') 3847c2fbfb3SApril Chin # make sure we do not exit on a cursor key (e.g. <esc>[A,B,C,D) 3857c2fbfb3SApril Chin read -r -t 0.01 -n 1 c 3867c2fbfb3SApril Chin if [[ "$c" == "[" ]] ; then 3877c2fbfb3SApril Chin # this was a cursor key sequence, just eat the 3rd charcater 3887c2fbfb3SApril Chin read -r -t 0.01 -n 1 c 3897c2fbfb3SApril Chin else 3907c2fbfb3SApril Chin exit 0 3917c2fbfb3SApril Chin fi 3927c2fbfb3SApril Chin ;; 3937c2fbfb3SApril Chin ~(Fi)u) (( game_use_unicode=(game_use_unicode+2+1) % 2)) ;; 3947c2fbfb3SApril Chin ~(Fi)c) (( game_use_colors=(game_use_colors+2+1) % 2)) ;; 3957c2fbfb3SApril Chin "") break ;; # timeout, switch to attract mode 3967c2fbfb3SApril Chin *) beep ;; 3977c2fbfb3SApril Chin esac 3987c2fbfb3SApril Chin done 3997c2fbfb3SApril Chin 4007c2fbfb3SApril Chin print -n -- "${vtcode["clear"]}" 4017c2fbfb3SApril Chin attract_mode 4027c2fbfb3SApril Chin done 4037c2fbfb3SApril Chin return 0 4047c2fbfb3SApril Chin} 4057c2fbfb3SApril Chin 4067c2fbfb3SApril Chinfunction levelmap_stripes 4077c2fbfb3SApril Chin{ 4087c2fbfb3SApril Chincat <<ENDOFLEVEL 4097c2fbfb3SApril Chin################################### 4107c2fbfb3SApril Chin#....... ............... P # 4117c2fbfb3SApril Chin#########..#################..### # 4127c2fbfb3SApril Chin#########..#################..### # 4137c2fbfb3SApril Chin#....... .. ..............# # 4147c2fbfb3SApril Chin############### ################ # 4157c2fbfb3SApril Chin############### ################ # 4167c2fbfb3SApril Chin#............. M ..............# # 4177c2fbfb3SApril Chin##..##################### ###### # 4187c2fbfb3SApril Chin##..##################### ###### # 4197c2fbfb3SApril Chin#....... ........... .......# # 4207c2fbfb3SApril Chin######## ############ ######### # 4217c2fbfb3SApril Chin# #### ############ ######### # 4227c2fbfb3SApril Chin# #.................. ......# # 4237c2fbfb3SApril Chin# ############################### # 4247c2fbfb3SApril Chin# # 4257c2fbfb3SApril Chin################################### 4267c2fbfb3SApril ChinENDOFLEVEL 4277c2fbfb3SApril Chin return 0 4287c2fbfb3SApril Chin} 4297c2fbfb3SApril Chin 4307c2fbfb3SApril Chinfunction levelmap_livad 4317c2fbfb3SApril Chin{ 4327c2fbfb3SApril Chincat <<ENDOFLEVEL 4337c2fbfb3SApril Chin##################################################### 4347c2fbfb3SApril Chin# # 4357c2fbfb3SApril Chin# ############## ############### ################ # 4367c2fbfb3SApril Chin# #............ P ..............# # 4377c2fbfb3SApril Chin# .#############################################.# # 4387c2fbfb3SApril Chin# #.#.......... ............#. # 4397c2fbfb3SApril Chin# #.#.########## ############### ############.#.# # 4407c2fbfb3SApril Chin# #...#........ ..........#...# # 4417c2fbfb3SApril Chin# #...#.#####################################.#.#.# # 4427c2fbfb3SApril Chin# #...#.#...... ........#...#.# # 4437c2fbfb3SApril Chin# #.#.#...###### #########################.#.#.#.# # 4447c2fbfb3SApril Chin# .#.....#.... M ......#...#.#.# # 4457c2fbfb3SApril Chin# #.#.#...####################### ########.#.#.#.# # 4467c2fbfb3SApril Chin# #...#.#...... ........#...#.# # 4477c2fbfb3SApril Chin# #...#.######## ############### ##########.#.#.# # 4487c2fbfb3SApril Chin# #...#........ ..........#...# # 4497c2fbfb3SApril Chin# #.#.#########################################.#.# # 4507c2fbfb3SApril Chin# #.#.......... ............#. # 4517c2fbfb3SApril Chin# .############ ############### ##############.# # 4527c2fbfb3SApril Chin# #............ ..............# # 4537c2fbfb3SApril Chin# ################################################# # 4547c2fbfb3SApril Chin# # 4557c2fbfb3SApril Chin##################################################### 4567c2fbfb3SApril ChinENDOFLEVEL 4577c2fbfb3SApril Chin return 0 4587c2fbfb3SApril Chin} 4597c2fbfb3SApril Chin 4607c2fbfb3SApril Chinfunction levelmap_classic1 4617c2fbfb3SApril Chin{ 4627c2fbfb3SApril Chincat <<ENDOFLEVEL 4637c2fbfb3SApril Chin######################### 4647c2fbfb3SApril Chin#.P.........#...........# 4657c2fbfb3SApril Chin#.####.####.#.####.####.# 4667c2fbfb3SApril Chin#.# #.# #.#.# #.# #.# 4677c2fbfb3SApril Chin#.# #.# #.#.# #.# #.# 4687c2fbfb3SApril Chin#.####.####.#.####.####.# 4697c2fbfb3SApril Chin#.......................# 4707c2fbfb3SApril Chin#.####.#.#######.#.####.# 4717c2fbfb3SApril Chin#.# #.#.# #.#.# #.# 4727c2fbfb3SApril Chin#.####.#.#######.#.####.# 4737c2fbfb3SApril Chin#......#....#....#......# 4747c2fbfb3SApril Chin######.####.#.####.###### 4757c2fbfb3SApril Chin###### # # ###### 4767c2fbfb3SApril Chin###### # ## ## # ###### 4777c2fbfb3SApril Chin###### # # # # ###### 4787c2fbfb3SApril Chin# # M # # 4797c2fbfb3SApril Chin###### # ####### # ###### 4807c2fbfb3SApril Chin###### # # ###### 4817c2fbfb3SApril Chin###### # ####### # ###### 4827c2fbfb3SApril Chin###### # # # # ###### 4837c2fbfb3SApril Chin######.#.#######.#.###### 4847c2fbfb3SApril Chin#...........#...........# 4857c2fbfb3SApril Chin#.###.###...#...###.###.# 4867c2fbfb3SApril Chin#...#...............#...# 4877c2fbfb3SApril Chin###.#....#######....#.### 4887c2fbfb3SApril Chin# #.#..#.# #.#..#.# # 4897c2fbfb3SApril Chin###....#.#######.#....### 4907c2fbfb3SApril Chin#......#....#....#......# 4917c2fbfb3SApril Chin#.#########.#.#########.# 4927c2fbfb3SApril Chin#.......................# 4937c2fbfb3SApril Chin######################### 4947c2fbfb3SApril ChinENDOFLEVEL 4957c2fbfb3SApril Chin return 0 4967c2fbfb3SApril Chin} 4977c2fbfb3SApril Chin 4987c2fbfb3SApril Chinfunction levelmap_classic2 4997c2fbfb3SApril Chin{ 5007c2fbfb3SApril Chincat <<ENDOFLEVEL 5017c2fbfb3SApril Chin####################### 5027c2fbfb3SApril Chin#.P...#.........#.....# 5037c2fbfb3SApril Chin#.###.#.#######.#.###.# 5047c2fbfb3SApril Chin#.....................# 5057c2fbfb3SApril Chin###.#.####.#.####.#.### 5067c2fbfb3SApril Chin###.#......#......#.### 5077c2fbfb3SApril Chin###.###.#######.###.### 5087c2fbfb3SApril Chin###.................### 5097c2fbfb3SApril Chin###.###.### ###.###.### 5107c2fbfb3SApril Chin###.#...#M #...#.### 5117c2fbfb3SApril Chin###.#.#.#######.#.#.### 5127c2fbfb3SApril Chin#.....#.........#.....# 5137c2fbfb3SApril Chin###.#####..#..#####.### 5147c2fbfb3SApril Chin###........#........### 5157c2fbfb3SApril Chin###.###.#######.###.### 5167c2fbfb3SApril Chin#.....................# 5177c2fbfb3SApril Chin#.###.####.#.####.###.# 5187c2fbfb3SApril Chin#.###.#....#....#.###.# 5197c2fbfb3SApril Chin#.###.#.#######.#.###.# 5207c2fbfb3SApril Chin#.....................# 5217c2fbfb3SApril Chin####################### 5227c2fbfb3SApril ChinENDOFLEVEL 5237c2fbfb3SApril Chin return 0 5247c2fbfb3SApril Chin} 5257c2fbfb3SApril Chin 5267c2fbfb3SApril Chinfunction levelmap_easy 5277c2fbfb3SApril Chin{ 5287c2fbfb3SApril Chincat <<ENDOFLEVEL 5297c2fbfb3SApril Chin################## 5307c2fbfb3SApril Chin# .............. # 5317c2fbfb3SApril Chin# . ###### # 5327c2fbfb3SApril Chin# . # M # # 5337c2fbfb3SApril Chin# . # # # 5347c2fbfb3SApril Chin# . ### ## # 5357c2fbfb3SApril Chin# . # # 5367c2fbfb3SApril Chin# . ### # 5377c2fbfb3SApril Chin# . # 5387c2fbfb3SApril Chin# .......... # 5397c2fbfb3SApril Chin# .......... P # 5407c2fbfb3SApril Chin################## 5417c2fbfb3SApril ChinENDOFLEVEL 5427c2fbfb3SApril Chin return 0 5437c2fbfb3SApril Chin} 5447c2fbfb3SApril Chin 5457c2fbfb3SApril Chinfunction levelmap_sunsolaristext 5467c2fbfb3SApril Chin{ 5477c2fbfb3SApril Chincat <<ENDOFLEVEL 5487c2fbfb3SApril Chin################################################ 5497c2fbfb3SApril Chin# .#### . # #....# # 5507c2fbfb3SApril Chin# # # # #....# # 5517c2fbfb3SApril Chin# #### # # #.#..# M # 5527c2fbfb3SApril Chin# # # # #..#.# # 5537c2fbfb3SApril Chin# # # # # #...## # 5547c2fbfb3SApril Chin# #### #### #....# # 5557c2fbfb3SApril Chin# # 5567c2fbfb3SApril Chin# #### #### # ## ##### # #### # 5577c2fbfb3SApril Chin# # #. .# # # # #....# # # # 5587c2fbfb3SApril Chin# #### # # # # P # #....# # #### # 5597c2fbfb3SApril Chin# # # ### #.#### #.### # # # 5607c2fbfb3SApril Chin# # .# #. .. # # #...# # # # # 5617c2fbfb3SApril Chin# #### #### ###### . # ....# # ####. # 5627c2fbfb3SApril Chin################################################ 5637c2fbfb3SApril ChinENDOFLEVEL 5647c2fbfb3SApril Chin return 0 5657c2fbfb3SApril Chin} 5667c2fbfb3SApril Chin 5677c2fbfb3SApril Chinfunction read_levelmap 5687c2fbfb3SApril Chin{ 5697c2fbfb3SApril Chin typeset map="$( $1 )" 5707c2fbfb3SApril Chin 5717c2fbfb3SApril Chin integer y=0 5727c2fbfb3SApril Chin integer x=0 5737c2fbfb3SApril Chin integer maxx=0 5747c2fbfb3SApril Chin integer numdots=0 5757c2fbfb3SApril Chin typeset line 5767c2fbfb3SApril Chin typeset c 5777c2fbfb3SApril Chin 5787c2fbfb3SApril Chin while read -r line ; do 5797c2fbfb3SApril Chin for (( x=0 ; x < ${#line} ; x++ )) ; do 5807c2fbfb3SApril Chin c="${line:x:1}" 5817c2fbfb3SApril Chin 5827c2fbfb3SApril Chin case $c in 5837c2fbfb3SApril Chin ".") numdots+=1 ;; 5847c2fbfb3SApril Chin "M") 5857c2fbfb3SApril Chin # log start position of monsters 5867c2fbfb3SApril Chin levelmap["monsterstartpos_x"]="$x" 5877c2fbfb3SApril Chin levelmap["monsterstartpos_y"]="$y" 5887c2fbfb3SApril Chin c=" " 5897c2fbfb3SApril Chin ;; 5907c2fbfb3SApril Chin "P") 5917c2fbfb3SApril Chin # log start position of player 5927c2fbfb3SApril Chin levelmap["playerstartpos_x"]="$x" 5937c2fbfb3SApril Chin levelmap["playerstartpos_y"]="$y" 5947c2fbfb3SApril Chin c=" " 5957c2fbfb3SApril Chin ;; 5967c2fbfb3SApril Chin esac 5977c2fbfb3SApril Chin 5987c2fbfb3SApril Chin levelmap["${x}_${y}"]="$c" 5997c2fbfb3SApril Chin done 6007c2fbfb3SApril Chin (( maxx=x , y++ )) 6017c2fbfb3SApril Chin done <<<"${map}" 6027c2fbfb3SApril Chin 6037c2fbfb3SApril Chin levelmap["max_x"]=${maxx} 6047c2fbfb3SApril Chin levelmap["max_y"]=${y} 6057c2fbfb3SApril Chin levelmap["numdots"]=${numdots} 6067c2fbfb3SApril Chin 6077c2fbfb3SApril Chin # consistency checks 6087c2fbfb3SApril Chin if [[ "${levelmap["monsterstartpos_x"]}" == "" ]] ; then 6097c2fbfb3SApril Chin fatal_error "read_levelmap: monsterstartpos_x is empty." 6107c2fbfb3SApril Chin fi 6117c2fbfb3SApril Chin if [[ "${levelmap["playerstartpos_x"]}" == "" ]] ; then 6127c2fbfb3SApril Chin fatal_error "read_levelmap: playerstartpos_x is empty." 6137c2fbfb3SApril Chin fi 6147c2fbfb3SApril Chin 6157c2fbfb3SApril Chin return 0 6167c2fbfb3SApril Chin} 6177c2fbfb3SApril Chin 6187c2fbfb3SApril Chinfunction player.set 6197c2fbfb3SApril Chin{ 6207c2fbfb3SApril Chin case "${.sh.subscript}" in 6217c2fbfb3SApril Chin pos_y) 6227c2fbfb3SApril Chin if [[ "${levelmap["${player["pos_x"]}_${.sh.value}"]}" == "#" ]] ; then 6237c2fbfb3SApril Chin .sh.value=${player["pos_y"]} 6247c2fbfb3SApril Chin beep 6257c2fbfb3SApril Chin fi 6267c2fbfb3SApril Chin ;; 6277c2fbfb3SApril Chin 6287c2fbfb3SApril Chin pos_x) 6297c2fbfb3SApril Chin if [[ "${levelmap["${.sh.value}_${player["pos_y"]}"]}" == "#" ]] ; then 6307c2fbfb3SApril Chin .sh.value=${player["pos_x"]} 6317c2fbfb3SApril Chin beep 6327c2fbfb3SApril Chin fi 6337c2fbfb3SApril Chin ;; 6347c2fbfb3SApril Chin esac 6357c2fbfb3SApril Chin return 0 6367c2fbfb3SApril Chin} 6377c2fbfb3SApril Chin 6387c2fbfb3SApril Chinfunction monster.set 6397c2fbfb3SApril Chin{ 6407c2fbfb3SApril Chin case "${.sh.subscript}" in 6417c2fbfb3SApril Chin *_pos_y) 6427c2fbfb3SApril Chin if [[ "${levelmap["${monster[${currmonster}_"pos_x"]}_${.sh.value}"]}" == "#" ]] ; then 6437c2fbfb3SApril Chin .sh.value=${monster[${currmonster}_"pos_y"]} 6447c2fbfb3SApril Chin # turn homing off when the monster hit a wall 6457c2fbfb3SApril Chin monster[${currmonster}_"homing"]=0 6467c2fbfb3SApril Chin fi 6477c2fbfb3SApril Chin ;; 6487c2fbfb3SApril Chin 6497c2fbfb3SApril Chin *_pos_x) 6507c2fbfb3SApril Chin if [[ "${levelmap["${.sh.value}_${monster[${currmonster}_"pos_y"]}"]}" == "#" ]] ; then 6517c2fbfb3SApril Chin .sh.value=${monster[${currmonster}_"pos_x"]} 6527c2fbfb3SApril Chin # turn homing off when the monster hit a wall 6537c2fbfb3SApril Chin monster[${currmonster}_"homing"]=0 6547c2fbfb3SApril Chin fi 6557c2fbfb3SApril Chin ;; 6567c2fbfb3SApril Chin esac 6577c2fbfb3SApril Chin return 0 6587c2fbfb3SApril Chin} 6597c2fbfb3SApril Chin 6607c2fbfb3SApril Chinfunction render_game 6617c2fbfb3SApril Chin{ 6627c2fbfb3SApril Chin # render_buffer is some kind of "background buffer" to "double buffer" 6637c2fbfb3SApril Chin # all output and combine it in one write to reduce flickering in the 6647c2fbfb3SApril Chin # terminal 6657c2fbfb3SApril Chin typeset render_buffer="$( 6667c2fbfb3SApril Chin integer screen_y_offset=1 6677c2fbfb3SApril Chin integer start_y_pos=0 6687c2fbfb3SApril Chin integer render_num_lines=${levelmap["max_y"]} 6697c2fbfb3SApril Chin 6707c2fbfb3SApril Chin if (( (termsize.lines-3) < levelmap["max_y"] )) ; then 6717c2fbfb3SApril Chin (( start_y_pos=player["pos_y"] / 2)) 6727c2fbfb3SApril Chin (( render_num_lines=termsize.lines-5)) 6737c2fbfb3SApril Chin fi 6747c2fbfb3SApril Chin 6757c2fbfb3SApril Chin #print -n -- "${vtcode["clear"]}" 6767c2fbfb3SApril Chin print_setcursorpos 0 0 6777c2fbfb3SApril Chin 6787c2fbfb3SApril Chin # print score (note the " " around "%d" are neccesary to clean up cruft 6797c2fbfb3SApril Chin # when we overwrite the level 6807c2fbfb3SApril Chin printf "SCORE: %05d DOTS: %.3d LIVES: %2.d " "${player["score"]}" "${levelmap["numdots"]}" "${player["lives"]}" 6817c2fbfb3SApril Chin print_levelmap ${screen_y_offset} ${start_y_pos} ${render_num_lines} 6827c2fbfb3SApril Chin 6837c2fbfb3SApril Chin # render player 6847c2fbfb3SApril Chin print_setcursorpos ${player["pos_x"]} $((player["pos_y"]+screen_y_offset-start_y_pos)) 6857c2fbfb3SApril Chin print -n "@" 6867c2fbfb3SApril Chin 6877c2fbfb3SApril Chin # render monsters 6887c2fbfb3SApril Chin for currmonster in ${monsterlist} ; do 6897c2fbfb3SApril Chin (( m_pos_x=monster[${currmonster}_"pos_x"] )) 6907c2fbfb3SApril Chin (( m_pos_y=monster[${currmonster}_"pos_y"]+screen_y_offset-start_y_pos )) 6917c2fbfb3SApril Chin 6927c2fbfb3SApril Chin if (( m_pos_y >= screen_y_offset && m_pos_y < render_num_lines )) ; then 6937c2fbfb3SApril Chin print_setcursorpos ${m_pos_x} ${m_pos_y} 6947c2fbfb3SApril Chin print -n "x" 6957c2fbfb3SApril Chin fi 6967c2fbfb3SApril Chin done 6977c2fbfb3SApril Chin 6987c2fbfb3SApril Chin # status block 6997c2fbfb3SApril Chin print_setcursorpos 0 $((render_num_lines+screen_y_offset)) 7007c2fbfb3SApril Chin emptyline=" " 7017c2fbfb3SApril Chin print -n " >> ${player["message"]} <<${emptyline:0:${#emptyline}-${#player["message"]}}" 7027c2fbfb3SApril Chin )" 7037c2fbfb3SApril Chin print -r -- "${render_buffer}${end_of_frame}" 7047c2fbfb3SApril Chin# print "renderbuffersize=$(print "${render_buffer}" | wc -c) ${end_of_frame}" 7057c2fbfb3SApril Chin return 0 7067c2fbfb3SApril Chin} 7077c2fbfb3SApril Chin 7087c2fbfb3SApril Chinfunction main_loop 7097c2fbfb3SApril Chin{ 7107c2fbfb3SApril Chin float sleep_per_cycle=0.2 7117c2fbfb3SApril Chin float seconds_before_read 7127c2fbfb3SApril Chin integer num_cycles=0 7137c2fbfb3SApril Chin float rs 7147c2fbfb3SApril Chin 7157c2fbfb3SApril Chin print -n -- "${vtcode["clear"]}" 7167c2fbfb3SApril Chin 7177c2fbfb3SApril Chin read_levelmap "$1" 7187c2fbfb3SApril Chin 7197c2fbfb3SApril Chin # player init 7207c2fbfb3SApril Chin player["pos_x"]=${levelmap["playerstartpos_x"]} 7217c2fbfb3SApril Chin player["pos_y"]=${levelmap["playerstartpos_y"]} 7227c2fbfb3SApril Chin player["score"]=0 # player score 7237c2fbfb3SApril Chin player["lives"]=5 # number of lives 7247c2fbfb3SApril Chin player["invulnerable"]=10 # cycles how long the player remains invulnerable 7257c2fbfb3SApril Chin player["message"]="Go..." 7267c2fbfb3SApril Chin 7277c2fbfb3SApril Chin monsterlist="maw claw jitterbug tentacle grendel" 7287c2fbfb3SApril Chin 7297c2fbfb3SApril Chin for currmonster in ${monsterlist} ; do 7307c2fbfb3SApril Chin monster[${currmonster}_"pos_x"]=${levelmap["monsterstartpos_x"]} 7317c2fbfb3SApril Chin monster[${currmonster}_"pos_y"]=${levelmap["monsterstartpos_y"]} 7327c2fbfb3SApril Chin monster[${currmonster}_"xstep"]=0 7337c2fbfb3SApril Chin monster[${currmonster}_"ystep"]=0 7347c2fbfb3SApril Chin monster[${currmonster}_"homing"]=0 7357c2fbfb3SApril Chin done 7367c2fbfb3SApril Chin 7377c2fbfb3SApril Chin # main game cycle loop 7387c2fbfb3SApril Chin while true ; do 7397c2fbfb3SApril Chin num_cycles+=1 7407c2fbfb3SApril Chin seconds_before_read=${SECONDS} 7417c2fbfb3SApril Chin c="" ; read -r -t ${sleep_per_cycle} -n 1 c 7427c2fbfb3SApril Chin 7437c2fbfb3SApril Chin if [[ "$c" != "" ]] ; then 7447c2fbfb3SApril Chin # special case handling for cursor keys which are usually composed 7457c2fbfb3SApril Chin # of three characters (e.g. "<ESC>[D"). If only <ESC> is hit we 7467c2fbfb3SApril Chin # quicky exit 7477c2fbfb3SApril Chin if [[ "$c" == $'\E' ]] ; then 7487c2fbfb3SApril Chin read -r -t 0.1 -n 1 c 7497c2fbfb3SApril Chin if [[ "$c" != "[" ]] ; then 7507c2fbfb3SApril Chin return 0 7517c2fbfb3SApril Chin fi 7527c2fbfb3SApril Chin 7537c2fbfb3SApril Chin # we assume the user is using the cursor keys, this |read| 7547c2fbfb3SApril Chin # should fetch the 3rd byte of the three-character sequence 7557c2fbfb3SApril Chin # for the cursor keys 7567c2fbfb3SApril Chin read -r -t 0.1 -n 1 c 7577c2fbfb3SApril Chin fi 7587c2fbfb3SApril Chin 7597c2fbfb3SApril Chin # if the user hit a key the "read" above was interrupted 7607c2fbfb3SApril Chin # and didn't wait exactly |sleep_per_cycle| seconds. 7617c2fbfb3SApril Chin # We wait here some moments (|rs|="remaining seconds") to 7627c2fbfb3SApril Chin # avoid that the game gets "faster" when more user input 7637c2fbfb3SApril Chin # is given. 7647c2fbfb3SApril Chin (( rs=sleep_per_cycle-(SECONDS-seconds_before_read) )) 7657c2fbfb3SApril Chin (( rs > 0.001 )) && sleep ${rs} 7667c2fbfb3SApril Chin 7677c2fbfb3SApril Chin player["message"]="" 7687c2fbfb3SApril Chin 7697c2fbfb3SApril Chin case "$c" in 7707c2fbfb3SApril Chin j|D|4) (( player["pos_x"]-=1 )) ;; 7717c2fbfb3SApril Chin k|C|6) (( player["pos_x"]+=1 )) ;; 7727c2fbfb3SApril Chin i|A|8) (( player["pos_y"]-=1 )) ;; 7737c2fbfb3SApril Chin m|B|2) (( player["pos_y"]+=1 )) ;; 7747c2fbfb3SApril Chin 7757c2fbfb3SApril Chin q) return 0 ;; 7767c2fbfb3SApril Chin esac 7777c2fbfb3SApril Chin 7787c2fbfb3SApril Chin if [[ "${levelmap["${player["pos_x"]}_${player["pos_y"]}"]}" == "." ]] ; then 7797c2fbfb3SApril Chin levelmap["${player["pos_x"]}_${player["pos_y"]}"]=" " 7807c2fbfb3SApril Chin (( levelmap["numdots"]-=1 )) 7817c2fbfb3SApril Chin 7827c2fbfb3SApril Chin (( player["score"]+=10 )) 7837c2fbfb3SApril Chin player["message"]='GNAW!!' 7847c2fbfb3SApril Chin 7857c2fbfb3SApril Chin if (( levelmap["numdots"] <= 0 )) ; then 7867c2fbfb3SApril Chin level_completed 7877c2fbfb3SApril Chin return 0 7887c2fbfb3SApril Chin fi 7897c2fbfb3SApril Chin fi 7907c2fbfb3SApril Chin fi 7917c2fbfb3SApril Chin 7927c2fbfb3SApril Chin # generic player status change 7937c2fbfb3SApril Chin if (( player["invulnerable"] > 0 )) ; then 7947c2fbfb3SApril Chin (( player["invulnerable"]-=1 )) 7957c2fbfb3SApril Chin fi 7967c2fbfb3SApril Chin if (( player["lives"] <= 0 )) ; then 7977c2fbfb3SApril Chin game_over 7987c2fbfb3SApril Chin return 0 7997c2fbfb3SApril Chin fi 8007c2fbfb3SApril Chin 8017c2fbfb3SApril Chin # move monsters 8027c2fbfb3SApril Chin for currmonster in ${monsterlist} ; do 8037c2fbfb3SApril Chin # make monster as half as slow then the others when it is following the user 8047c2fbfb3SApril Chin if (( monster[${currmonster}_"homing"] > 0 )) ; then 8057c2fbfb3SApril Chin (( (num_cycles%2) > 0 )) && continue 8067c2fbfb3SApril Chin fi 8077c2fbfb3SApril Chin 8087c2fbfb3SApril Chin if [[ ${monster[${currmonster}_"pos_x"]} == ${player["pos_x"]} ]] ; then 8097c2fbfb3SApril Chin if (( (monster[${currmonster}_"pos_y"]-player["pos_y"]) > 0 )) ; then 8107c2fbfb3SApril Chin (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=-1 )) 8117c2fbfb3SApril Chin else 8127c2fbfb3SApril Chin (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+1 )) 8137c2fbfb3SApril Chin fi 8147c2fbfb3SApril Chin monster[${currmonster}_"homing"]=1 8157c2fbfb3SApril Chin if (( player["invulnerable"] <= 0 )) ; then 8167c2fbfb3SApril Chin player["message"]="Attention: ${currmonster} is chasing you" 8177c2fbfb3SApril Chin fi 8187c2fbfb3SApril Chin elif (( monster[${currmonster}_"pos_y"] == player["pos_y"] )) ; then 8197c2fbfb3SApril Chin if (( (monster[${currmonster}_"pos_x"]-player["pos_x"]) > 0 )) ; then 8207c2fbfb3SApril Chin (( monster[${currmonster}_"xstep"]=-1 , monster[${currmonster}_"ystep"]=-0 )) 8217c2fbfb3SApril Chin else 8227c2fbfb3SApril Chin (( monster[${currmonster}_"xstep"]=+1 , monster[${currmonster}_"ystep"]=+0 )) 8237c2fbfb3SApril Chin fi 8247c2fbfb3SApril Chin monster[${currmonster}_"homing"]=1 8257c2fbfb3SApril Chin if (( player["invulnerable"] <= 0 )) ; then 8267c2fbfb3SApril Chin player["message"]="Attention: ${currmonster} is chasing you" 8277c2fbfb3SApril Chin fi 8287c2fbfb3SApril Chin else 8297c2fbfb3SApril Chin if (( monster[${currmonster}_"homing"] == 0 )) ; then 8307c2fbfb3SApril Chin case $((SECONDS % 6 + RANDOM % 4)) in 8317c2fbfb3SApril Chin 0) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+0 )) ;; 8327c2fbfb3SApril Chin 2) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+1 )) ;; 8337c2fbfb3SApril Chin 3) (( monster[${currmonster}_"xstep"]=+1 , monster[${currmonster}_"ystep"]=+0 )) ;; 8347c2fbfb3SApril Chin 5) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=-1 )) ;; 8357c2fbfb3SApril Chin 6) (( monster[${currmonster}_"xstep"]=-1 , monster[${currmonster}_"ystep"]=+0 )) ;; 8367c2fbfb3SApril Chin esac 8377c2fbfb3SApril Chin fi 8387c2fbfb3SApril Chin fi 8397c2fbfb3SApril Chin 8407c2fbfb3SApril Chin (( monster[${currmonster}_"pos_x"]=monster[${currmonster}_"pos_x"]+monster[${currmonster}_"xstep"] )) 8417c2fbfb3SApril Chin (( monster[${currmonster}_"pos_y"]=monster[${currmonster}_"pos_y"]+monster[${currmonster}_"ystep"] )) 8427c2fbfb3SApril Chin 8437c2fbfb3SApril Chin # check if a monster hit the player 8447c2fbfb3SApril Chin if (( player["invulnerable"] <= 0 )) ; then 8457c2fbfb3SApril Chin if (( monster[${currmonster}_"pos_x"] == player["pos_x"] && \ 8467c2fbfb3SApril Chin monster[${currmonster}_"pos_y"] == player["pos_y"] )) ; then 8477c2fbfb3SApril Chin # if player was hit by a monster take one life and 8487c2fbfb3SApril Chin # make him invulnerable for 10 cycles to avoid that 8497c2fbfb3SApril Chin # the next cycle steals more lives 8507c2fbfb3SApril Chin player["message"]="Ouuuchhhh" 8517c2fbfb3SApril Chin player["invulnerable"]=10 8527c2fbfb3SApril Chin (( player["lives"]-=1 )) 8537c2fbfb3SApril Chin 8547c2fbfb3SApril Chin beep ; beep ; sleep 0.2 ; beep ; beep 8557c2fbfb3SApril Chin fi 8567c2fbfb3SApril Chin fi 8577c2fbfb3SApril Chin done 8587c2fbfb3SApril Chin 8597c2fbfb3SApril Chin render_game 8607c2fbfb3SApril Chin done 8617c2fbfb3SApril Chin return 0 8627c2fbfb3SApril Chin} 8637c2fbfb3SApril Chin 8647c2fbfb3SApril Chinfunction map_filter 8657c2fbfb3SApril Chin{ 8667c2fbfb3SApril Chin typeset ch_player ch_monster ch_wall var 8677c2fbfb3SApril Chin 8687c2fbfb3SApril Chin if (( $1 == 1 )) ; then 8697c2fbfb3SApril Chin ch_player="${vtcode["fg_yellow"]}" 8707c2fbfb3SApril Chin ch_monster="${vtcode["fg_red"]}" 8717c2fbfb3SApril Chin ch_wall="${vtcode["fg_blue"]}" 8727c2fbfb3SApril Chin else 8737c2fbfb3SApril Chin ch_player="" 8747c2fbfb3SApril Chin ch_monster="" 8757c2fbfb3SApril Chin ch_wall="" 8767c2fbfb3SApril Chin fi 8777c2fbfb3SApril Chin 8787c2fbfb3SApril Chin if (( $2 == 1 )) ; then 8797c2fbfb3SApril Chin # unicode map 8807c2fbfb3SApril Chin ch_player+="$(printf '\u[24d2]')" 8817c2fbfb3SApril Chin ch_monster+="$(printf '\u[2605]')" 8827c2fbfb3SApril Chin ch_wall+="$(printf '\u[25a6]')" 8837c2fbfb3SApril Chin else 8847c2fbfb3SApril Chin # ascii map 8857c2fbfb3SApril Chin ch_player+="@" 8867c2fbfb3SApril Chin ch_monster+="x" 8877c2fbfb3SApril Chin ch_wall+="#" 8887c2fbfb3SApril Chin fi 8897c2fbfb3SApril Chin 8907c2fbfb3SApril Chin # note that this filter currently defeats the "double-buffering" 8917c2fbfb3SApril Chin while IFS='' read -r -d "${end_of_frame}" var ; do 8927c2fbfb3SApril Chin var="${var// /${vtcode["fg_grey"]} }" 8937c2fbfb3SApril Chin var="${var//\./${vtcode["fg_lightred"]}.}" 8947c2fbfb3SApril Chin var="${var//@/${ch_player}}" 8957c2fbfb3SApril Chin var="${var//x/${ch_monster}}" 8967c2fbfb3SApril Chin var="${var//#/${ch_wall}}" 8977c2fbfb3SApril Chin 8987c2fbfb3SApril Chin print -r -- "${var}" 8997c2fbfb3SApril Chin done 9007c2fbfb3SApril Chin return 0 9017c2fbfb3SApril Chin} 9027c2fbfb3SApril Chin 9037c2fbfb3SApril Chinfunction exit_trap 9047c2fbfb3SApril Chin{ 9057c2fbfb3SApril Chin # restore stty settings 9067c2fbfb3SApril Chin stty ${saved_stty} 9077c2fbfb3SApril Chin 9087c2fbfb3SApril Chin print "bye." 9097c2fbfb3SApril Chin return 0 9107c2fbfb3SApril Chin} 9117c2fbfb3SApril Chin 9127c2fbfb3SApril Chinfunction usage 9137c2fbfb3SApril Chin{ 9147c2fbfb3SApril Chin OPTIND=0 9157c2fbfb3SApril Chin getopts -a "${progname}" "${gnaw_usage}" OPT '-?' 9167c2fbfb3SApril Chin exit 2 9177c2fbfb3SApril Chin} 9187c2fbfb3SApril Chin 9197c2fbfb3SApril Chin# program start 9207c2fbfb3SApril Chin# make sure we use the ksh93 "cat" builtin which supports the "-u" option 9217c2fbfb3SApril Chinbuiltin basename 9227c2fbfb3SApril Chinbuiltin cat 9237c2fbfb3SApril Chinbuiltin wc 9247c2fbfb3SApril Chin 9257c2fbfb3SApril Chintypeset progname="${ basename "${0}" ; }" 9267c2fbfb3SApril Chin 9277c2fbfb3SApril Chin# terminal size rect 92834f9b3eeSRoland Mainzcompound termsize=( 9297c2fbfb3SApril Chin integer columns=-1 9307c2fbfb3SApril Chin integer lines=-1 9317c2fbfb3SApril Chin) 9327c2fbfb3SApril Chin 9337c2fbfb3SApril Chin# global variables 9347c2fbfb3SApril Chintypeset quiet=false 9357c2fbfb3SApril Chin 9367c2fbfb3SApril Chintypeset -A levelmap 9377c2fbfb3SApril Chintypeset -A player 9387c2fbfb3SApril Chintypeset -A monster 9397c2fbfb3SApril Chin# global rendering options 9407c2fbfb3SApril Chininteger game_use_colors=0 9417c2fbfb3SApril Chininteger game_use_unicode=0 9427c2fbfb3SApril Chin 9437c2fbfb3SApril Chintypeset -r gnaw_usage=$'+ 94434f9b3eeSRoland Mainz[-?\n@(#)\$Id: gnaw (Roland Mainz) 2009-05-09 \$\n] 9457c2fbfb3SApril Chin[-author?Roland Mainz <roland.mainz@nrubsig.org>] 9467c2fbfb3SApril Chin[+NAME?gnaw - maze game written in ksh93] 9477c2fbfb3SApril Chin[+DESCRIPTION?\bgnaw\b is a maze game. 9487c2fbfb3SApril Chin The player maneuvers a yellow "@" sign to navigate a maze while eating 9497c2fbfb3SApril Chin small dots. A level is finished when all the dots are eaten. Five monsters 9507c2fbfb3SApril Chin (maw, claw, jitterbug, tentacle and grendel) also wander the maze in an attempt 9517c2fbfb3SApril Chin to catch the "@". Each level begins with all ghosts in their home, and "@" near 9527c2fbfb3SApril Chin the bottom of the maze. The monsters are released from the home one by one at the 9537c2fbfb3SApril Chin start of each level and start their rentless hunt after the player.] 9547c2fbfb3SApril Chin[q:quiet?Disable use of terminal bell.] 9557c2fbfb3SApril Chin[+SEE ALSO?\bksh93\b(1)] 9567c2fbfb3SApril Chin' 9577c2fbfb3SApril Chin 9587c2fbfb3SApril Chinwhile getopts -a "${progname}" "${gnaw_usage}" OPT ; do 9597c2fbfb3SApril Chin# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" 9607c2fbfb3SApril Chin case ${OPT} in 9617c2fbfb3SApril Chin q) quiet=true ;; 9627c2fbfb3SApril Chin +q) quiet=false ;; 9637c2fbfb3SApril Chin *) usage ;; 9647c2fbfb3SApril Chin esac 9657c2fbfb3SApril Chindone 9667c2fbfb3SApril Chinshift $((OPTIND-1)) 9677c2fbfb3SApril Chin 9687c2fbfb3SApril Chin# save stty values and register the exit trap which restores these values on exit 9697c2fbfb3SApril Chinsaved_stty="$(stty -g)" 9707c2fbfb3SApril Chintrap exit_trap EXIT 9717c2fbfb3SApril Chin 9727c2fbfb3SApril Chinprint "Loading..." 9737c2fbfb3SApril Chin 9747c2fbfb3SApril Chin# set stty values, "-icanon min 1 time 0 -inpck" should improve input latency, 9757c2fbfb3SApril Chin# "-echo" turns the terminal echo off 9767c2fbfb3SApril Chinstty -icanon min 1 time 0 -inpck -echo 9777c2fbfb3SApril Chin 9787c2fbfb3SApril Chinget_term_size termsize || fatal_error "Could not get terminal size." 9797c2fbfb3SApril Chin 9807c2fbfb3SApril Chin# prechecks 9817c2fbfb3SApril Chin(( termsize.columns < 60 )) && fatal_error "Terminal width must be larger than 60 columns (currently ${termsize.columns})." 9827c2fbfb3SApril Chin 9837c2fbfb3SApril Chintypeset -A vtcode 9847c2fbfb3SApril Chin# color values taken from http://frexx.de/xterm-256-notes/, other 9857c2fbfb3SApril Chin# codes from http://vt100.net/docs/vt100-tm/ 9867c2fbfb3SApril Chinvtcode=( 9877c2fbfb3SApril Chin ["bg_black"]="$(print -n "\E[40m")" 9887c2fbfb3SApril Chin ["fg_black"]="$(print -n "\E[30m")" 9897c2fbfb3SApril Chin ["fg_red"]="$(print -n "\E[31m")" 9907c2fbfb3SApril Chin ["fg_lightred"]="$(print -n "\E[1;31m")" 9917c2fbfb3SApril Chin ["fg_green"]="$(print -n "\E[32m")" 9927c2fbfb3SApril Chin ["fg_lightgreen"]="$(print -n "\E[1;32m")" 9937c2fbfb3SApril Chin ["fg_yellow"]="$(print -n "\E[33m")" 9947c2fbfb3SApril Chin ["fg_lightyellow"]="$(print -n "\E[1;33m")" 9957c2fbfb3SApril Chin ["fg_blue"]="$(print -n "\E[34m")" 9967c2fbfb3SApril Chin ["fg_lightblue"]="$(print -n "\E[1;34m")" 9977c2fbfb3SApril Chin ["fg_grey"]="$(print -n "\E[1;37m")" 9987c2fbfb3SApril Chin ["fg_white"]="$(print -n "\E[37m")" 9997c2fbfb3SApril Chin 10007c2fbfb3SApril Chin # misc other vt stuff 10017c2fbfb3SApril Chin ["vtreset"]="$(tput reset)" 10027c2fbfb3SApril Chin ["clear"]="$(tput clear)" 10037c2fbfb3SApril Chin ["bel"]="$(tput bel)" 10047c2fbfb3SApril Chin ["spaceline"]="$(for (( i=0 ; i < termsize.columns ; i++ )) ; do print -n " " ; done)" 10057c2fbfb3SApril Chin) 10067c2fbfb3SApril Chin 10077c2fbfb3SApril Chin# character used to as marker that a single frame ends at this point - this 10087c2fbfb3SApril Chin# is used by the "double buffering" code to make sure the "read" builtin 10097c2fbfb3SApril Chin# can read a whole "frame" instead of reading stuff line-by-line 10107c2fbfb3SApril Chintypeset -r end_of_frame=$'\t' 10117c2fbfb3SApril Chin 10127c2fbfb3SApril Chin# get terminal sequence to move cursor to position x,y 10137c2fbfb3SApril Chin# (see http://vt100.net/docs/vt100-ug/chapter3.html#CPR) 10147c2fbfb3SApril Chincase ${TERM} in 10157c2fbfb3SApril Chin xterm | xterm-color | vt100 | vt220 | dtterm | sun | sun-color) 10167c2fbfb3SApril Chin cup="$(infocmp -1 | \ 10177c2fbfb3SApril Chin egrep '^[[:space:]]*cup=' | \ 10187c2fbfb3SApril Chin sed -e 's/.*cup=//' \ 10197c2fbfb3SApril Chin -e 's/%[%id]*p1[%id]*/%2\\\$d/g' \ 10207c2fbfb3SApril Chin -e 's/%[%id]*p2[%id]*/%1\\\$d/g' \ 10217c2fbfb3SApril Chin -e 's/,$//')" 10227c2fbfb3SApril Chin for (( x=0 ; x < termsize.columns ; x++ )) ; do 10237c2fbfb3SApril Chin for (( y=0 ; y < termsize.lines ; y++ )) ; do 10247c2fbfb3SApril Chin vtcode[cup_${x}_${y}]="$(printf "${cup}" $((x + 1)) $((y + 1)) )" 10257c2fbfb3SApril Chin done 10267c2fbfb3SApril Chin done 10277c2fbfb3SApril Chin ;; 10287c2fbfb3SApril Chin *) 10297c2fbfb3SApril Chin printf "# Unrecognised terminal type '%s', fetching %dx%d items from terminfo database, please wait...\n" "${TERM}" "${termsize.columns}" "${termsize.lines}" 10307c2fbfb3SApril Chin for (( x=0 ; x < termsize.columns ; x++ )) ; do 10317c2fbfb3SApril Chin for (( y=0 ; y < termsize.lines ; y++ )) ; do 10327c2fbfb3SApril Chin vtcode[cup_${x}_${y}]="$(tput cup ${y} ${x})" 10337c2fbfb3SApril Chin done 10347c2fbfb3SApril Chin done 10357c2fbfb3SApril Chin ;; 10367c2fbfb3SApril Chinesac 10377c2fbfb3SApril Chin 10387c2fbfb3SApril Chinprint -- "${vtcode["vtreset"]}" 10397c2fbfb3SApril Chin 10407c2fbfb3SApril Chinrun_logo 10417c2fbfb3SApril Chinrun_menu 10427c2fbfb3SApril Chin 10437c2fbfb3SApril Chinexit 0 10447c2fbfb3SApril Chin# EOF. 1045