├── debian ├── compat ├── manpages ├── docs ├── install ├── source │ └── format ├── .depends ├── dirs ├── rules ├── menu ├── postrm ├── postinst ├── control ├── copyright └── changelog ├── .metadata ├── tint.scores ├── README.md ├── CREDITS ├── tint.6 ├── config.h ├── utils.h ├── NOTES ├── typedefs.h ├── utils.c ├── Makefile ├── io.h ├── engine.h ├── io.c ├── engine.c └── tint.c /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/manpages: -------------------------------------------------------------------------------- 1 | tint.6 2 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | NOTES 2 | CREDITS 3 | -------------------------------------------------------------------------------- /debian/install: -------------------------------------------------------------------------------- 1 | tint usr/games 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /debian/.depends: -------------------------------------------------------------------------------- 1 | tint.postinst.o: tint.postinst.c 2 | -------------------------------------------------------------------------------- /debian/dirs: -------------------------------------------------------------------------------- 1 | usr/games 2 | usr/share/man/man6 3 | var/games 4 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | %: 4 | dh $@ 5 | 6 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidGriffith/tint/HEAD/.metadata -------------------------------------------------------------------------------- /tint.scores: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidGriffith/tint/HEAD/tint.scores -------------------------------------------------------------------------------- /debian/menu: -------------------------------------------------------------------------------- 1 | ?package(tint):needs="text" section="Games/Blocks" \ 2 | title="TINT Is Not Tetris(tm)" \ 3 | command="sh -c '/usr/games/tint -l 5;echo;echo PRESS ENTER;read line'" \ 4 | hints="Text" 5 | -------------------------------------------------------------------------------- /debian/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | scorefile="/var/games/tint.scores" 4 | 5 | if [ "$1" = "purge" ] 6 | then 7 | if [ -e $scorefile ] 8 | then 9 | rm $scorefile 10 | fi 11 | fi 12 | 13 | #DEBHELPER# 14 | 15 | -------------------------------------------------------------------------------- /debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | scorefile="/var/games/tint.scores" 4 | 5 | if [ ! -e $scorefile ] 6 | then 7 | touch $scorefile 8 | chmod 0664 $scorefile 9 | chown root:games $scorefile 10 | fi 11 | 12 | #DEBHELPER# 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TINT Is Not Tetris(tm) ...at least the name isn't 2 | ================================================= 3 | 4 | --- 5 | 6 | As the title suggests, this is a clone of the original tetris game 7 | written by Alexey Pajitnov, Dmitry Pavlovsky, and Vadim Gerasimov. 8 | 9 | The game is as close to the original as possible, but there are a few 10 | differences. Nevertheless, it's probably the closest to the original 11 | that you'll ever find in the UNIX world... 12 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: tint 2 | Section: games 3 | Priority: optional 4 | Maintainer: Mario Lang 5 | Build-Depends: debhelper (>= 7), libncurses5-dev 6 | Standards-Version: 3.9.1 7 | 8 | Package: tint 9 | Architecture: any 10 | Depends: ${shlibs:Depends}, ${misc:Depends} 11 | Description: TINT Is Not Tetris(tm) ...at least the name isn't 12 | As the title suggests, this is a clone of the original tetris game 13 | written by Alexey Pajitnov, Dmitry Pavlovsky, and Vadim Gerasimov. 14 | . 15 | The game is as close to the original as possible, but there are a few 16 | differences. Nevertheless, it's probably the closest to the original 17 | that you'll ever find in the UNIX world... 18 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | 2 | Many thanks to the authors of the original tetris(tm) on which this 3 | game is based: 4 | 5 | Alexey Pajitnov 6 | Dmitry Pavlovsky 7 | Vadim Gerasimov 8 | 9 | Here are some links to pay tribute to their efforts: 10 | 11 | http://vadim.www.media.mit.edu/Tetris.htm 12 | http://www.geocities.com/Hollywood/2430/tetris.html 13 | http://atarihq.com/tsr/special/tetrishist.html 14 | 15 | As you'll see from those pages, there is a certain evil company prohibiting 16 | software such as this. This is unfortunate and is also the reason why you 17 | have to type tint each time you want to play the game instead 18 | you-know-what :P 19 | 20 | Here is a list of people who have written code for tint: 21 | 22 | Robert Lemmen 23 | Marcello Mamino 24 | 25 | Thanks for your contributions. 26 | 27 | -------------------------------------------------------------------------------- /tint.6: -------------------------------------------------------------------------------- 1 | .TH TINT 6 "Nov 28, 2019" 2 | .\" Please adjust this date whenever revising the manpage. 3 | .\" 4 | .\" Some roff macros, for reference: 5 | .\" .nh disable hyphenation 6 | .\" .hy enable hyphenation 7 | .\" .ad l left justify 8 | .\" .ad b justify to both left and right margins 9 | .\" .nf disable filling 10 | .\" .fi enable filling 11 | .\" .br insert line break 12 | .\" .sp insert n+1 empty lines 13 | .\" for manpage-specific macros, see man(7) 14 | .SH NAME 15 | tint \- clone of the original tint 16 | .SH SYNOPSIS 17 | .B tint 18 | .RI [ -h ] 19 | .RI [ -l\ level ] 20 | .RI [ -n ] 21 | .RI [ -d ] 22 | .RI [ -b\ char ] 23 | .RI [ -s ] 24 | .SH DESCRIPTION 25 | This manual page documents briefly the 26 | .B tint 27 | clone. As with all games (and especially with tint), you have to play it, 28 | not read about it. 29 | .SH OPTIONS 30 | A summary of options is included below. 31 | For a complete description, see the NOTES file in /usr/share/doc/tint. 32 | .TP 33 | .B \-h 34 | Show summary of options. 35 | .TP 36 | .B \-l 37 | Specify the starting level (1-9). The higher the level you're starting from, 38 | the faster you'll earn points. 39 | .TP 40 | .B \-n 41 | Draw next shape. When the next shape is drawn, you might find the game to be 42 | easier, but it will be slower to earn points. 43 | .TP 44 | .B \-d 45 | Draw dotted lines. 46 | .TP 47 | .B \-b 48 | Use the specified character (instead of spaces) to draw blocks. 49 | .TP 50 | .B \-s 51 | Draw shadow of shape. 52 | .SH AUTHOR 53 | This manual page was written by Abraham van der Merwe , 54 | for the Debian GNU/Linux system (but may be used by others). 55 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | /* 5 | * Copyright (c) Abraham vd Merwe 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of the author nor the names of other contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | /* Score file */ 33 | const char scorefile[] = SCOREFILE; 34 | 35 | #endif /* #ifndef CONFIG_H */ 36 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This is the Debian GNU/Linux prepackaged version of tint. These 2 | files were written and packaged by Abraham van der Merwe 3 | 4 | The games is released under a derivative of the BSD license. For more 5 | information see http://www.opensource.org/licenses/bsd-license.html 6 | 7 | The original source can be found at: http://oasis.frogfoot.net 8 | 9 | Copyright: 10 | 11 | Copyright (c) Abraham vd Merwe 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions 16 | are met: 17 | 18 | 1. Redistributions of source code must retain the above copyright 19 | notice, this list of conditions and the following disclaimer. 20 | 21 | 2. Redistributions in binary form must reproduce the above copyright 22 | notice, this list of conditions and the following disclaimer in the 23 | documentation and/or other materials provided with the distribution. 24 | 25 | 3. Neither the name of the author nor the names of other contributors 26 | may be used to endorse or promote products derived from this software 27 | without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 30 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 31 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 36 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 37 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | 40 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | /* 5 | * Copyright (c) Abraham vd Merwe 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of the author nor the names of other contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "typedefs.h" 33 | 34 | /* 35 | * Initialize random number generator 36 | */ 37 | void rand_init (); 38 | 39 | /* 40 | * Generate a random number within range 41 | */ 42 | int rand_value (int range); 43 | 44 | /* 45 | * Convert an str to long. Returns TRUE if successful, 46 | * FALSE otherwise. 47 | */ 48 | bool str2int (int *i,const char *str); 49 | 50 | #endif /* #ifndef UTILS_H */ 51 | -------------------------------------------------------------------------------- /NOTES: -------------------------------------------------------------------------------- 1 | 2 | ROTATION 3 | -------- 4 | STEP 1: 5 | Drop the rotate() functions and make a datastructure which holds all the 6 | shapes (and their rotated versions). 7 | 8 | typedef struct 9 | { 10 | int x,y; 11 | } block_t; 12 | 13 | typedef struct 14 | { 15 | int color; 16 | int next; 17 | block_t block[NUMSHAPES]; 18 | } shape_t; 19 | 20 | We then just hold the current blocknumber, when we rotate it, we replace it 21 | with it's the next field, and so on. 22 | 23 | STEP 2: 24 | Also, make the board a one-dimensional array and get rid of the block_t 25 | structure. The shape_t structure should look like this then: 26 | 27 | typedef struct 28 | { 29 | int next; 30 | int block[NUMSHAPES]; 31 | } shape_t; 32 | 33 | Just make a array with the initial 7 colors, and keep that color until the 34 | next piece is chosen. This should prove to be the optimal solution. 35 | 36 | SCORE 37 | ----- 38 | 39 | Ok, here's what I could figure out and what I think should be used. 40 | 41 | 1. We count the number of lines that a piece drops when the user press SPACE, 42 | 2. Add 1 to that when we figure out that the block has come to rest, 43 | 3. Multiply above by the current level, 44 | 4. If "Show Next" is enabled, divide by two, else take as is, and add the 45 | result to the score. 46 | 47 | Of course, we should add 2 instead of 1 to prevent loss of precision in step 48 | 4, and the displayed score is then the score / 2. 49 | 50 | TIMING 51 | ------ 52 | 53 | Here's what I'm going to use: 54 | 55 | 1. There is 9 levels, numbered from 1 to 9. We allow 1/level of a second to 56 | pass before we drop each block one line. 57 | 58 | 2. After each ten lines that is removed, we increase the level automatically, 59 | unless the player is already at the highest level (level 9). CAVEAT: If the 60 | user starts at a higher level than one, we pretend he didn't when we come 61 | to increasing levels, e.g. if he/she started at level 3, 30 lines must be 62 | dropped before we go to level 4. 63 | 64 | 3. I still have to decide whether to use the BSD type delaying (the type I'm 65 | currently using) or to do it the way I first did it (the signal handler 66 | method). The question remains which one is the most playable and which 67 | one is the most portable. 68 | 69 | -------------------------------------------------------------------------------- /typedefs.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPEDEFS_H 2 | #define TYPEDEFS_H 3 | 4 | /* 5 | * Copyright (c) Abraham vd Merwe 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of the author nor the names of other contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | /* 33 | * Boolean definitions 34 | */ 35 | 36 | #ifndef bool 37 | #define bool int 38 | #endif 39 | 40 | #if !defined(false) || (false != 0) 41 | #define false 0 42 | #endif 43 | 44 | #if !defined(true) || (true != 0) 45 | #define true 1 46 | #endif 47 | 48 | #if !defined(FALSE) || (FALSE != false) 49 | #define FALSE false 50 | #endif 51 | 52 | #if !defined(TRUE) || (TRUE != true) 53 | #define TRUE true 54 | #endif 55 | 56 | /* 57 | * Error flags 58 | */ 59 | 60 | #if !defined(ERR) || (ERR != -1) 61 | #define ERR -1 62 | #endif 63 | 64 | #if !defined(OK) || (OK != 0) 65 | #define OK 0 66 | #endif 67 | 68 | #endif /* #ifndef TYPEDEFS_H */ 69 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (c) Abraham vd Merwe 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of the author nor the names of other contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include "typedefs.h" 35 | 36 | /* 37 | * Initialize random number generator 38 | */ 39 | void rand_init () 40 | { 41 | #ifdef USE_RAND 42 | srand (time (NULL)); 43 | #else 44 | srandom (time (NULL)); 45 | #endif 46 | } 47 | 48 | /* 49 | * Generate a random number within range 50 | */ 51 | int rand_value (int range) 52 | { 53 | #ifdef USE_RAND 54 | return ((int) ((float) range * rand () / (RAND_MAX + 1.0))); 55 | #else 56 | return (random () % range); 57 | #endif 58 | } 59 | 60 | /* 61 | * Convert an str to long. Returns TRUE if successful, 62 | * FALSE otherwise. 63 | */ 64 | bool str2int (int *i,const char *str) 65 | { 66 | char *endptr; 67 | *i = strtol (str,&endptr,0); 68 | if (*str == '\0' || *endptr != '\0' || *i == LONG_MIN || *i == LONG_MAX || *i < INT_MIN || *i > INT_MAX) return FALSE; 69 | return TRUE; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # -*- sh -*- 3 | 4 | # Copyright (c) Abraham vd Merwe 5 | # All rights reserved. 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions 9 | # are met: 10 | # 1. Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 13 | # 2. Redistributions in binary form must reproduce the above copyright 14 | # notice, this list of conditions and the following disclaimer in the 15 | # documentation and/or other materials provided with the distribution. 16 | # 3. Neither the name of the author nor the names of other contributors 17 | # may be used to endorse or promote products derived from this software 18 | # without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | bindir = $(DESTDIR)/usr/games 32 | mandir = $(DESTDIR)/usr/share/man 33 | localstatedir = $(DESTDIR)/var/games 34 | 35 | ifeq ($(CC),) 36 | CC = gcc 37 | else 38 | ifeq ($(CC),colorgcc) 39 | ifneq ($(CROSS),) 40 | CC = gcc 41 | endif 42 | endif 43 | endif 44 | 45 | CFLAGS += -Wall 46 | CPPFLAGS = -DSCOREFILE=\"$(localstatedir)/$(PRG).scores\" #-DUSE_RAND 47 | LDLIBS = -lncurses 48 | 49 | OBJ = engine.o utils.o io.o tint.o 50 | SRC = $(OBJ:%.o=%.c) 51 | PRG = tint 52 | 53 | ########### NOTHING TO EDIT BELOW THIS ########### 54 | 55 | .PHONY: all clean do-it-all depend with-depends without-depends debian 56 | 57 | all: do-it-all 58 | 59 | ifeq (.depends,$(wildcard .depends)) 60 | include .depends 61 | do-it-all: with-depends 62 | else 63 | do-it-all: without-depends 64 | endif 65 | 66 | without-depends: depend with-depends 67 | 68 | depend: 69 | rm -f .depends 70 | set -e; for F in $(SRC); do $(CC) -MM $(CFLAGS) $(CPPFLAGS) $$F >> .depends; done 71 | 72 | with-depends: $(PRG) 73 | 74 | $(PRG): $(OBJ) 75 | $(CROSS)$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) 76 | 77 | clean: 78 | rm -f .depends *~ $(OBJ) $(PRG) {configure,build}-stamp gmon.out a.out 79 | 80 | distclean: clean 81 | 82 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | tint (0.04+nmu1) unstable; urgency=low 2 | 3 | * Non-maintainer upload. 4 | * Create /var/games during installation (Closes: #591590) 5 | * Remove score file on purge (Closes: 328472) 6 | * Apply Guido Berhoerster's patch to fix two buffer overflows 7 | (Closes: 590208) 8 | * Bring Standards-Version up-to-date (3.9.1). 9 | 10 | -- Sebastian Reichel Sun, 08 Aug 2010 17:54:30 +0200 11 | 12 | tint (0.04) unstable; urgency=low 13 | 14 | * This is the "RMLL 2010 preparation" release :-). 15 | * Assume maintainership (Closes: Bug#499263). 16 | * Add support for arrow and return keys (Closes: Bug#360910, Bug#504198, 17 | Bug#575583). 18 | * Change menu section from "Games/Tetris-like" to "Games/Blocks". 19 | * Use debhelper 7. 20 | * Do not unconditionally strip executable (Closes: Bug#438211). 21 | * Bring Standards-Version up-to-date (3.8.4). 22 | * Add option "-b " for specifying the character to use when drawing 23 | blocks. 24 | * Mention "-d" in tint.6. 25 | 26 | -- Mario Lang Wed, 23 Jun 2010 10:16:32 +0200 27 | 28 | tint (0.03b) unstable; urgency=low 29 | 30 | * Added breaks at end of switch statements to keep gcc 3+ happy 31 | (Closes: #316022) 32 | * Added missing includes to engine.c 33 | * Fixed spelling mistake in NOTES 34 | * Updated debian policy version 35 | 36 | -- Abraham van der Merwe Sun, 17 Jul 2005 13:32:17 +0200 37 | 38 | tint (0.03a) unstable; urgency=low 39 | 40 | * Applied patch with some minor tweaks from Marcello Mamino which 41 | adds a dotted background. 42 | * Applied patches from Robert Lemmen which add support for user logins as 43 | default name and an interactive mode for specifying the start level. 44 | * Show player statistics. 45 | 46 | -- Abraham van der Merwe Mon, 16 Jun 2003 23:07:37 +0200 47 | 48 | tint (0.02d) unstable; urgency=low 49 | 50 | * Install man page in correct directory (Closes: #128923) 51 | * Created a postinst program that checks for old score files 52 | before installing the default score file (Closes: #136466) 53 | * Added a menu control file (Closes: #128924) 54 | 55 | -- Abraham van der Merwe Wed, 19 Dec 2001 18:03:34 +0200 56 | 57 | tint (0.02c) unstable; urgency=low 58 | 59 | * Removed common-sense suggests from control file *g* (Closes: #123204) 60 | 61 | -- Abraham van der Merwe Wed, 19 Dec 2001 18:03:34 +0200 62 | 63 | tint (0.02b) unstable; urgency=low 64 | 65 | * Changed the name from tclassic to tint (as in TINT Is Not Tetris(tm)) 66 | * Added a build dependancy on libncurses5-dev (Closes: #124241) 67 | * Changed the location for the score file to /var/games (Closes: #124236) 68 | * Made score file sgid games (Closes: #123595) 69 | 70 | -- Abraham van der Merwe Wed, 19 Dec 2001 18:03:34 +0200 71 | 72 | tclassic (0.02a) unstable; urgency=low 73 | 74 | * Initial Release. (Closes: #122839) 75 | 76 | -- Abraham van der Merwe Fri, 7 Dec 2001 17:59:25 +0200 77 | 78 | Local variables: 79 | mode: debian-changelog 80 | End: 81 | -------------------------------------------------------------------------------- /io.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_H 2 | #define IO_H 3 | 4 | /* 5 | * Copyright (c) Abraham vd Merwe 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of the author nor the names of other contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include 33 | #include 34 | 35 | /* 36 | * Colors 37 | */ 38 | 39 | #define COLOR_BLACK 0 /* Black */ 40 | #define COLOR_RED 1 /* Red */ 41 | #define COLOR_GREEN 2 /* Green */ 42 | #define COLOR_YELLOW 3 /* Yellow */ 43 | #define COLOR_BLUE 4 /* Blue */ 44 | #define COLOR_MAGENTA 5 /* Magenta */ 45 | #define COLOR_CYAN 6 /* Cyan */ 46 | #define COLOR_WHITE 7 /* White */ 47 | 48 | /* 49 | * Attributes 50 | */ 51 | 52 | #define ATTR_OFF 0 /* All attributes off */ 53 | #define ATTR_BOLD 1 /* Bold On */ 54 | #define ATTR_DIM 2 /* Dim (Is this really in the ANSI standard? */ 55 | #define ATTR_UNDERLINE 4 /* Underline (Monochrome Display Only */ 56 | #define ATTR_BLINK 5 /* Blink On */ 57 | #define ATTR_REVERSE 7 /* Reverse Video On */ 58 | #define ATTR_INVISIBLE 8 /* Concealed On */ 59 | 60 | /* 61 | * Init & Close 62 | */ 63 | 64 | /* Initialize screen */ 65 | void io_init (); 66 | 67 | /* Restore original screen state */ 68 | void io_close (); 69 | 70 | /* 71 | * Output 72 | */ 73 | 74 | /* Set color attributes */ 75 | void out_setattr (int attr); 76 | 77 | /* Set color */ 78 | void out_setcolor (int fg,int bg); 79 | 80 | /* Move cursor to position (x,y) on the screen. Upper corner of screen is (0,0) */ 81 | void out_gotoxy (int x,int y); 82 | 83 | /* Put a character on the screen */ 84 | void out_putch (char ch); 85 | 86 | /* Write a string to the screen */ 87 | void out_printf (char *format, ...); 88 | 89 | /* Refresh screen */ 90 | void out_refresh (); 91 | 92 | /* Get the screen width */ 93 | int out_width (); 94 | 95 | /* Get the screen height */ 96 | int out_height (); 97 | 98 | /* Beep */ 99 | void out_beep (); 100 | 101 | /* 102 | * Input 103 | */ 104 | 105 | /* Read a character */ 106 | int in_getch (); 107 | 108 | /* Set keyboard timeout in microseconds */ 109 | void in_timeout (int delay); 110 | 111 | /* Empty keyboard buffer */ 112 | void in_flush (); 113 | 114 | #endif /* #ifndef IO_H */ 115 | -------------------------------------------------------------------------------- /engine.h: -------------------------------------------------------------------------------- 1 | #ifndef ENGINE_H 2 | #define ENGINE_H 3 | 4 | /* 5 | * Copyright (c) Abraham vd Merwe 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of the author nor the names of other contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "typedefs.h" /* bool */ 33 | 34 | /* 35 | * Macros 36 | */ 37 | 38 | /* Number of shapes in the game */ 39 | #define NUMSHAPES 7 40 | 41 | /* Number of blocks in each shape */ 42 | #define NUMBLOCKS 4 43 | 44 | /* Number of rows and columns in board */ 45 | #define NUMROWS 23 46 | #define NUMCOLS 13 47 | 48 | /* Wall id - Arbitrary, but shouldn't have the same value as one of the colors */ 49 | #define WALL 16 50 | 51 | /* 52 | * Type definitions 53 | */ 54 | 55 | typedef int board_t[NUMCOLS][NUMROWS]; 56 | 57 | typedef struct 58 | { 59 | int x,y; 60 | } block_t; 61 | 62 | typedef struct 63 | { 64 | int color; 65 | int type; 66 | bool flipped; 67 | block_t block[NUMBLOCKS]; 68 | } shape_t,shapes_t[NUMSHAPES]; 69 | 70 | typedef struct 71 | { 72 | int moves; 73 | int rotations; 74 | int dropcount; 75 | int efficiency; 76 | int droppedlines; 77 | int currentdroppedlines; 78 | } status_t; 79 | 80 | typedef struct engine_struct 81 | { 82 | bool shadow; /* show shadow */ 83 | int curx,cury,curx_shadow,cury_shadow; /* coordinates of current piece */ 84 | int curshape,nextshape; /* current & next shapes */ 85 | int score; /* score */ 86 | int bag_iterator; /* iterator for randomized bag */ 87 | int bag[NUMSHAPES]; /* pointer to bag of shapes */ 88 | shapes_t shapes; /* shapes */ 89 | board_t board; /* board */ 90 | status_t status; /* current status of shapes */ 91 | void (*score_function)(struct engine_struct *); /* score function */ 92 | } engine_t; 93 | 94 | typedef enum { ACTION_LEFT, ACTION_ROTATE_CLOCKWISE, ACTION_ROTATE_COUNTERCLOCKWISE, ACTION_RIGHT, ACTION_DROP, ACTION_DOWN } action_t; 95 | 96 | /* 97 | * Global variables 98 | */ 99 | 100 | extern const shapes_t SHAPES; 101 | 102 | /* 103 | * Functions 104 | */ 105 | 106 | /* 107 | * Initialize specified tetris engine 108 | */ 109 | void engine_init (engine_t *engine,void (*score_function)(engine_t *)); 110 | 111 | /* 112 | * Perform the given action on the specified tetris engine 113 | */ 114 | void engine_move (engine_t *engine,action_t action); 115 | 116 | /* 117 | * Evaluate the status of the specified tetris engine 118 | * 119 | * OUTPUT: 120 | * 1 = shape moved down one line 121 | * 0 = shape at bottom, next one released 122 | * -1 = game over (board full) 123 | */ 124 | int engine_evaluate (engine_t *engine); 125 | 126 | #endif /* #ifndef ENGINE_H */ 127 | -------------------------------------------------------------------------------- /io.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (c) Abraham vd Merwe 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of the author nor the names of other contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include /* va_list(), va_start(), va_end() */ 31 | #include /* gettimeofday() */ 32 | #include /* gettimeofday() */ 33 | 34 | #include "io.h" 35 | 36 | /* Number of colors defined in io.h */ 37 | #define NUM_COLORS 8 38 | 39 | /* Number of attributes defined in io.h */ 40 | #define NUM_ATTRS 9 41 | 42 | /* Cursor definitions */ 43 | #define CURSOR_INVISIBLE 0 44 | #define CURSOR_NORMAL 1 45 | 46 | /* Maps color definitions onto their real definitions */ 47 | static int color_map[NUM_COLORS]; 48 | 49 | /* Maps attribute definitions onto their real definitions */ 50 | static int attr_map[NUM_ATTRS]; 51 | 52 | /* Current attribute used on screen */ 53 | static int out_attr; 54 | 55 | /* Current color used on screen */ 56 | static int out_color; 57 | 58 | /* This is the timeout in microseconds */ 59 | static int in_timetotal; 60 | 61 | /* This is the amount of time left to before a timeout occurs (in microseconds) */ 62 | static int in_timeleft; 63 | 64 | /* 65 | * Init & Close 66 | */ 67 | 68 | /* Initialize screen */ 69 | void io_init () 70 | { 71 | initscr (); 72 | start_color (); 73 | curs_set (CURSOR_INVISIBLE); 74 | out_attr = A_NORMAL; 75 | out_color = COLOR_WHITE; 76 | noecho (); 77 | /* Map colors */ 78 | color_map[COLOR_BLACK] = COLOR_BLACK; 79 | color_map[COLOR_RED] = COLOR_RED; 80 | color_map[COLOR_GREEN] = COLOR_GREEN; 81 | color_map[COLOR_YELLOW] = COLOR_YELLOW; 82 | color_map[COLOR_BLUE] = COLOR_BLUE; 83 | color_map[COLOR_MAGENTA] = COLOR_MAGENTA; 84 | color_map[COLOR_CYAN] = COLOR_CYAN; 85 | color_map[COLOR_WHITE] = COLOR_WHITE; 86 | /* Map attributes */ 87 | attr_map[ATTR_OFF] = A_NORMAL; 88 | attr_map[ATTR_BOLD] = A_BOLD; 89 | attr_map[ATTR_DIM] = A_DIM; 90 | attr_map[ATTR_UNDERLINE] = A_UNDERLINE; 91 | attr_map[ATTR_BLINK] = A_BLINK; 92 | attr_map[ATTR_REVERSE] = A_REVERSE; 93 | attr_map[ATTR_INVISIBLE] = A_INVIS; 94 | 95 | keypad(stdscr, TRUE); 96 | } 97 | 98 | /* Restore original screen state */ 99 | void io_close () 100 | { 101 | echo (); 102 | attrset (A_NORMAL); 103 | clear (); 104 | curs_set (CURSOR_NORMAL); 105 | refresh (); 106 | endwin (); 107 | } 108 | 109 | /* 110 | * Output 111 | */ 112 | 113 | /* Set color attributes */ 114 | void out_setattr (int attr) 115 | { 116 | out_attr = attr_map[attr]; 117 | } 118 | 119 | /* Set color */ 120 | void out_setcolor (int fg,int bg) 121 | { 122 | out_color = (color_map[bg] << 3) + color_map[fg]; 123 | init_pair (out_color,color_map[fg],color_map[bg]); 124 | attrset (COLOR_PAIR (out_color) | out_attr); 125 | } 126 | 127 | /* Move cursor to position (x,y) on the screen. Upper corner of screen is (0,0) */ 128 | void out_gotoxy (int x,int y) 129 | { 130 | move (y,x); 131 | } 132 | 133 | /* Put a character on the screen */ 134 | void out_putch (char ch) 135 | { 136 | addch (ch); 137 | } 138 | 139 | /* Put a unicode character on the screen */ 140 | /* Put a string on the screen */ 141 | void out_printf (char *format, ...) 142 | { 143 | va_list ap; 144 | va_start (ap,format); 145 | vw_printw (stdscr,format,ap); 146 | va_end (ap); 147 | } 148 | 149 | /* Refresh screen */ 150 | void out_refresh () 151 | { 152 | refresh (); 153 | } 154 | 155 | /* Get the screen width */ 156 | int out_width () 157 | { 158 | return COLS; 159 | } 160 | 161 | /* Get the screen height */ 162 | int out_height () 163 | { 164 | return LINES; 165 | } 166 | 167 | /* Beep */ 168 | void out_beep () 169 | { 170 | beep (); 171 | } 172 | 173 | /* 174 | * Input 175 | */ 176 | 177 | /* Read a character. Please note that you MUST call in_timeout() before in_getch() */ 178 | int in_getch () 179 | { 180 | struct timeval starttv,endtv; 181 | int ch; 182 | timeout (in_timeleft / 1000); 183 | gettimeofday (&starttv,NULL); 184 | ch = getch (); 185 | gettimeofday (&endtv,NULL); 186 | /* Timeout? */ 187 | if (ch == ERR) 188 | in_timeleft = in_timetotal; 189 | /* No? Then calculate time left */ 190 | else 191 | { 192 | endtv.tv_sec -= starttv.tv_sec; 193 | endtv.tv_usec -= starttv.tv_usec; 194 | if (endtv.tv_usec < 0) 195 | { 196 | endtv.tv_usec += 1000000; 197 | endtv.tv_sec--; 198 | } 199 | in_timeleft -= endtv.tv_usec; 200 | if (in_timeleft <= 0) in_timeleft = in_timetotal; 201 | } 202 | return ch; 203 | } 204 | 205 | /* Set keyboard timeout in microseconds */ 206 | void in_timeout (int delay) 207 | { 208 | /* ncurses timeout() function works with milliseconds, not microseconds */ 209 | in_timetotal = in_timeleft = delay; 210 | } 211 | 212 | /* Empty keyboard buffer */ 213 | void in_flush () 214 | { 215 | flushinp (); 216 | } 217 | 218 | -------------------------------------------------------------------------------- /engine.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (c) Abraham vd Merwe 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of the author nor the names of other contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | #include 32 | 33 | #include "typedefs.h" 34 | #include "utils.h" 35 | #include "io.h" 36 | #include "engine.h" 37 | 38 | /* 39 | * Global variables 40 | */ 41 | 42 | const shapes_t SHAPES = 43 | { 44 | { COLOR_CYAN, 0, FALSE, { { 1, 0 }, { 0, 0 }, { 0, -1 }, { -1, -1 } } }, 45 | { COLOR_GREEN, 1, FALSE, { { 1, -1 }, { 0, -1 }, { 0, 0 }, { -1, 0 } } }, 46 | { COLOR_YELLOW, 2, FALSE, { { -1, 0 }, { 0, 0 }, { 1, 0 }, { 0, 1 } } }, 47 | { COLOR_BLUE, 3, FALSE, { { -1, -1 }, { 0, -1 }, { -1, 0 }, { 0, 0 } } }, 48 | { COLOR_MAGENTA, 4, FALSE, { { -1, 1 }, { -1, 0 }, { 0, 0 }, { 1, 0 } } }, 49 | { COLOR_WHITE, 5, FALSE, { { 1, 1 }, { 1, 0 }, { 0, 0 }, { -1, 0 } } }, 50 | { COLOR_RED, 6, FALSE, { { -1, 0 }, { 0, 0 }, { 1, 0 }, { 2, 0 } } } 51 | }; 52 | 53 | /* 54 | * Functions 55 | */ 56 | 57 | /* This rotates a shape */ 58 | static void real_rotate (shape_t *shape,bool clockwise) 59 | { 60 | int i,tmp; 61 | if (clockwise) 62 | { 63 | for (i = 0; i < NUMBLOCKS; i++) 64 | { 65 | tmp = shape->block[i].x; 66 | shape->block[i].x = -shape->block[i].y; 67 | shape->block[i].y = tmp; 68 | } 69 | } 70 | else 71 | { 72 | for (i = 0; i < NUMBLOCKS; i++) 73 | { 74 | tmp = shape->block[i].x; 75 | shape->block[i].x = shape->block[i].y; 76 | shape->block[i].y = -tmp; 77 | } 78 | } 79 | } 80 | 81 | /* Rotate shapes the way tetris likes it (= not mathematically correct) */ 82 | static void fake_rotate (shape_t *shape,bool clockwise) 83 | { 84 | switch (shape->type) 85 | { 86 | case 0: /* Just rotate this one anti-clockwise and clockwise */ 87 | if (shape->flipped) real_rotate (shape,TRUE); else real_rotate (shape,FALSE); 88 | shape->flipped = !shape->flipped; 89 | break; 90 | case 1: /* Just rotate these two clockwise and anti-clockwise */ 91 | case 6: 92 | if (shape->flipped) real_rotate (shape,FALSE); else real_rotate (shape,TRUE); 93 | shape->flipped = !shape->flipped; 94 | break; 95 | case 2: /* Rotate these three according to supplied direction */ 96 | case 4: 97 | case 5: 98 | real_rotate (shape,clockwise); 99 | break; 100 | case 3: /* This one is not rotated at all */ 101 | break; 102 | } 103 | } 104 | 105 | /* Draw a shape on the board */ 106 | static void drawshape (board_t board,shape_t *shape,int x,int y) 107 | { 108 | int i; 109 | for (i = 0; i < NUMBLOCKS; i++) board[x + shape->block[i].x][y + shape->block[i].y] = shape->color; 110 | } 111 | 112 | /* Erase a shape from the board */ 113 | static void eraseshape (board_t board,shape_t *shape,int x,int y) 114 | { 115 | int i; 116 | for (i = 0; i < NUMBLOCKS; i++) board[x + shape->block[i].x][y + shape->block[i].y] = COLOR_BLACK; 117 | } 118 | 119 | /* Check if shape is allowed to be in this position */ 120 | static bool allowed (board_t board,shape_t *shape,int x,int y) 121 | { 122 | int i,occupied = FALSE; 123 | for (i = 0; i < NUMBLOCKS; i++) if (board[x + shape->block[i].x][y + shape->block[i].y]) occupied = TRUE; 124 | return (!occupied); 125 | } 126 | 127 | /* Set y coordinate of shadow */ 128 | static void place_shadow_to_bottom (board_t board,shape_t *shape,int x_shadow,int *y_shadow,int y) { 129 | while (allowed(board,shape,x_shadow,y+1)) y++; 130 | *y_shadow = y; 131 | } 132 | 133 | /* Move the shape left if possible */ 134 | static bool shape_left (engine_t *engine) 135 | { 136 | board_t *board = &engine->board; 137 | shape_t *shape = &engine->shapes[engine->curshape]; 138 | bool result = FALSE; 139 | eraseshape (*board,shape,engine->curx,engine->cury); 140 | if (engine->shadow) eraseshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 141 | if (allowed (*board,shape,engine->curx - 1,engine->cury)) 142 | { 143 | engine->curx--; 144 | result = TRUE; 145 | if (engine->shadow) 146 | { 147 | engine->curx_shadow--; 148 | place_shadow_to_bottom(*board,shape,engine->curx_shadow,&engine->cury_shadow,engine->cury); 149 | } 150 | } 151 | if (engine->shadow) drawshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 152 | drawshape (*board,shape,engine->curx,engine->cury); 153 | return result; 154 | } 155 | 156 | /* Move the shape right if possible */ 157 | static bool shape_right (engine_t *engine) 158 | { 159 | board_t *board = &engine->board; 160 | shape_t *shape = &engine->shapes[engine->curshape]; 161 | bool result = FALSE; 162 | eraseshape (*board,shape,engine->curx,engine->cury); 163 | if (engine->shadow) eraseshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 164 | if (allowed (*board,shape,engine->curx + 1,engine->cury)) 165 | { 166 | engine->curx++; 167 | result = TRUE; 168 | if (engine->shadow) 169 | { 170 | engine->curx_shadow++; 171 | place_shadow_to_bottom(*board,shape,engine->curx_shadow,&engine->cury_shadow,engine->cury); 172 | } 173 | } 174 | if (engine->shadow) drawshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 175 | drawshape (*board,shape,engine->curx,engine->cury); 176 | return result; 177 | } 178 | 179 | /* Rotate the shape if possible */ 180 | static bool shape_rotate (engine_t *engine,bool clockwise) 181 | { 182 | board_t *board = &engine->board; 183 | shape_t *shape = &engine->shapes[engine->curshape]; 184 | bool result = FALSE; 185 | shape_t test; 186 | eraseshape (*board,shape,engine->curx,engine->cury); 187 | if (engine->shadow) eraseshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 188 | memcpy (&test,shape,sizeof (shape_t)); 189 | fake_rotate (&test,clockwise); 190 | if (allowed (*board,&test,engine->curx,engine->cury)) 191 | { 192 | memcpy (shape,&test,sizeof (shape_t)); 193 | result = TRUE; 194 | if (engine->shadow) place_shadow_to_bottom(*board,shape,engine->curx_shadow,&engine->cury_shadow,engine->cury); 195 | } 196 | if (engine->shadow) drawshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 197 | drawshape (*board,shape,engine->curx,engine->cury); 198 | return result; 199 | } 200 | 201 | /* Move the shape one row down if possible */ 202 | static bool shape_down (engine_t *engine) 203 | { 204 | board_t *board = &engine->board; 205 | shape_t *shape = &engine->shapes[engine->curshape]; 206 | bool result = FALSE; 207 | eraseshape (*board,shape,engine->curx,engine->cury); 208 | if (engine->shadow) eraseshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 209 | if (allowed (*board,shape,engine->curx,engine->cury + 1)) 210 | { 211 | engine->cury++; 212 | result = TRUE; 213 | if (engine->shadow) place_shadow_to_bottom(*board,shape,engine->curx_shadow,&engine->cury_shadow,engine->cury); 214 | } 215 | if (engine->shadow) drawshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 216 | drawshape (*board,shape,engine->curx,engine->cury); 217 | return result; 218 | } 219 | 220 | /* Check if shape can move down (= in the air) or not (= at the bottom */ 221 | /* of the board or on top of one of the resting shapes) */ 222 | static bool shape_bottom (engine_t *engine) 223 | { 224 | board_t *board = &engine->board; 225 | shape_t *shape = &engine->shapes[engine->curshape]; 226 | bool result = FALSE; 227 | eraseshape (*board,shape,engine->curx,engine->cury); 228 | if (engine->shadow) eraseshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 229 | result = !allowed (*board,shape,engine->curx,engine->cury + 1); 230 | if (engine->shadow) drawshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 231 | drawshape (*board,shape,engine->curx,engine->cury); 232 | return result; 233 | } 234 | 235 | /* Drop the shape until it comes to rest on the bottom of the board or */ 236 | /* on top of a resting shape */ 237 | static int shape_drop (engine_t *engine) 238 | { 239 | board_t *board = &engine->board; 240 | shape_t *shape = &engine->shapes[engine->curshape]; 241 | eraseshape (*board,shape,engine->curx,engine->cury); 242 | int droppedlines = 0; 243 | 244 | if (engine->shadow) { 245 | drawshape (*board,shape,engine->curx_shadow,engine->cury_shadow); 246 | droppedlines = engine->cury_shadow - engine->cury; 247 | engine->cury = engine->cury_shadow; 248 | return droppedlines; 249 | } 250 | 251 | while (allowed (*board,shape,engine->curx,engine->cury + 1)) 252 | { 253 | engine->cury++; 254 | droppedlines++; 255 | } 256 | drawshape (*board,shape,engine->curx,engine->cury); 257 | return droppedlines; 258 | } 259 | 260 | /* This removes all the rows on the board that is completely filled with blocks */ 261 | static int droplines (board_t board) 262 | { 263 | int i,x,y,ny,status,droppedlines; 264 | board_t newboard; 265 | /* initialize new board */ 266 | memset (newboard,0,sizeof (board_t)); 267 | for (i = 0; i < NUMCOLS; i++) newboard[i][NUMROWS - 1] = newboard[i][NUMROWS - 2] = WALL; 268 | for (i = 0; i < NUMROWS; i++) newboard[0][i] = newboard[NUMCOLS - 1][i] = newboard[NUMCOLS - 2][i] = WALL; 269 | /* ... */ 270 | ny = NUMROWS - 3; 271 | droppedlines = 0; 272 | for (y = NUMROWS - 3; y > 0; y--) 273 | { 274 | status = 0; 275 | for (x = 1; x < NUMCOLS - 2; x++) if (board[x][y]) status++; 276 | if (status < NUMCOLS - 3) 277 | { 278 | for (x = 1; x < NUMCOLS - 2; x++) newboard[x][ny] = board[x][y]; 279 | ny--; 280 | } 281 | else droppedlines++; 282 | } 283 | memcpy (board,newboard,sizeof (board_t)); 284 | return droppedlines; 285 | } 286 | 287 | /* shuffle int array */ 288 | void shuffle (int *array, size_t n) 289 | { 290 | size_t i; 291 | for (i = 0; i < n - 1; i++) 292 | { 293 | int range = (int)(n - i); 294 | size_t j = i + rand_value(range); 295 | int t = array[j]; 296 | array[j] = array[i]; 297 | array[i] = t; 298 | } 299 | } 300 | 301 | /* 302 | * Initialize specified tetris engine 303 | */ 304 | void engine_init (engine_t *engine,void (*score_function)(engine_t *)) 305 | { 306 | int i; 307 | engine->shadow = FALSE; 308 | engine->score_function = score_function; 309 | /* intialize values */ 310 | engine->curx = 5; 311 | engine->cury = 1; 312 | engine->curx_shadow = 5; 313 | engine->cury_shadow = 1; 314 | engine->bag_iterator = 0; 315 | /* create and randomize bag */ 316 | for (int j = 0; j < NUMSHAPES; j++) engine->bag[j] = j; 317 | shuffle (engine->bag,NUMSHAPES); 318 | engine->curshape = engine->bag[engine->bag_iterator%NUMSHAPES]; 319 | engine->nextshape = engine->bag[(engine->bag_iterator+1)%NUMSHAPES]; 320 | engine->bag_iterator++; 321 | engine->score = 0; 322 | engine->status.moves = engine->status.rotations = engine->status.dropcount = engine->status.efficiency = engine->status.droppedlines = 0; 323 | /* initialize shapes */ 324 | memcpy (engine->shapes,SHAPES,sizeof (shapes_t)); 325 | /* initialize board */ 326 | memset (engine->board,0,sizeof (board_t)); 327 | for (i = 0; i < NUMCOLS; i++) engine->board[i][NUMROWS - 1] = engine->board[i][NUMROWS - 2] = WALL; 328 | for (i = 0; i < NUMROWS; i++) engine->board[0][i] = engine->board[NUMCOLS - 1][i] = engine->board[NUMCOLS - 2][i] = WALL; 329 | } 330 | 331 | /* 332 | * Perform the given action on the specified tetris engine 333 | */ 334 | void engine_move (engine_t *engine,action_t action) 335 | { 336 | switch (action) 337 | { 338 | /* move shape to the left if possible */ 339 | case ACTION_LEFT: 340 | if (shape_left (engine)) engine->status.moves++; 341 | break; 342 | /* rotate shape clockwise if possible */ 343 | case ACTION_ROTATE_CLOCKWISE: 344 | if (shape_rotate (engine, true)) engine->status.rotations++; 345 | break; 346 | /* rotate shape counterclockwise if possible */ 347 | case ACTION_ROTATE_COUNTERCLOCKWISE: 348 | if (shape_rotate (engine, false)) engine->status.rotations++; 349 | break; 350 | /* move shape to the right if possible */ 351 | case ACTION_RIGHT: 352 | if (shape_right (engine)) engine->status.moves++; 353 | break; 354 | /* move shape to the down if possible */ 355 | case ACTION_DOWN: 356 | if (shape_down (engine)) engine->status.moves++; 357 | break; 358 | /* drop shape to the bottom */ 359 | case ACTION_DROP: 360 | engine->status.dropcount += shape_drop (engine); 361 | } 362 | } 363 | 364 | /* 365 | * Evaluate the status of the specified tetris engine 366 | * 367 | * OUTPUT: 368 | * 1 = shape moved down one line 369 | * 0 = shape at bottom, next one released 370 | * -1 = game over (board full) 371 | */ 372 | int engine_evaluate (engine_t *engine) 373 | { 374 | if (shape_bottom (engine)) 375 | { 376 | /* update status information */ 377 | int dropped_lines = droplines(engine->board); 378 | engine->status.droppedlines += dropped_lines; 379 | engine->status.currentdroppedlines = dropped_lines; 380 | /* increase score */ 381 | engine->score_function (engine); 382 | engine->curx -= 5; 383 | engine->curx = abs (engine->curx); 384 | engine->curx_shadow -= 5; 385 | engine->curx_shadow = abs (engine->curx_shadow); 386 | engine->status.rotations = 4 - engine->status.rotations; 387 | engine->status.rotations = engine->status.rotations > 0 ? 0 : engine->status.rotations; 388 | engine->status.efficiency += engine->status.dropcount + engine->status.rotations + (engine->curx - engine->status.moves); 389 | engine->status.efficiency >>= 1; 390 | engine->status.dropcount = engine->status.rotations = engine->status.moves = 0; 391 | /* intialize values */ 392 | engine->curx = 5; 393 | engine->cury = 1; 394 | engine->curx_shadow = 5; 395 | engine->cury_shadow = 1; 396 | engine->curshape = engine->bag[engine->bag_iterator%NUMSHAPES]; 397 | /* shuffle bag before first item in bag would be reused */ 398 | if ((engine->bag_iterator+1) % NUMSHAPES == 0) shuffle(engine->bag, NUMSHAPES); 399 | engine->nextshape = engine->bag[(engine->bag_iterator+1)%NUMSHAPES]; 400 | engine->bag_iterator++; 401 | /* initialize shapes */ 402 | memcpy (engine->shapes,SHAPES,sizeof (shapes_t)); 403 | /* return games status */ 404 | return allowed (engine->board,&engine->shapes[engine->curshape],engine->curx,engine->cury) ? 0 : -1; 405 | } 406 | shape_down (engine); 407 | return 1; 408 | } 409 | -------------------------------------------------------------------------------- /tint.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (c) Abraham vd Merwe 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of the author nor the names of other contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "typedefs.h" 39 | #include "utils.h" 40 | #include "io.h" 41 | #include "config.h" 42 | #include "engine.h" 43 | 44 | /* 45 | * Macros 46 | */ 47 | 48 | /* Upper left corner of board */ 49 | #define XTOP ((out_width () - NUMROWS - 3) >> 1) 50 | #define YTOP ((out_height () - NUMCOLS - 9) >> 1) 51 | 52 | /* Maximum digits in a number (i.e. number of digits in score, */ 53 | /* number of blocks, etc. should not exceed this value */ 54 | #define MAXDIGITS 5 55 | 56 | /* Number of levels in the game */ 57 | #define MINLEVEL 1 58 | #define MAXLEVEL 9 59 | 60 | /* This calculates the time allowed to move a shape, before it is moved a row down */ 61 | #define DELAY (1000000 / (level + 2)) 62 | 63 | /* The score is multiplied by this to avoid losing precision */ 64 | #define SCOREFACTOR 2 65 | 66 | /* This calculates the stored score value */ 67 | #define SCOREVAL(x) (SCOREFACTOR * (x)) 68 | 69 | /* This calculates the real (displayed) value of the score */ 70 | #define GETSCORE(score) ((score) / SCOREFACTOR) 71 | 72 | static bool shownext; 73 | static bool dottedlines; 74 | static bool shadow; 75 | static int level = MINLEVEL - 1,shapecount[NUMSHAPES]; 76 | static char blockchar = ' '; 77 | 78 | /* 79 | * Functions 80 | */ 81 | 82 | /* This function is responsible for increasing the score appropriately whenever 83 | * a block collides at the bottom of the screen (or the top of the heap */ 84 | static void score_function (engine_t *engine) 85 | { 86 | int score = SCOREVAL (level * (engine->status.dropcount + 1)); 87 | score += SCOREVAL ((level + 10) * engine->status.currentdroppedlines * engine->status.currentdroppedlines); 88 | 89 | if (shownext) score /= 2; 90 | if (dottedlines) score /= 2; 91 | 92 | engine->score += score; 93 | } 94 | 95 | /* Draw the board on the screen */ 96 | static void drawboard (board_t board) 97 | { 98 | int x,y; 99 | out_setattr (ATTR_OFF); 100 | for (y = 1; y < NUMROWS - 1; y++) for (x = 0; x < NUMCOLS - 1; x++) 101 | { 102 | out_gotoxy (XTOP + x * 2,YTOP + y); 103 | switch (board[x][y]) 104 | { 105 | /* Wall */ 106 | case WALL: 107 | out_setattr (ATTR_BOLD); 108 | out_setcolor (COLOR_BLUE,COLOR_BLACK); 109 | out_putch ('<'); 110 | out_putch ('>'); 111 | out_setattr (ATTR_OFF); 112 | break; 113 | /* Background */ 114 | case 0: 115 | if (dottedlines) 116 | { 117 | out_setcolor (COLOR_BLUE,COLOR_BLACK); 118 | out_putch ('.'); 119 | out_putch (' '); 120 | } 121 | else 122 | { 123 | out_setcolor (COLOR_BLACK,COLOR_BLACK); 124 | out_putch (' '); 125 | out_putch (' '); 126 | } 127 | break; 128 | /* Block */ 129 | default: 130 | out_setcolor (COLOR_BLACK,board[x][y]); 131 | out_putch (blockchar); 132 | out_putch (blockchar); 133 | } 134 | } 135 | out_setattr (ATTR_OFF); 136 | } 137 | 138 | /* Show the next piece on the screen */ 139 | static void drawnext (int shapenum,int x,int y) 140 | { 141 | int i; 142 | block_t ofs[NUMSHAPES] = 143 | { { 1, 0 }, { 1, 0 }, { 1, -1 }, { 2, 0 }, { 1, -1 }, { 1, -1 }, { 0, -1 } }; 144 | out_setcolor (COLOR_BLACK,COLOR_BLACK); 145 | for (i = y - 2; i < y + 2; i++) 146 | { 147 | out_gotoxy (x - 2,i); 148 | out_printf (" "); 149 | } 150 | out_setcolor (COLOR_BLACK,SHAPES[shapenum].color); 151 | for (i = 0; i < NUMBLOCKS; i++) 152 | { 153 | out_gotoxy (x + SHAPES[shapenum].block[i].x * 2 + ofs[shapenum].x, 154 | y + SHAPES[shapenum].block[i].y + ofs[shapenum].y); 155 | out_putch (' '); 156 | out_putch (' '); 157 | } 158 | } 159 | 160 | /* Draw the background */ 161 | static void drawbackground () 162 | { 163 | out_setattr (ATTR_OFF); 164 | out_setcolor (COLOR_WHITE,COLOR_BLACK); 165 | out_gotoxy (4,YTOP + 7); out_printf ("H E L P"); 166 | out_gotoxy (1,YTOP + 9); out_printf ("p: Pause"); 167 | out_gotoxy (1,YTOP + 10); out_printf ("j: Left"); 168 | out_gotoxy (1,YTOP + 11); out_printf ("l: Right"); 169 | out_gotoxy (1,YTOP + 12); out_printf ("K: Rotate (clockwise)"); 170 | out_gotoxy (1,YTOP + 13); out_printf ("k: Rotate (counterclockwise)"); 171 | out_gotoxy (1,YTOP + 14); out_printf ("s: Draw next"); 172 | out_gotoxy (1,YTOP + 15); out_printf ("d: Toggle lines"); 173 | out_gotoxy (1,YTOP + 16); out_printf ("a: Speed up"); 174 | out_gotoxy (1,YTOP + 17); out_printf ("q: Quit"); 175 | out_gotoxy (2,YTOP + 18); out_printf ("SPACE: Drop"); 176 | out_gotoxy (3,YTOP + 20); out_printf ("Next:"); 177 | } 178 | 179 | static int getsum () 180 | { 181 | int i,sum = 0; 182 | for (i = 0; i < NUMSHAPES; i++) sum += shapecount[i]; 183 | return (sum); 184 | } 185 | 186 | /* This show the current status of the game */ 187 | static void showstatus (engine_t *engine) 188 | { 189 | static const int shapenum[NUMSHAPES] = { 4, 6, 5, 1, 0, 3, 2 }; 190 | char tmp[MAXDIGITS + 1]; 191 | int i,sum = getsum (); 192 | out_setattr (ATTR_OFF); 193 | out_setcolor (COLOR_WHITE,COLOR_BLACK); 194 | out_gotoxy (1,YTOP + 1); out_printf ("Your level: %d",level); 195 | out_gotoxy (1,YTOP + 2); out_printf ("Full lines: %d",engine->status.droppedlines); 196 | out_gotoxy (2,YTOP + 4); out_printf ("Score"); 197 | out_setattr (ATTR_BOLD); 198 | out_setcolor (COLOR_YELLOW,COLOR_BLACK); 199 | out_printf (" %d",GETSCORE (engine->score)); 200 | if (shownext) drawnext (engine->nextshape,3,YTOP + 22); 201 | out_setattr (ATTR_OFF); 202 | out_setcolor (COLOR_WHITE,COLOR_BLACK); 203 | out_gotoxy (out_width () - MAXDIGITS - 12,YTOP + 1); 204 | out_printf ("STATISTICS"); 205 | out_setcolor (COLOR_BLACK,COLOR_MAGENTA); 206 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 3); 207 | out_printf (" "); 208 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 4); 209 | out_printf (" "); 210 | out_setcolor (COLOR_MAGENTA,COLOR_BLACK); 211 | out_gotoxy (out_width () - MAXDIGITS - 3,YTOP + 3); 212 | out_putch ('-'); 213 | snprintf (tmp,MAXDIGITS + 1,"%d",shapecount[shapenum[0]]); 214 | out_gotoxy (out_width () - strlen (tmp) - 1,YTOP + 3); 215 | out_printf ("%s",tmp); 216 | out_setcolor (COLOR_BLACK,COLOR_RED); 217 | out_gotoxy (out_width () - MAXDIGITS - 13,YTOP + 5); 218 | out_printf (" "); 219 | out_setcolor (COLOR_RED,COLOR_BLACK); 220 | out_gotoxy (out_width () - MAXDIGITS - 3,YTOP + 5); 221 | out_putch ('-'); 222 | snprintf (tmp,MAXDIGITS + 1,"%d",shapecount[shapenum[1]]); 223 | out_gotoxy (out_width () - strlen (tmp) - 1,YTOP + 5); 224 | out_printf ("%s",tmp); 225 | out_setcolor (COLOR_BLACK,COLOR_WHITE); 226 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 7); 227 | out_printf (" "); 228 | out_gotoxy (out_width () - MAXDIGITS - 13,YTOP + 8); 229 | out_printf (" "); 230 | out_setcolor (COLOR_WHITE,COLOR_BLACK); 231 | out_gotoxy (out_width () - MAXDIGITS - 3,YTOP + 7); 232 | out_putch ('-'); 233 | snprintf (tmp,MAXDIGITS + 1,"%d",shapecount[shapenum[2]]); 234 | out_gotoxy (out_width () - strlen (tmp) - 1,YTOP + 7); 235 | out_printf ("%s",tmp); 236 | out_setcolor (COLOR_BLACK,COLOR_GREEN); 237 | out_gotoxy (out_width () - MAXDIGITS - 9,YTOP + 9); 238 | out_printf (" "); 239 | out_gotoxy (out_width () - MAXDIGITS - 11,YTOP + 10); 240 | out_printf (" "); 241 | out_setcolor (COLOR_GREEN,COLOR_BLACK); 242 | out_gotoxy (out_width () - MAXDIGITS - 3,YTOP + 9); 243 | out_putch ('-'); 244 | snprintf (tmp,MAXDIGITS + 1,"%d",shapecount[shapenum[3]]); 245 | out_gotoxy (out_width () - strlen (tmp) - 1,YTOP + 9); 246 | out_printf ("%s",tmp); 247 | out_setcolor (COLOR_BLACK,COLOR_CYAN); 248 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 11); 249 | out_printf (" "); 250 | out_gotoxy (out_width () - MAXDIGITS - 15,YTOP + 12); 251 | out_printf (" "); 252 | out_setcolor (COLOR_CYAN,COLOR_BLACK); 253 | out_gotoxy (out_width () - MAXDIGITS - 3,YTOP + 11); 254 | out_putch ('-'); 255 | snprintf (tmp,MAXDIGITS + 1,"%d",shapecount[shapenum[4]]); 256 | out_gotoxy (out_width () - strlen (tmp) - 1,YTOP + 11); 257 | out_printf ("%s",tmp); 258 | out_setcolor (COLOR_BLACK,COLOR_BLUE); 259 | out_gotoxy (out_width () - MAXDIGITS - 9,YTOP + 13); 260 | out_printf (" "); 261 | out_gotoxy (out_width () - MAXDIGITS - 9,YTOP + 14); 262 | out_printf (" "); 263 | out_setcolor (COLOR_BLUE,COLOR_BLACK); 264 | out_gotoxy (out_width () - MAXDIGITS - 3,YTOP + 13); 265 | out_putch ('-'); 266 | snprintf (tmp,MAXDIGITS + 1,"%d",shapecount[shapenum[5]]); 267 | out_gotoxy (out_width () - strlen (tmp) - 1,YTOP + 13); 268 | out_printf ("%s",tmp); 269 | out_setattr (ATTR_OFF); 270 | out_setcolor (COLOR_BLACK,COLOR_YELLOW); 271 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 15); 272 | out_printf (" "); 273 | out_gotoxy (out_width () - MAXDIGITS - 15,YTOP + 16); 274 | out_printf (" "); 275 | out_setcolor (COLOR_YELLOW,COLOR_BLACK); 276 | out_gotoxy (out_width () - MAXDIGITS - 3,YTOP + 15); 277 | out_putch ('-'); 278 | snprintf (tmp,MAXDIGITS + 1,"%d",shapecount[shapenum[6]]); 279 | out_gotoxy (out_width () - strlen (tmp) - 1,YTOP + 15); 280 | out_printf ("%s",tmp); 281 | out_setcolor (COLOR_WHITE,COLOR_BLACK); 282 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 17); 283 | for (i = 0; i < MAXDIGITS + 16; i++) out_putch ('-'); 284 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 18); 285 | out_printf ("Sum :"); 286 | snprintf (tmp,MAXDIGITS + 1,"%d",sum); 287 | out_gotoxy (out_width () - strlen (tmp) - 1,YTOP + 18); 288 | out_printf ("%s",tmp); 289 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 20); 290 | for (i = 0; i < MAXDIGITS + 16; i++) out_putch (' '); 291 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 20); 292 | out_printf ("Score ratio :"); 293 | snprintf (tmp,MAXDIGITS + 1,"%d",GETSCORE (engine->score) / sum); 294 | out_gotoxy (out_width () - strlen (tmp) - 1,YTOP + 20); 295 | out_printf ("%s",tmp); 296 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 21); 297 | for (i = 0; i < MAXDIGITS + 16; i++) out_putch (' '); 298 | out_gotoxy (out_width () - MAXDIGITS - 17,YTOP + 21); 299 | out_printf ("Efficiency :"); 300 | snprintf (tmp,MAXDIGITS + 1,"%d",engine->status.efficiency); 301 | out_gotoxy (out_width () - strlen (tmp) - 1,YTOP + 21); 302 | out_printf ("%s",tmp); 303 | } 304 | 305 | /***************************************************************************/ 306 | /***************************************************************************/ 307 | /***************************************************************************/ 308 | 309 | /* Header for scorefile */ 310 | #define SCORE_HEADER "Tint 0.02b (c) Abraham vd Merwe - Scores" 311 | 312 | /* Header for score title */ 313 | static const char scoretitle[] = "\n\t TINT HIGH SCORES\n\n\tRank Score Name\n\n"; 314 | 315 | /* Length of a player's name */ 316 | #define NAMELEN 20 317 | 318 | /* Number of scores allowed in highscore list */ 319 | #define NUMSCORES 10 320 | 321 | typedef struct 322 | { 323 | char name[NAMELEN]; 324 | int score; 325 | time_t timestamp; 326 | } score_t; 327 | 328 | static void getname (char *name) 329 | { 330 | struct passwd *pw = getpwuid (geteuid ()); 331 | 332 | fprintf (stderr,"Congratulations! You have a new high score.\n"); 333 | fprintf (stderr,"Enter your name [%s]: ",pw != NULL ? pw->pw_name : ""); 334 | 335 | fgets (name,NAMELEN - 1,stdin); 336 | name[strlen (name) - 1] = '\0'; 337 | 338 | if (!strlen (name) && pw != NULL) 339 | { 340 | strncpy (name,pw->pw_name,NAMELEN); 341 | name[NAMELEN - 1] = '\0'; 342 | } 343 | } 344 | 345 | static void err1 () 346 | { 347 | fprintf (stderr,"Error creating %s\n",scorefile); 348 | exit (EXIT_FAILURE); 349 | } 350 | 351 | static void err2 () 352 | { 353 | fprintf (stderr,"Error writing to %s\n",scorefile); 354 | exit (EXIT_FAILURE); 355 | } 356 | 357 | void showplayerstats (engine_t *engine) 358 | { 359 | fprintf (stderr, 360 | "\n\t PLAYER STATISTICS\n\n\t" 361 | "Score %11d\n\t" 362 | "Efficiency %11d\n\t" 363 | "Score ratio %11d\n", 364 | GETSCORE (engine->score),engine->status.efficiency,GETSCORE (engine->score) / getsum ()); 365 | } 366 | 367 | static void createscores (int score) 368 | { 369 | FILE *handle; 370 | int i,j; 371 | score_t scores[NUMSCORES]; 372 | char header[strlen (SCORE_HEADER)+1]; 373 | if (score == 0) return; /* No need saving this */ 374 | for (i = 1; i < NUMSCORES; i++) 375 | { 376 | strcpy (scores[i].name,"None"); 377 | scores[i].score = -1; 378 | scores[i].timestamp = 0; 379 | } 380 | getname (scores[0].name); 381 | scores[0].score = score; 382 | scores[0].timestamp = time (NULL); 383 | if ((handle = fopen (scorefile,"w")) == NULL) err1 (); 384 | strcpy (header,SCORE_HEADER); 385 | i = fwrite (header,strlen (SCORE_HEADER),1,handle); 386 | if (i != 1) err2 (); 387 | for (i = 0; i < NUMSCORES; i++) 388 | { 389 | j = fwrite (scores[i].name,strlen (scores[i].name) + 1,1,handle); 390 | if (j != 1) err2 (); 391 | j = fwrite (&(scores[i].score),sizeof (int),1,handle); 392 | if (j != 1) err2 (); 393 | j = fwrite (&(scores[i].timestamp),sizeof (time_t),1,handle); 394 | if (j != 1) err2 (); 395 | } 396 | fclose (handle); 397 | 398 | fprintf (stderr,"%s",scoretitle); 399 | fprintf (stderr,"\t 1* %7d %s\n\n",score,scores[0].name); 400 | } 401 | 402 | static int cmpscores (const void *a,const void *b) 403 | { 404 | int result; 405 | result = (int) ((score_t *) a)->score - (int) ((score_t *) b)->score; 406 | /* a < b */ 407 | if (result < 0) return 1; 408 | /* a > b */ 409 | if (result > 0) return -1; 410 | /* a = b */ 411 | result = (time_t) ((score_t *) a)->timestamp - (time_t) ((score_t *) b)->timestamp; 412 | /* a is older */ 413 | if (result < 0) return -1; 414 | /* b is older */ 415 | if (result > 0) return 1; 416 | /* timestamps is equal */ 417 | return 0; 418 | } 419 | 420 | static void savescores (int score) 421 | { 422 | FILE *handle; 423 | int i,j,ch; 424 | score_t scores[NUMSCORES]; 425 | char header[strlen (SCORE_HEADER)+1]; 426 | time_t tmp = 0; 427 | if ((handle = fopen (scorefile,"r")) == NULL) 428 | { 429 | createscores (score); 430 | return; 431 | } 432 | i = fread (header,strlen (SCORE_HEADER),1,handle); 433 | if ((i != 1) || (strncmp (SCORE_HEADER,header,strlen (SCORE_HEADER)) != 0)) 434 | { 435 | createscores (score); 436 | return; 437 | } 438 | for (i = 0; i < NUMSCORES; i++) 439 | { 440 | j = 0; 441 | while ((ch = fgetc (handle)) != '\0') 442 | { 443 | if ((ch == EOF) || (j >= NAMELEN - 2)) 444 | { 445 | createscores (score); 446 | return; 447 | } 448 | scores[i].name[j++] = (char) ch; 449 | } 450 | scores[i].name[j] = '\0'; 451 | j = fread (&(scores[i].score),sizeof (int),1,handle); 452 | if (j != 1) 453 | { 454 | createscores (score); 455 | return; 456 | } 457 | j = fread (&(scores[i].timestamp),sizeof (time_t),1,handle); 458 | if (j != 1) 459 | { 460 | createscores (score); 461 | return; 462 | } 463 | } 464 | fclose (handle); 465 | if (score > scores[NUMSCORES - 1].score) 466 | { 467 | getname (scores[NUMSCORES - 1].name); 468 | scores[NUMSCORES - 1].score = score; 469 | scores[NUMSCORES - 1].timestamp = tmp = time (NULL); 470 | } 471 | qsort (scores,NUMSCORES,sizeof (score_t),cmpscores); 472 | if ((handle = fopen (scorefile,"w")) == NULL) err2 (); 473 | strcpy (header,SCORE_HEADER); 474 | i = fwrite (header,strlen (SCORE_HEADER),1,handle); 475 | if (i != 1) err2 (); 476 | for (i = 0; i < NUMSCORES; i++) 477 | { 478 | j = fwrite (scores[i].name,strlen (scores[i].name) + 1,1,handle); 479 | if (j != 1) err2 (); 480 | j = fwrite (&(scores[i].score),sizeof (int),1,handle); 481 | if (j != 1) err2 (); 482 | j = fwrite (&(scores[i].timestamp),sizeof (time_t),1,handle); 483 | if (j != 1) err2 (); 484 | } 485 | fclose (handle); 486 | 487 | fprintf (stderr,"%s",scoretitle); 488 | i = 0; 489 | while ((i < NUMSCORES) && (scores[i].score != -1)) 490 | { 491 | j = scores[i].timestamp == tmp ? '*' : ' '; 492 | fprintf (stderr,"\t %2d%c %7d %s\n",i + 1,j,scores[i].score,scores[i].name); 493 | i++; 494 | } 495 | fprintf (stderr,"\n"); 496 | } 497 | 498 | /***************************************************************************/ 499 | /***************************************************************************/ 500 | /***************************************************************************/ 501 | 502 | static void showhelp () 503 | { 504 | fprintf (stderr,"USAGE: tint [-h] [-l level] [-n] [-d] [-b char]\n"); 505 | fprintf (stderr," -h Show this help message\n"); 506 | fprintf (stderr," -l Specify the starting level (%d-%d)\n",MINLEVEL,MAXLEVEL); 507 | fprintf (stderr," -n Draw next shape\n"); 508 | fprintf (stderr," -d Draw vertical dotted lines\n"); 509 | fprintf (stderr," -b Use this character to draw blocks instead of spaces\n"); 510 | fprintf (stderr," -s Draw shadow of shape\n"); 511 | exit (EXIT_FAILURE); 512 | } 513 | 514 | static void parse_options (int argc,char *argv[]) 515 | { 516 | int i = 1; 517 | while (i < argc) 518 | { 519 | /* Help? */ 520 | if (strcmp (argv[i],"-h") == 0) 521 | showhelp (); 522 | /* Level? */ 523 | else if (strcmp (argv[i],"-l") == 0) 524 | { 525 | i++; 526 | if (i >= argc || !str2int (&level,argv[i])) showhelp (); 527 | if ((level < MINLEVEL) || (level > MAXLEVEL)) 528 | { 529 | fprintf (stderr,"You must specify a level between %d and %d\n",MINLEVEL,MAXLEVEL); 530 | exit (EXIT_FAILURE); 531 | } 532 | } 533 | /* Show next? */ 534 | else if (strcmp (argv[i],"-n") == 0) 535 | shownext = TRUE; 536 | else if(strcmp(argv[i],"-d")==0) 537 | dottedlines = TRUE; 538 | else if(strcmp(argv[i], "-b")==0) 539 | { 540 | i++; 541 | if (i >= argc || strlen(argv[i]) < 1) showhelp(); 542 | blockchar = argv[i][0]; 543 | } 544 | else if (strcmp (argv[i],"-s") == 0) 545 | shadow = TRUE; 546 | else 547 | { 548 | fprintf (stderr,"Invalid option -- %s\n",argv[i]); 549 | showhelp (); 550 | } 551 | i++; 552 | } 553 | } 554 | 555 | static void choose_level () 556 | { 557 | char buf[NAMELEN]; 558 | 559 | do 560 | { 561 | fprintf (stderr,"Choose a level to start [%d-%d]: ",MINLEVEL,MAXLEVEL); 562 | fgets (buf,NAMELEN - 1,stdin); 563 | buf[strlen (buf) - 1] = '\0'; 564 | } 565 | while (!str2int (&level,buf) || level < MINLEVEL || level > MAXLEVEL); 566 | } 567 | 568 | static bool evaluate (engine_t *engine) 569 | { 570 | bool finished = FALSE; 571 | switch (engine_evaluate (engine)) 572 | { 573 | /* game over (board full) */ 574 | case -1: 575 | if ((level < MAXLEVEL) && ((engine->status.droppedlines / 10) > level)) level++; 576 | finished = TRUE; 577 | break; 578 | /* shape at bottom, next one released */ 579 | case 0: 580 | if ((level < MAXLEVEL) && ((engine->status.droppedlines / 10) > level)) 581 | { 582 | level++; 583 | in_timeout (DELAY); 584 | } 585 | shapecount[engine->curshape]++; 586 | break; 587 | /* shape moved down one line */ 588 | case 1: 589 | break; 590 | } 591 | return finished; 592 | } 593 | 594 | /***************************************************************************/ 595 | /***************************************************************************/ 596 | /***************************************************************************/ 597 | 598 | int main (int argc,char *argv[]) 599 | { 600 | bool finished; 601 | int ch; 602 | engine_t engine; 603 | /* Initialize */ 604 | rand_init (); /* must be called before engine_init () */ 605 | engine_init (&engine,score_function); /* must be called before using engine.curshape */ 606 | finished = shownext = shadow = FALSE; 607 | memset (shapecount,0,NUMSHAPES * sizeof (int)); 608 | shapecount[engine.curshape]++; 609 | parse_options (argc,argv); /* must be called after initializing variables */ 610 | engine.shadow = shadow; 611 | if (level < MINLEVEL) choose_level (); 612 | io_init (); 613 | drawbackground (); 614 | in_timeout (DELAY); 615 | /* Main loop */ 616 | do 617 | { 618 | /* draw shape */ 619 | showstatus (&engine); 620 | drawboard (engine.board); 621 | out_refresh (); 622 | /* Check if user pressed a key */ 623 | if ((ch = in_getch ()) != ERR) 624 | { 625 | switch (ch) 626 | { 627 | case 'j': 628 | case KEY_LEFT: 629 | engine_move (&engine,ACTION_LEFT); 630 | break; 631 | case 'k': 632 | case KEY_UP: 633 | case '\n': 634 | engine_move (&engine,ACTION_ROTATE_COUNTERCLOCKWISE); 635 | break; 636 | case 'K': 637 | engine_move (&engine,ACTION_ROTATE_CLOCKWISE); 638 | break; 639 | case 'l': 640 | case KEY_RIGHT: 641 | engine_move (&engine,ACTION_RIGHT); 642 | break; 643 | case KEY_DOWN: 644 | engine_move (&engine,ACTION_DOWN); 645 | break; 646 | case ' ': 647 | engine_move (&engine,ACTION_DROP); 648 | finished = evaluate(&engine); /* prevent key press after drop */ 649 | break; 650 | /* show next piece */ 651 | case 's': 652 | shownext = TRUE; 653 | break; 654 | /* toggle dotted lines */ 655 | case 'd': 656 | dottedlines = !dottedlines; 657 | break; 658 | /* next level */ 659 | case 'a': 660 | if (level < MAXLEVEL) 661 | { 662 | level++; 663 | in_timeout (DELAY); 664 | } 665 | else out_beep (); 666 | break; 667 | /* quit */ 668 | case 'q': 669 | finished = TRUE; 670 | break; 671 | /* pause */ 672 | case 'p': 673 | out_setcolor (COLOR_WHITE,COLOR_BLACK); 674 | out_gotoxy ((out_width () - 34) / 2,out_height () - 2); 675 | out_printf ("Paused - Press any key to continue"); 676 | while ((ch = in_getch ()) == ERR) ; /* Wait for a key to be pressed */ 677 | in_flush (); /* Clear keyboard buffer */ 678 | out_gotoxy ((out_width () - 34) / 2,out_height () - 2); 679 | out_printf (" "); 680 | break; 681 | /* unknown keypress */ 682 | default: 683 | out_beep (); 684 | } 685 | in_flush (); 686 | } 687 | else 688 | finished = evaluate(&engine); 689 | } 690 | while (!finished); 691 | /* Restore console settings and exit */ 692 | io_close (); 693 | /* Don't bother the player if he want's to quit */ 694 | if (ch != 'q') 695 | { 696 | showplayerstats (&engine); 697 | savescores (GETSCORE (engine.score)); 698 | } 699 | exit (EXIT_SUCCESS); 700 | } 701 | 702 | --------------------------------------------------------------------------------