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