#!/bin/sh :;exec /usr/local/bin/stk -f "$0" "$@" ;;;; ;;;; STetris Version 1.1 ;;;; By Harvey J. Stein hjstein@math.huji.ac.il ;;;; Copyright (C) 1994 Harvey J. Stein, Tel Aviv, ISRAEL ;;;; ;;;; Permission to use, copy, and/or distribute this software and its ;;;; documentation for any purpose is hereby granted, provided that ;;;; both the above copyright notice and this permission notice appear ;;;; in all copies and derived works, and that copies and/or derived ;;;; works are used, copied and/or distributed without fees. Fees for ;;;; distribution or use of this software or derived works may only be ;;;; charged with express written permission of the copyright holder. ;;;; This software is provided ``as is'' without express or implied ;;;; warranty. ;;; This is an implementation of a falling block game. Just run it. ;;; ;;; The controls are as follows, but are easily modified (see below): ;;; Move to left : j or left arrow ;;; Move to right: l or right arrow ;;; Rotate right : k or down arrow ;;; Rotate left : i or up arrow ;;; Drop quick : space ;;; New game : n ;;; Pause : p ;;; Continue : c ;;; Scramble : s - Scrambles the blocks so that rotate left & ;;; rotate right actually transform the shape ;;; instead of rotating it. Only available ;;; between games. ;;; Unscramble : u - Go back to original configuration ;;; Help : h ;;; Quit : q ;;; End game : e ;;; Bump up level: b ;;; ;;; ------------- Installation ------------------------------- ;;; Should just work fine as is. If you have xboing, and you have a ;;; /dev/audio device, this game can produce sounds. To get the ;;; sounds, edit the definition of sounddir (first definition of the ;;; global variables section below). Make sure it refers to the ;;; directory with your xboing sounds. ;;; To do: ;;; -Maintain high score file. Question: How can I protect it? ;;; (Typically one will make a high score file write only to group ;;; games & make the game suid games. But, this can't be done in ;;; general for shellscripts). ;;; -Man page. ;;; -Next piece preview. ;;; -More sounds. ;;; -Better way to play sounds than catting to /dev/audio. ;;; -Make up sounds for game instead of just "borrowing" sounds from ;;; xboing. ;;; -Code cleanup - Parameterize the pieces better. Right now I ;;; have the number 7 (for the number of pieces) hard wired into ;;; the code, and the colors of each piece are just stuffed into a ;;; fcn. It would be nice to have a global variable (n) for the # of ;;; blocks to use in the pieces & then to generate all the pieces ;;; containing n squares. ;;; -Find better way of playing sounds than catting to /dev/audio ;;; -Standardize comment style. ;;; -Write STk program which uses send to play stetris. ;;; -Need to change name of window before I can write a stetris ;;; player that uses send... ;;; -Fix bug where game sometimes ends with last piece overlapping ;;; another piece. ;;; Changes from v1.0 to v1.1: ;;; -Got rid of some of the 7s. ;;; -Added scrambling & help. ;;; -Didn't fix bug where game sometimes ends with last piece ;;; overlapping another piece, but made it more rare. ;;; -Now starts of pieces off screen so that they all appear ;;; initially as one row. ;;; -Added buttons for new game, pause, unpause, help, etc. ;;; -Blank screen during pauses. ;;; -No need for stetris shellscript (thanks to Erick). ;;; -Added to increase level by 1. ;;; -Reduced min-fall-delay from 80 to 60 because it seems to be ;;; long enough (at least on my 486dx33). Make it bigger if your ;;; top level is jerky. ;;; Helpful for debugging (so that stetris.stk can be reloaded into ;;; the interpreter): (for-each destroy (winfo 'children *root*)) ;;; To avoid inopportune garbage collections: (cond ((not (symbol-bound? 'heap-expanded)) ; Don't expand after addn'l loads. (expand-heap 75000) (define heap-expanded #t))) ;;; ------------------- Include files ------------------------ (require "Tk-classes") (require "fs") (require "dialog") ;;; ----------- Global variables --------------------------- ;; Sound directory (set for your system, or set to a nonexistent directory to ;; disable sound): (define sounddir "/usr/games/lib/xboing/sounds") ;;; Sounds (modifiable): ;;; Expects to find (string-append soundir "/" "game_over.au"), for example. ;;; Sound is played by catting it to /dev/audio (define soundmap '((game-over "game_over.au") (near-end "looksbad.au") (goto-next-level "warp.au") (piece-landed "metal.au") (piece-moved "click.au") (three-in-row "applause.au") (four-in-row "youagod.au"))) ;; Keyboard mappings & corresponding actions (modifiable). ;; Now found at end... ;; block size & playing field size parameters (modifyable). (define block-width 20) ; Width of a block. (define block-height 20) ; Height of a block. (define block-border-width 2) ; Width of block borders. (define play-cols 9) ; cols # 0-9 = 10 cols. (define play-rows 29) ; rows # 0-28 = 29 rows. ;; Window shape & size parameters (modifyable). (define frame-border-width 3) ; Width of frame border for ; playing field & score box. (define score-frame-width 150) ; Width of score box (don't ; make too small!). ;; Game parameters (modifiable). (define start-fall-delay 750) ; initially, game drops stetris piece ; one notch every start-fall-delay ; milliseconds. (define level-time (* 40 start-fall-delay)) ; Length of time (in milliseconds) ; that each level lasts. (define min-fall-delay 60) ; Min amt of time allowable btw piece ; drops. (define delta-reducer .80) ; Each time level goes up, multiply ; fall-delay by this to get new fall ; delay. (define bump-bonus 300) ; When you bump up the level ; manually, you get bump-bonus ; pts * the % of time left ; until the next level. ;;; -------------- Less modifiable parameters -------------------- ;; Game parameters (don't touch). (define winx (* block-width (1+ play-cols))) ; size of playing field (define winy (* block-width (1+ play-rows))) (define start-delta-count 0) ; # of steps at game start. (define delta-count start-delta-count) ; Lapsed time (in steps) of current ; level. (define level-number 1) ; Current level number. (define fall-delay start-fall-delay) ; Current amt of time btw drops (in ms) (define move-count 1) ; # drops since beginning of game. (define old-count 1) ; # drops since last piece hit bottom. (define quit-now #t) ; False causes game to stop. (define current-piece ()) ; Piece that is currently falling. (define score 0) ; Score. (define game-over "") ; String to display when game ends. (define paused-game #f) (define (ms-left) (- level-time (* fall-delay delta-count))) (define (time-left) (inexact->exact (/ (ms-left) 1000))) (define time-to-speedup (time-left)) ; Time left to current level. (define current-block-colors ()) ; Used to store block colors ; when screen is blanked. ;;; ------------ Start real work ---------------------------- ;;; Check sound validity - First check that sounddir exists & that ;;; /dev/audio exists. (cond ((or (not (file-is-directory? sounddir)) ;;; If sounddir doesn't exist. (not (file-is-writable? "/dev/audio"))) ;; If /dev/audio doesn't exist. (set! soundmap ()))) ;;; Now, check that all sounds are readable. Delete the ones that ;;; aren't. (set! soundmap (let delete-nonexistent ((l soundmap)) (cond ((null? l) ()) ((file-is-readable? (string-append sounddir "/" (cadar l))) (cons (car l) (delete-nonexistent (cdr l)))) (else (delete-nonexistent (cdr l)))))) (define (reset-vars) ;;; Clears game variables for start of new game. (set! delta-count start-delta-count) (set! level-number 1) (set! fall-delay start-fall-delay) (set! old-count 1) (set! move-count 1) (set! quit-now #f) (set! score 0) (set! game-over "")) ;;; ------------------ Window size setup -------------------------- (wm 'title *root* "STetris") (wm 'minsize *root* (+ winx score-frame-width) (+ winy (* 2 frame-border-width))) (wm 'maxsize *root* (+ winx score-frame-width) (+ winy (* 2 frame-border-width))) (wm 'geometry *root* (format #f "~Ax~A" (+ winx score-frame-width) (+ winy (* 2 frame-border-width)))) ;;; -------------------- Widget Creation --------------------------- ;;; Playing canvas '(define canvas-frame (make :relief 'ridge :highlight-thickness -2 :border-width frame-border-width)) '(pack canvas-frame :side 'left) (define stetris-canvas (make :height winy :border-width 0 :relief 'ridge :highlight-thickness 0 :width winx)) (pack stetris-canvas :side 'left :fill 'both :expand #f) ;;; Statistics frame (define score-frame (make :relief 'ridge :border-width frame-border-width)) (pack score-frame :fill 'both :expand #t :side 'left) (define filler-1 (make :parent score-frame)) (define score-title-label (make