Hi! This (fairly big) patch adds a cdebconf-gtk-tetris package to the debian-installer. As the name suggest, this will allow you to play Tetris within d-i. The implementation is based on Gnometris, porting from C++ and stripping it from most of its fancy features. If you want to see what it looks like, you can use one of the available mini.iso [1,2], start in expert mode and use the "Play Tetris" option in main-menu. [1] http://people.debian.org/~lunar/g-i+tetris-mini.iso (i386) [2] http://people.debian.org/~lunar/g-i+tetris-mini-amd64.iso I wonder if this patch should be integrated as is. Maybe it would be better to be able to start the Tetris during any progress bar. Or while base-installer/pkgsel are running... Another option is just to integrate it as the entropy plugin for the graphical frontend. I am also unsure about the required Depends for the udeb. Comments are really welcome on that matter, as my original dependencies made me report #437323. Note: This patch depends on the integration of the fe_gtk branch, but I won't spam the mailling-list with another huge patch to review, as there is no significant modification from what is already in the subversion repository. --- packages/cdebconf-tetris/Makefile.in | 84 +++++ packages/cdebconf-tetris/block_ops.c | 297 +++++++++++++++ packages/cdebconf-tetris/block_ops.h | 64 ++++ packages/cdebconf-tetris/blocks.c | 308 +++++++++++++++ packages/cdebconf-tetris/blocks.h | 45 +++ packages/cdebconf-tetris/configure.ac | 16 + .../debian/cdebconf-gtk-tetris.install | 1 + .../debian/cdebconf-gtk-tetris.postinst | 8 + .../debian/cdebconf-gtk-tetris.templates | 43 +++ packages/cdebconf-tetris/debian/changelog | 5 + packages/cdebconf-tetris/debian/compat | 1 + packages/cdebconf-tetris/debian/control | 17 + packages/cdebconf-tetris/debian/copyright | 30 ++ packages/cdebconf-tetris/debian/po/POTFILES.in | 1 + packages/cdebconf-tetris/debian/rules | 71 ++++ packages/cdebconf-tetris/field.c | 286 ++++++++++++++ packages/cdebconf-tetris/field.h | 52 +++ packages/cdebconf-tetris/gtk-plugin-tetris.c | 395 ++++++++++++++++++++ packages/cdebconf-tetris/linker-script | 6 + packages/cdebconf-tetris/preview.c | 166 ++++++++ packages/cdebconf-tetris/preview.h | 42 ++ packages/cdebconf-tetris/score.c | 182 +++++++++ packages/cdebconf-tetris/score.h | 45 +++ packages/cdebconf-tetris/tetris.h | 77 ++++ 24 files changed, 2242 insertions(+), 0 deletions(-) create mode 100644 packages/cdebconf-tetris/Makefile.in create mode 100644 packages/cdebconf-tetris/block_ops.c create mode 100644 packages/cdebconf-tetris/block_ops.h create mode 100644 packages/cdebconf-tetris/blocks.c create mode 100644 packages/cdebconf-tetris/blocks.h create mode 100644 packages/cdebconf-tetris/configure.ac create mode 100644 packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.install create mode 100644 packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.postinst create mode 100644 packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.templates create mode 100644 packages/cdebconf-tetris/debian/changelog create mode 100644 packages/cdebconf-tetris/debian/compat create mode 100644 packages/cdebconf-tetris/debian/control create mode 100644 packages/cdebconf-tetris/debian/copyright create mode 100644 packages/cdebconf-tetris/debian/po/POTFILES.in create mode 100755 packages/cdebconf-tetris/debian/rules create mode 100644 packages/cdebconf-tetris/field.c create mode 100644 packages/cdebconf-tetris/field.h create mode 100644 packages/cdebconf-tetris/gtk-plugin-tetris.c create mode 100644 packages/cdebconf-tetris/linker-script create mode 100644 packages/cdebconf-tetris/preview.c create mode 100644 packages/cdebconf-tetris/preview.h create mode 100644 packages/cdebconf-tetris/score.c create mode 100644 packages/cdebconf-tetris/score.h create mode 100644 packages/cdebconf-tetris/tetris.h diff --git a/packages/cdebconf-tetris/Makefile.in b/packages/cdebconf-tetris/Makefile.in new file mode 100644 index 0000000..e60f2d9 --- /dev/null +++ b/packages/cdebconf-tetris/Makefile.in @@ -0,0 +1,84 @@ +prefix = @prefix@ +etcdir = @sysconfdir@ +bindir = ${prefix}/bin +sbindir = ${prefix}/sbin +libdir = ${prefix}/lib +moddir = ${libdir}/cdebconf/frontend +sharedir = ${prefix}/share/debconf +mandir = ${prefix}/share/man +incdir = ${prefix}/include/cdebconf + +CC = @CC@ +CFLAGS = @CFLAGS@ @GTK_CFLAGS@ -I. +LDFLAGS = @LDFLAGS@ @LIBS@ @GTK_LIBS@ + +# Export only strictly needed symbols +LDFLAGS += "-Wl,--version-script=linker-script" + +# let the type char be unsigned by default +CFLAGS += -funsigned-char +# apply strict aliasing rules +CFLAGS += -fstrict-aliasing +# turn on all common warnings +CFLAGS += -Wall +# turn on extra warnings +CFLAGS += -W +# treat warnings as errors +CFLAGS += -Werror +# warn about undefined preprocessor identifiers +CFLAGS += -Wundef +# warn about casting of pointers to increased alignment requirements +CFLAGS += -Wcast-align +# make string constants const +CFLAGS += -Wwrite-strings +# warn about comparisons between signed and unsigned values +CFLAGS += -Wsign-compare +# warn about unused declared stuff +CFLAGS += -Wno-unused-parameter +# warn about variables which are initialized with themselves +CFLAGS += -Winit-self +# warn about pointer arithmetic on void* and function pointers +CFLAGS += -Wpointer-arith +# warn about multiple declarations +CFLAGS += -Wredundant-decls +# do not warn about zero-length formats. +CFLAGS += -Wno-format-zero-length +# missing prototypes +CFLAGS += -Wmissing-prototypes +# warn about functions without format attribute that should have one +CFLAGS += -Wmissing-format-attribute + +PLUGIN_MODULES = gtk-plugin-tetris.so + +SOURCES = \ + gtk-plugin-tetris.c tetris.h \ + blocks.c blocks.h \ + block_ops.c block_ops.h \ + field.c field.h \ + preview.c preview.h \ + score.c score.h + +OBJS = $(filter %.opic,$(subst .c,.opic,$(SOURCES))) + +all: $(PLUGIN_MODULES) + +install: $(PLUGIN_MODULES) + for p in $(PLUGIN_MODULES); do \ + install -m755 -d $(DESTDIR)/$(moddir)/$${p%%-*} ; \ + install -m644 $$p $(DESTDIR)/$(moddir)/$${p%%-*}/$${p#*-} ; \ + done + +clean: + rm -f $(PLUGIN_MODULES) + rm -f $(OBJS) + +distclean: clean + rm -f config.log config.status + rm -f Makefile + +gtk-plugin-tetris.so: $(OBJS) + $(CC) $(LDFLAGS) -shared -o $@ $(OBJS) + +%.opic: %.c + $(CC) $(CFLAGS) -fPIC -o $@ -c $< + diff --git a/packages/cdebconf-tetris/block_ops.c b/packages/cdebconf-tetris/block_ops.c new file mode 100644 index 0000000..c7d0a9b --- /dev/null +++ b/packages/cdebconf-tetris/block_ops.c @@ -0,0 +1,297 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "block_ops.h" + +#include <glib.h> + +#include "tetris.h" +#include "blocks.h" + +gboolean block_ok_here(struct tetris * tetris, int dx, int dy, int mr) +{ + int x = tetris->posx + dx; + int y = tetris->posy + dy; + int b = tetris->blocknr; + int r = -1 == mr ? tetris->rot : mr; + int x1; + int y1; + + x -= 2; + + for (x1 = 0; x1 < 4; ++x1) { + for (y1 = 0; y1 < 4; ++y1) { + if (BLOCK_TABLE[b][r][x1][y1] && (x1 + x < 0)) { + return FALSE; + } + if (BLOCK_TABLE[b][r][x1][y1] && (x1 + x >= COLUMNS)) { + return FALSE; + } + if (BLOCK_TABLE[b][r][x1][y1] && (y1 + y >= LINES)) { + return FALSE; + } + if (BLOCK_TABLE[b][r][x1][y1] && + LAYING == tetris->blocks[x + x1][y1 + y].what) { + return FALSE; + } + } + } + + return TRUE; +} + +int get_lines_to_bottom(struct tetris * tetris) +{ + int lines = LINES; + int x; + int y; + int yy; + int tmp; + + for (x = 0; x < 4; ++x) { + for (y = 3; y >= 0; --y) { + if (!BLOCK_TABLE[tetris->blocknr][tetris->rot][x][y]) { + continue; + } + for (yy = tetris->posy + y; yy < LINES; ++yy) { + if (LAYING == tetris->blocks[tetris->posx + x - 2][yy].what) { + break; + } + } + tmp = yy - tetris->posy - y; + if (lines > tmp) { + lines = tmp; + } + } + } + + return lines; +} + +gboolean move_block_left(struct tetris * tetris) +{ + if (!block_ok_here(tetris, -1, 0, -1)) { + return FALSE; + } + put_block_in_field(tetris, EMPTY); + --tetris->posx; + put_block_in_field(tetris, FALLING); + return TRUE; +} + +gboolean move_block_right(struct tetris * tetris) +{ + if (!block_ok_here(tetris, 1, 0, -1)) { + return FALSE; + } + put_block_in_field(tetris, EMPTY); + ++tetris->posx; + put_block_in_field(tetris, FALLING); + return TRUE; +} + +#define ROTATE_COUNTER_CLOCK_WISE TRUE +#define ROTATE_CLOCK_WISE FALSE + +gboolean rotate_block(struct tetris * tetris, gboolean rotate_ccw) +{ + int r = tetris->rot; + + if (rotate_ccw) { + if (--r < 0) { + r = 3; + } + } else { + if (++r >= 4) { + r = 0; + } + } + + if (!block_ok_here(tetris, 0, 0, r)) { + return FALSE; + } + put_block_in_field(tetris, EMPTY); + tetris->rot = r; + put_block_in_field(tetris, FALLING); + return TRUE; +} + +gboolean move_block_down(struct tetris * tetris) +{ + if (!block_ok_here(tetris, 0, 1, -1)) { + return TRUE; + } + put_block_in_field(tetris, EMPTY); + ++tetris->posy; + put_block_in_field(tetris, FALLING); + return FALSE; +} + +int drop_block(struct tetris * tetris) +{ + int count = 0; + + while (!move_block_down(tetris)) { + count++; + } + + return count; +} + +void falling_to_laying(struct tetris * tetris) +{ + int x; + int y; + + for (x = 0; x < COLUMNS; ++x) { + for (y = 0; y < LINES; ++y) { + if (FALLING == tetris->blocks[x][y].what) { + tetris->blocks[x][y].what = LAYING; + } + } + } +} + +void eliminate_line(struct tetris * tetris, int l) +{ + int y; + int x; + + for (y = l; y > 0; --y) { + for (x = 0; x < COLUMNS; ++x) { + tetris->blocks[x][y] = tetris->blocks[x][y - 1]; + + tetris->blocks[x][y - 1].what = EMPTY; + tetris->blocks[x][y - 1].color = 0; + } + } +} + +int check_full_lines(struct tetris * tetris) +{ + /* we can have at most 4 full lines (vertical block) */ + int full_lines[4] = {0, 0, 0, 0}; + int num_full_lines = 0; + int x; + int y; + int i; + gboolean f; + + for (y = tetris->posy; y < MIN(tetris->posy + 4, LINES); ++y) { + f = TRUE; + for (x = 0; x < COLUMNS; ++x) { + if (tetris->blocks[x][y].what != LAYING) { + f = FALSE; + break; + } + } + + if (f) { + full_lines[num_full_lines] = y; + ++num_full_lines; + } + } + + if (num_full_lines > 0) { + for (i = 0; i < num_full_lines; ++i) { + eliminate_line(tetris, full_lines[i]); + } + } + + return num_full_lines; +} + +gboolean generate_falling_block(struct tetris * tetris) +{ + tetris->posx = COLUMNS / 2 + 1; + tetris->posy = 0; + + tetris->blocknr = tetris->blocknr_next == -1 ? + g_random_int_range(0, BLOCK_TYPES) : + tetris->blocknr_next; + tetris->rot = tetris->rot_next == -1 ? + g_random_int_range(0, 4) : + tetris->rot_next; + + tetris->blocknr_next = g_random_int_range(0, BLOCK_TYPES); + tetris->rot_next = g_random_int_range(0, 4); + + if (!block_ok_here(tetris, 0, 0, -1)) { + return FALSE; + } + + return TRUE; +} + +void empty_field(struct tetris * tetris) +{ + int y; + int x; + + for (y = 0; y < LINES; ++y) { + for (x = 0; x < COLUMNS; ++x) { + tetris->blocks[x][y].what = EMPTY; + tetris->blocks[x][y].color = 0; + } + } +} + +void put_block_in_field(struct tetris * tetris, SlotType fill) +{ + int bx = tetris->posx; + int by = tetris->posy; + int x; + int y; + int i; + int j; + + for (x = 0; x < 4; ++x) { + for (y = 0; y < 4; ++y) { + if (BLOCK_TABLE[tetris->blocknr][tetris->rot][x][y]) { + i = bx - 2 + x; + j = y + by; + + tetris->blocks[i][j].what = fill; + if ((FALLING == fill) || (LAYING == fill)) { + tetris->blocks[i][j].color = tetris->blocknr % BLOCK_TYPES; + } else { + tetris->blocks[i][j].color = 0; + } + } + } + } +} + +gboolean is_field_empty(struct tetris * tetris) +{ + int x; + + for (x = 0; x < COLUMNS; x++) { + if (EMPTY != tetris->blocks[x][LINES - 1].what) { + return FALSE; + } + } + + return TRUE; +} + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/block_ops.h b/packages/cdebconf-tetris/block_ops.h new file mode 100644 index 0000000..2c219f9 --- /dev/null +++ b/packages/cdebconf-tetris/block_ops.h @@ -0,0 +1,64 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _BLOCK_OPS_H_ +#define _BLOCK_OPS_H_ + +#include <glib.h> + +#include "tetris.h" +#include "blocks.h" + +gboolean block_ok_here(struct tetris * tetris, int dx, int dy, int mr); + +int get_lines_to_bottom(struct tetris * tetris); + +gboolean move_block_left(struct tetris * tetris); + +gboolean move_block_right(struct tetris * tetris); + +#define ROTATE_COUNTER_CLOCK_WISE TRUE +#define ROTATE_CLOCK_WISE FALSE + +gboolean rotate_block(struct tetris * tetris, gboolean rotate_ccw); + +gboolean move_block_down(struct tetris * tetris); + +int drop_block(struct tetris * tetris); + +void falling_to_laying(struct tetris * tetris); + +void eliminate_line(struct tetris * tetris, int l); + +int check_full_lines(struct tetris * tetris); + +gboolean generate_falling_block(struct tetris * tetris); + +void empty_field(struct tetris * tetris); + +void put_block_in_field(struct tetris * tetris, SlotType fill); + +gboolean is_field_empty(struct tetris * tetris); + +#endif /* !_BLOCK_OPS_H_ */ + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/blocks.c b/packages/cdebconf-tetris/blocks.c new file mode 100644 index 0000000..570b5af --- /dev/null +++ b/packages/cdebconf-tetris/blocks.c @@ -0,0 +1,308 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "blocks.h" + +const int BLOCK_TABLE[BLOCK_TYPES][4][4][4] = { + { + { + {0, 0, 0, 0}, + {1, 1, 1, 0}, + {1, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 1, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 1, 0}, + {1, 1, 1, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {1, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 0, 0}, + }, + + }, + + { + { + {0, 0, 0, 0}, + {1, 1, 1, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 1, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 0, 0}, + }, + { + {1, 0, 0, 0}, + {1, 1, 1, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {1, 1, 0, 0}, + {0, 0, 0, 0}, + }, + }, + + { + { + {0, 0, 0, 0}, + {1, 1, 1, 0}, + {0, 1, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 0, 0}, + {0, 1, 1, 0}, + {0, 1, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 0, 0}, + {1, 1, 1, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 0, 0}, + {1, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 0, 0}, + }, + }, + + { + { + {0, 0, 0, 0}, + {0, 1, 1, 0}, + {1, 1, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 0, 0}, + {0, 1, 1, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 1, 0}, + {1, 1, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {1, 0, 0, 0}, + {1, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 0, 0}, + }, + }, + + { + { + {0, 0, 0, 0}, + {1, 1, 0, 0}, + {0, 1, 1, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 1, 0}, + {0, 1, 1, 0}, + {0, 1, 0, 0}, + {0, 0, 0, 0}, + }, + { + {1, 1, 0, 0}, + {0, 1, 1, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 0, 0}, + {1, 1, 0, 0}, + {1, 0, 0, 0}, + {0, 0, 0, 0}, + }, + }, + + { + { + {0, 0, 0, 0}, + {1, 1, 1, 1}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + }, + { + {0, 0, 0, 0}, + {1, 1, 1, 1}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + }, + }, + + { + { + {0, 0, 0, 0}, + {0, 1, 1, 0}, + {0, 1, 1, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 1, 1, 0}, + {0, 1, 1, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 1, 1, 0}, + {0, 1, 1, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 1, 1, 0}, + {0, 1, 1, 0}, + {0, 0, 0, 0}, + }, + } +}; + +const int SIZE_TABLE[BLOCK_TYPES][4][2] = { + { + {3, 2}, + {2, 3}, + {3, 2}, + {2, 3}, + }, + { + {3, 2}, + {2, 3}, + {3, 2}, + {2, 3}, + }, + { + {3, 2}, + {2, 3}, + {3, 2}, + {2, 3}, + }, + { + {3, 2}, + {2, 3}, + {3, 2}, + {2, 3}, + }, + { + {3, 2}, + {2, 3}, + {3, 2}, + {2, 3}, + }, + { + {4, 1}, + {1, 4}, + {4, 1}, + {1, 4}, + }, + { + {2, 2}, + {2, 2}, + {2, 2}, + {2, 2}, + }, +}; + +const int OFFSET_TABLE[BLOCK_TYPES][4][2] = { + { + {0, 1}, + {1, 0}, + {0, 0}, + {0, 0}, + + }, + { + {0, 1}, + {1, 0}, + {0, 0}, + {0, 0}, + }, + { + {0, 1}, + {1, 0}, + {0, 0}, + {0, 0}, + }, + { + {0, 1}, + {1, 0}, + {0, 0}, + {0, 0}, + }, + { + {0, 1}, + {1, 0}, + {0, 0}, + {0, 0}, + }, + { + {0, 1}, + {1, 0}, + {0, 2}, + {2, 0}, + }, + { + {1, 1}, + {1, 1}, + {1, 1}, + {1, 1}, + }, +}; + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/blocks.h b/packages/cdebconf-tetris/blocks.h new file mode 100644 index 0000000..9066492 --- /dev/null +++ b/packages/cdebconf-tetris/blocks.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _BLOCKS_H_ +#define _BLOCKS_H_ + +typedef enum { + EMPTY = 0, + FALLING, + LAYING +} SlotType; + +struct block { + SlotType what; + int color; +}; + +#define BLOCK_TYPES 7 + +extern const int BLOCK_TABLE[BLOCK_TYPES][4][4][4]; +extern const int SIZE_TABLE[BLOCK_TYPES][4][2]; +extern const int OFFSET_TABLE[BLOCK_TYPES][4][2]; + +#endif /* !_BLOCKS_H_ */ + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/configure.ac b/packages/cdebconf-tetris/configure.ac new file mode 100644 index 0000000..d381c51 --- /dev/null +++ b/packages/cdebconf-tetris/configure.ac @@ -0,0 +1,16 @@ +AC_INIT +PACKAGE=tetris +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") + +AC_PROG_MAKE_SET +AC_PROG_CC + +dnl PKG_CHECK_MODULES(GTK, [gtk+-2.0]) +PKG_CHECK_MODULES(GTK, [gtk+-directfb-2.0]) + +AC_CHECK_LIB(m, pow) + +AC_SUBST(GTK_CFLAGS) +AC_SUBST(GTK_LIBS) + +AC_OUTPUT(Makefile) diff --git a/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.install b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.install new file mode 100644 index 0000000..3a7472e --- /dev/null +++ b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.install @@ -0,0 +1 @@ +usr/lib/cdebconf/frontend/gtk diff --git a/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.postinst b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.postinst new file mode 100644 index 0000000..8125948 --- /dev/null +++ b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.postinst @@ -0,0 +1,8 @@ +#! /bin/sh -e +. /usr/share/debconf/confmodule + +db_capb + +db_fset cdebconf-gtk-tetris/tetris seen false +db_input critical cdebconf-gtk-tetris/tetris || true +db_go || true diff --git a/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.templates b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.templates new file mode 100644 index 0000000..29d9805 --- /dev/null +++ b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.templates @@ -0,0 +1,43 @@ +Template: cdebconf-gtk-tetris/tetris +Type: tetris +_Description: Play Tetris + +# The following keys are available: +# Left/arrows: Move block left/right - Up arrow: Rotate block +# Down arrow: Fast fall - Spacebar: Drop block - P: Pause + +Template: cdebconf-gtk-tetris/paused +Type: text +# Translators: this will appear in the play field +_Description: Paused + +Template: cdebconf-gtk-tetris/game-over +Type: text +# Translators: this will appear on the play field +_Description: Game Over + +Template: cdebconf-gtk-tetris/new-game +Type: text +# Translators: this will appear on a button +_Description: New game + +Template: cdebconf-gtk-tetris/end-game +Type: text +# Translators: this will appear on a button +_Description: End game + +Template: cdebconf-gtk-tetris/pause +Type: text +# Translators: this will appear on a button +_Description: Pause + +Template: cdebconf-gtk-tetris/resume +Type: text +# Translators: this will appear on a button +_Description: Resume + +Template: debian-installer/cdebconf-gtk-tetris/title +Type: text +# Main menu item +# Translators: keep it under 65 columns +_Description: Play Tetris diff --git a/packages/cdebconf-tetris/debian/changelog b/packages/cdebconf-tetris/debian/changelog new file mode 100644 index 0000000..939f18b --- /dev/null +++ b/packages/cdebconf-tetris/debian/changelog @@ -0,0 +1,5 @@ +cdebconf-tetris (1) UNRELEASED; urgency=low + + * Initial release. (Closes: #XXXXXX) + + -- Jérémy Bobbio <lunar@debian.org> Thu, 09 Aug 2007 12:13:32 +0200 diff --git a/packages/cdebconf-tetris/debian/compat b/packages/cdebconf-tetris/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/packages/cdebconf-tetris/debian/compat @@ -0,0 +1 @@ +5 diff --git a/packages/cdebconf-tetris/debian/control b/packages/cdebconf-tetris/debian/control new file mode 100644 index 0000000..ec1178d --- /dev/null +++ b/packages/cdebconf-tetris/debian/control @@ -0,0 +1,17 @@ +Source: cdebconf-tetris +Priority: extra +Section: debian-installer +Maintainer: Debian Install System Team <debian-boot@lists.debian.org> +Uploaders: Jérémy Bobbio <lunar@debian.org> +Build-Depends: debhelper (>= 5), libgtk-directfb-2.0-dev, + libdebconfclient0-dev (>> 0.119) +Standards-Version: 3.7.2 +XS-Vcs-Svn: svn://svn.debian.org/d-i/trunk/packages/cdebconf-tetris + +Package: cdebconf-gtk-tetris +Architecture: any +Section: debian-installer +XC-Package-Type: udeb +XB-Installer-Menu-Item: 95000 +Description: Play Tetris + This udeb will add a Tetris to the graphical version of the debian-installer. diff --git a/packages/cdebconf-tetris/debian/copyright b/packages/cdebconf-tetris/debian/copyright new file mode 100644 index 0000000..d402e02 --- /dev/null +++ b/packages/cdebconf-tetris/debian/copyright @@ -0,0 +1,30 @@ +Tetris plugin for the GTK+ frontend of cdebconf + +Author: + + Jérémy Bobbio <lunar@debian.org> + +Copyright: + + © 2007 Jérémy Bobbio <lunar@debian.org> + +This work is based on Gnometris, written by: + + J. Marcin Gorycki <marcin.gorycki@intel.com> + +License: + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in file /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth + Floor, Boston, MA 02110-1301 USA diff --git a/packages/cdebconf-tetris/debian/po/POTFILES.in b/packages/cdebconf-tetris/debian/po/POTFILES.in new file mode 100644 index 0000000..f8ab290 --- /dev/null +++ b/packages/cdebconf-tetris/debian/po/POTFILES.in @@ -0,0 +1 @@ +[type: gettext/rfc822deb] cdebconf-gtk-tetris.templates diff --git a/packages/cdebconf-tetris/debian/rules b/packages/cdebconf-tetris/debian/rules new file mode 100755 index 0000000..9479f58 --- /dev/null +++ b/packages/cdebconf-tetris/debian/rules @@ -0,0 +1,71 @@ +#! /usr/bin/make -f + +#export DH_VERBOSE=1 + +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +CFLAGS = -Wall -g + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif + +ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE)) + confflags += --build $(DEB_HOST_GNU_TYPE) +else + confflags += --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE) +endif + +config.status: configure + dh_testdir + CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,syms" \ + ./configure $(confflags) --prefix=/usr + +build: build-stamp +build-stamp: config.status + dh_testdir + $(MAKE) + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + -$(MAKE) distclean +ifneq "$(wildcard /usr/share/misc/config.sub)" "" + cp -f /usr/share/misc/config.sub config.sub +endif +ifneq "$(wildcard /usr/share/misc/config.guess)" "" + cp -f /usr/share/misc/config.guess config.guess +endif + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp + +binary-indep: build install + # We have nothing to do. + +binary-arch: build install + dh_testdir + dh_testroot + dh_install --sourcedir=debian/tmp + dh_installdebconf + dh_strip + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install + diff --git a/packages/cdebconf-tetris/field.c b/packages/cdebconf-tetris/field.c new file mode 100644 index 0000000..7cd39a4 --- /dev/null +++ b/packages/cdebconf-tetris/field.c @@ -0,0 +1,286 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "field.h" + +#include <gtk/gtk.h> +#include <cairo/cairo.h> + +#include <cdebconf/cdebconf_gtk.h> + +#include "tetris.h" +#include "blocks.h" + +#define FONT "Sans Bold" + +struct field { + struct tetris * tetris; + GtkWidget * drawing_area; + int pixel_width; + int pixel_height; + cairo_surface_t * buffer; + MessageType show_message; + struct block ** blocks; +}; + +void draw_cell(cairo_t * cr, struct block * block, int x, int y) +{ + const gdouble colours[7][3] = { + {1.0, 0.0, 0.0}, + {0.0, 1.0, 0.0}, + {0.0, 0.0, 1.0}, + {1.0, 1.0, 1.0}, + {1.0, 1.0, 0.0}, + {1.0, 0.0, 1.0}, + {0.0, 1.0, 1.0} + }; + int i; + + if (EMPTY == block->what) { + return; + } + + i = block->color; + i = CLAMP(i, 0, 6); + + cairo_set_source_rgb(cr, colours[i][0], colours[i][1], colours[i][2]); + + cairo_rectangle(cr, x + 0.05, y + 0.05, 0.9, 0.9); + cairo_fill(cr); +} + +void draw_background(cairo_t * cr) +{ + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_paint(cr); +} + +static void draw_buffer(struct field * field) +{ + cairo_t * cr; + int x; + int y; + + cr = cairo_create(field->buffer); + + draw_background(cr); + + cairo_scale(cr, 1.0 * field->pixel_width / COLUMNS, 1.0 * field->pixel_height / LINES); + + for (y = 0; y < LINES; y++) { + for (x = 0; x < COLUMNS; x++) { + draw_cell(cr, &field->tetris->blocks[x][y], x, y); + } + } + + cairo_destroy(cr); +} + +static void draw_widget(struct field * field, gint x, gint y, gint wd, gint ht) +{ + cairo_t * cr; + + cr = gdk_cairo_create(field->drawing_area->window); + + cairo_set_source_surface(cr, field->buffer, 0, 0); + cairo_rectangle(cr, x, y, wd, ht); + cairo_fill(cr); + + cairo_destroy(cr); +} + +static void draw_message(struct field * field, cairo_t * cr, const char * msg) +{ + PangoLayout * dummy_layout; + PangoLayout * layout; + PangoFontDescription * desc; + int lw; + int lh; + + cairo_save(cr); + + // Center coordinates + cairo_translate(cr, field->pixel_width / 2, field->pixel_height / 2); + + desc = pango_font_description_from_string(FONT); + + layout = pango_cairo_create_layout(cr); + pango_layout_set_text(layout, msg, -1); + + dummy_layout = pango_layout_copy(layout); + pango_layout_set_font_description(dummy_layout, desc); + pango_layout_get_size(dummy_layout, &lw, &lh); + g_object_unref(dummy_layout); + + /* desired height : lh = widget width * 0.9 : lw */ + pango_font_description_set_absolute_size( + desc, ((float) lh / lw) * PANGO_SCALE * field->pixel_width * 0.8); + pango_layout_set_font_description(layout, desc); + pango_font_description_free(desc); + + pango_layout_get_size(layout, &lw, &lh); + cairo_move_to(cr, -((double)lw / PANGO_SCALE) / 2, + -((double)lh / PANGO_SCALE) / 2); + pango_cairo_layout_path(cr, layout); + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_fill_preserve(cr); + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + /* A linewidth of 2 pixels at the default size. */ + cairo_set_line_width(cr, field->pixel_width / 220.0); + cairo_stroke(cr); + + g_object_unref(layout); + + cairo_restore(cr); +} + +static gboolean expose(GtkWidget * widget, GdkEventExpose * event, + struct field * field) +{ + draw_widget(field, event->area.x, event->area.y, event->area.width, + event->area.height); + + return TRUE; +} + +static gboolean configure(GtkWidget * widget, GdkEventConfigure * event, + struct field * field) +{ + cairo_t * cr; + + field->pixel_width = widget->allocation.width; + field->pixel_height = widget->allocation.height; + + cr = gdk_cairo_create(widget->window); + + if (field->buffer) { + cairo_surface_destroy(field->buffer); + } + field->buffer = cairo_surface_create_similar( + cairo_get_target(cr), CAIRO_CONTENT_COLOR, widget->allocation.width, + widget->allocation.height); + + cairo_destroy(cr); + + return TRUE; +} + +struct field * create_field(struct tetris * tetris, GtkWidget * container) +{ + struct field * field; + GtkWidget * aspect_frame; + GtkWidget * drawing_area; + + if (NULL == (field = g_malloc0(sizeof (struct field)))) { + g_warning("g_malloc0 failed."); + return NULL; + } + + field->tetris = tetris; + field->pixel_width = -1; + field->pixel_height = -1; + field->buffer = NULL; + field->show_message = MESSAGE_NONE; + + aspect_frame = gtk_aspect_frame_new( + NULL /* no label */, 0.5 /* center */, 0.5 /* middle */, + (float) COLUMNS / (float) LINES, FALSE /* enforce ratio */); + if (NULL == aspect_frame) { + g_warning("gtk_aspect_frame_new failed."); + g_free(field); + return NULL; + } + gtk_frame_set_shadow_type(GTK_FRAME (aspect_frame), GTK_SHADOW_NONE); + + if (NULL == (drawing_area = gtk_drawing_area_new())) { + g_warning("gtk_drawing_area_new failed."); + g_free(field); + return NULL; + } + + g_signal_connect(drawing_area, "expose_event", + G_CALLBACK(expose), field); + g_signal_connect(drawing_area, "configure_event", + G_CALLBACK(configure), field); + + gtk_widget_set_size_request(drawing_area, COLUMNS * 190 / LINES, 190); + + g_object_ref(drawing_area); + field->drawing_area = drawing_area; + + gtk_container_add(GTK_CONTAINER(aspect_frame), drawing_area); + gtk_box_pack_start_defaults(GTK_BOX(container), aspect_frame); + + return field; +} + +void destroy_field(struct field * field) +{ + if (NULL == field) { + return; + } + if (NULL != field->buffer) { + cairo_surface_destroy(field->buffer); + } + g_object_unref(field->drawing_area); + /* field->drawing_area will be destroyed by its parent. */ + g_free(field); +} + +static void redraw(struct field * field) +{ + cairo_t * cr; + gchar * message; + + g_return_if_fail(field->buffer); + draw_buffer(field); + cr = cairo_create(field->buffer); + if (MESSAGE_PAUSED == field->show_message) { + message = cdebconf_gtk_get_text( + field->tetris->fe, "cdebconf-gtk-tetris/paused", "Paused"); + draw_message(field, cr, message); + g_free(message); + } else if (MESSAGE_GAME_OVER == field->show_message) { + message = cdebconf_gtk_get_text( + field->tetris->fe, "cdebconf-gtk-tetris/game-over", "Game Over"); + draw_message(field, cr, message); + g_free(message); + } + cairo_destroy(cr); + draw_widget(field, 0, 0, field->pixel_width, field->pixel_height); + gtk_widget_queue_draw(field->drawing_area); +} + +void redraw_field(struct tetris * tetris) +{ + redraw(tetris->field); +} + +void show_message(struct tetris * tetris, MessageType message_type) +{ + struct field * field = tetris->field; + + field->show_message = message_type; + redraw(field); +} + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/field.h b/packages/cdebconf-tetris/field.h new file mode 100644 index 0000000..b688eba --- /dev/null +++ b/packages/cdebconf-tetris/field.h @@ -0,0 +1,52 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _FIELD_H_ +#define _FIELD_H_ + +#include <gtk/gtk.h> +#include <cairo/cairo.h> + +struct field; + +#include "tetris.h" + +typedef enum { + MESSAGE_NONE, + MESSAGE_PAUSED, + MESSAGE_GAME_OVER +} MessageType; + +struct field * create_field(struct tetris * tetris, GtkWidget * container); + +void destroy_field(struct field * field); + +void draw_background(cairo_t * cr); +void draw_cell(cairo_t * cr, struct block * block, int x, int y); + +void redraw_field(struct tetris * tetris); + +void show_message(struct tetris * tetris, MessageType message_type); + +#endif /* !_FIELD_H_ */ + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/gtk-plugin-tetris.c b/packages/cdebconf-tetris/gtk-plugin-tetris.c new file mode 100644 index 0000000..804b81b --- /dev/null +++ b/packages/cdebconf-tetris/gtk-plugin-tetris.c @@ -0,0 +1,395 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> +#include <math.h> + +#include <cdebconf/frontend.h> +#include <cdebconf/question.h> +#include <cdebconf/cdebconf_gtk.h> + +/* Plugin entry point. */ +int cdebconf_gtk_handler_tetris(struct frontend * fe, + struct question * question, + GtkWidget * question_box); + +#include "field.h" +#include "block_ops.h" +#include "preview.h" +#include "score.h" + +/* XXX: remove? +#define BLOCK_SIZE 40 */ + +/* XXX: remove? +#define TILE_THRESHOLD 65 */ + +static void toggle_pause(struct tetris * tetris) +{ + int paused = !tetris->paused; + gchar * label; + + tetris->paused = paused; + + show_message(tetris, paused ? MESSAGE_PAUSED : MESSAGE_NONE); + + if (paused) { + label = cdebconf_gtk_get_text( + tetris->fe, "cdebconf-gtk-tetris/resume", "Resume"); + } else { + label = cdebconf_gtk_get_text( + tetris->fe, "cdebconf-gtk-tetris/pause", "Pause"); + } + gtk_button_set_label(GTK_BUTTON(tetris->pause_button), label); + g_free(label); +} + +static void end_game(struct tetris * tetris) +{ + gchar * label; + + if (0 != tetris->timeout_id) { + g_source_remove(tetris->timeout_id); + tetris->timeout_id = 0; + } + if (tetris->paused) { + toggle_pause(tetris); + } + gtk_widget_set_sensitive(tetris->pause_button, FALSE); + gtk_widget_set_sensitive(tetris->continue_button, TRUE); + + tetris->blocknr_next = -1; + tetris->rot_next = -1; + preview_block(tetris->preview); + show_message(tetris, MESSAGE_GAME_OVER); + tetris->in_play = FALSE; + + label = cdebconf_gtk_get_text( + tetris->fe, "cdebconf-gtk-tetris/new-game", "New game"); + gtk_button_set_label(GTK_BUTTON(tetris->game_button), label); + g_free(label); +} + +static void generate_new_block(struct tetris * tetris) +{ + if (generate_falling_block(tetris)) { + put_block_in_field(tetris, FALLING); + preview_block(tetris->preview); + tetris->one_pause = TRUE; + } else { + end_game(tetris); + } +} + +static void manage_fallen(struct tetris * tetris); + +static gboolean handle_timeout(struct tetris * tetris) +{ + gboolean res; + + if (tetris->paused) { + return TRUE; + } + + if (tetris->one_pause) { + tetris->one_pause = FALSE; + redraw_field(tetris); + } else { + res = move_block_down(tetris); + redraw_field(tetris); + if (res) { + manage_fallen(tetris); + } + } + return TRUE; +} + +static void generate_timer(struct tetris * tetris, int level) +{ + int intv; + + g_assert(level > 0); + + if (0 < tetris->timeout_id) { + g_source_remove(tetris->timeout_id); + } + + intv = (int) (1000.0 * pow(0.8, level - 1)); + if (10 >= intv) { + intv = 10; + } + tetris->timeout_id = g_timeout_add(intv, (GSourceFunc) handle_timeout, + tetris); +} + +static void manage_fallen(struct tetris * tetris) +{ + int level_before; + int level_after; + + falling_to_laying(tetris); + + level_before = tetris->level; + level_after = score_lines(tetris, check_full_lines(tetris)); + if (level_before != level_after) { + generate_timer(tetris, level_after); + } + + if (is_field_empty(tetris)) { + score_last_line_bonus(tetris); + } + + generate_new_block(tetris); +} + +static void start_new_game(struct tetris * tetris) +{ + gchar * label; + + if (tetris->timeout_id) { + g_source_remove(tetris->timeout_id); + tetris->timeout_id = 0; + } + + tetris->in_play = TRUE; + tetris->paused = FALSE; + + reset_score(tetris); + + generate_timer(tetris, tetris->level); + empty_field(tetris); + + generate_new_block(tetris); + + gtk_widget_set_sensitive(tetris->pause_button, TRUE); + gtk_widget_set_sensitive(tetris->continue_button, FALSE); + + label = cdebconf_gtk_get_text( + tetris->fe, "cdebconf-gtk-tetris/end-game", "End game"); + gtk_button_set_label(GTK_BUTTON(tetris->game_button), label); + g_free(label); + + /* will redraw the field. */ + show_message(tetris, MESSAGE_NONE); +} + +static gboolean handle_key_press(GtkWidget * widget, GdkEvent * event, + struct tetris * tetris) +{ + gboolean res = FALSE; + int keyval = ((GdkEventKey *) event)->keyval; + + if (tetris->in_play && KEY_PAUSE == keyval) { + toggle_pause(tetris); + return TRUE; + } + + if (0 == tetris->timeout_id || tetris->paused) { + return FALSE; + } + + if (KEY_DOWN == keyval) { + if (!tetris->fast_fall && !tetris->one_pause) { + tetris->fast_fall = TRUE; + g_source_remove(tetris->timeout_id); + tetris->timeout_id = g_timeout_add( + 10, (GSourceFunc) handle_timeout, tetris); + } + res = TRUE; + } + + if (KEY_LEFT == keyval) { + res = move_block_left(tetris); + tetris->one_pause = FALSE; + res = TRUE; + } else if (KEY_RIGHT == keyval) { + res = move_block_right(tetris); + tetris->one_pause = FALSE; + res = TRUE; + } else if (KEY_UP == keyval) { + res = rotate_block(tetris, ROTATE_COUNTER_CLOCK_WISE); + tetris->one_pause = FALSE; + res = TRUE; + } else if (KEY_DROP == keyval) { + tetris->drop_block = TRUE; + drop_block(tetris); + manage_fallen(tetris); + res = TRUE; + } + if (res) { + redraw_field(tetris); + } + return res; +} + +static gboolean handle_key_release(GtkWidget * widget, GdkEvent * event, + struct tetris * tetris) +{ + int keyval = ((GdkEventKey *) event)->keyval; + + if (0 == tetris->timeout_id || tetris->paused) { + return FALSE; + } + + if (KEY_DOWN == keyval) { + if (tetris->fast_fall) { + tetris->fast_fall = FALSE; + generate_timer(tetris, tetris->level); + } + return TRUE; + } + if (KEY_DROP == keyval) { + tetris->drop_block = FALSE; + return TRUE; + } + return FALSE; +} + +static void handle_game_button(struct tetris * tetris) +{ + if (tetris->in_play) { + end_game(tetris); + } else { + start_new_game(tetris); + } +} + +static void create_buttons(struct tetris * tetris) +{ + gchar * label; + GtkWidget * pause_button; + GtkWidget * game_button; + GtkWidget * continue_button; + + label = cdebconf_gtk_get_text( + tetris->fe, "cdebconf-gtk-tetris/pause", "Pause"); + pause_button = gtk_button_new_with_label(label); + g_free(label); + cdebconf_gtk_add_button(tetris->fe, pause_button); + cdebconf_gtk_set_button_secondary(tetris->fe, pause_button, TRUE); + gtk_widget_set_sensitive(pause_button, FALSE); + g_signal_connect_swapped(pause_button, "clicked", + (GCallback) toggle_pause, tetris); + g_object_ref(pause_button); + tetris->pause_button = pause_button; + + label = cdebconf_gtk_get_text( + tetris->fe, "cdebconf-gtk-tetris/new-game", "New game"); + game_button = gtk_button_new_with_label(label); + g_free(label); + cdebconf_gtk_add_button(tetris->fe, game_button); + g_signal_connect_swapped(game_button, "clicked", + (GCallback) handle_game_button, tetris); + g_object_ref(game_button); + tetris->game_button = game_button; + + continue_button = cdebconf_gtk_create_continue_button(tetris->fe); + g_object_ref(continue_button); + tetris->continue_button = continue_button; +} + +static GtkWidget * create_widget(struct tetris * tetris) +{ + GtkWidget * hb; + GtkWidget * vb1; + GtkWidget * vb2; + + hb = gtk_hbox_new(FALSE, 0); + + vb1 = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vb1), 10); + tetris->field = create_field(tetris, vb1); + gtk_box_pack_start_defaults(GTK_BOX(hb), vb1); + + vb2 = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vb2), 10); + gtk_box_pack_end(GTK_BOX(hb), vb2, 0, 0, 0); + + create_buttons(tetris); + tetris->preview = create_preview(tetris, vb2); + tetris->score_frame = create_score_frame(tetris, vb2); + + return hb; +} + +static void destroy_tetris(struct tetris * tetris) +{ + if (NULL == tetris) { + return; + } + destroy_field(tetris->field); + destroy_preview(tetris->preview); + destroy_score_frame(tetris->score_frame); + g_object_unref(tetris->widget); + g_free(tetris); +} + +static void cleanup(struct question * question, struct tetris * tetris) +{ + GtkWidget * widget = tetris->widget; + GtkWidget * main_window = gtk_widget_get_toplevel(widget); + + g_assert(!tetris->in_play); + g_signal_handlers_disconnect_by_func( + main_window, handle_key_press, tetris); + g_signal_handlers_disconnect_by_func( + main_window, handle_key_release, tetris); + destroy_tetris(tetris); +} + +int cdebconf_gtk_handler_tetris(struct frontend * fe, + struct question * question, + GtkWidget * question_box) +{ + struct tetris * tetris; + GtkWidget * widget; + GtkWidget * main_window; + + if (NULL == (tetris = g_malloc0(sizeof (struct tetris)))) { + g_warning("g_malloc0 failed."); + return DC_NOTOK; + } + tetris->fe = fe; + if (NULL == (widget = create_widget(tetris))) { + g_warning("create_widget failed."); + return DC_NOTOK; + } + g_object_ref(widget); + tetris->widget = widget; + + cdebconf_gtk_add_common_layout(fe, question, question_box, widget); + + main_window = gtk_widget_get_toplevel(widget); + + g_signal_connect(main_window, "key_press_event", + G_CALLBACK(handle_key_press), tetris); + g_signal_connect(main_window, "key_release_event", + G_CALLBACK(handle_key_release), tetris); + + gtk_widget_grab_focus(widget); + cdebconf_gtk_register_setter(fe, SETTER_FUNCTION(cleanup), question, + tetris); + return DC_OK; +} + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/linker-script b/packages/cdebconf-tetris/linker-script new file mode 100644 index 0000000..2877829 --- /dev/null +++ b/packages/cdebconf-tetris/linker-script @@ -0,0 +1,6 @@ +{ + global: + cdebconf_gtk_handler_tetris; + local: + *; +}; diff --git a/packages/cdebconf-tetris/preview.c b/packages/cdebconf-tetris/preview.c new file mode 100644 index 0000000..b1d0d2c --- /dev/null +++ b/packages/cdebconf-tetris/preview.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <gtk/gtk.h> +#include <cairo/cairo.h> + +#include "preview.h" + +#include "blocks.h" +#include "field.h" + +#define PREVIEW_WIDTH 6 +#define PREVIEW_HEIGHT 6 +#define PREVIEW_SIZE 5 + +struct preview { + struct tetris * tetris; + GtkWidget * widget; + gint pixel_width; + gint pixel_height; + gboolean enabled; + struct block blocks[PREVIEW_WIDTH][PREVIEW_HEIGHT]; +}; + +static gboolean configure(GtkWidget * widget, GdkEventConfigure * event, + struct preview * preview) +{ + preview->pixel_width = event->width; + preview->pixel_height = event->height; + + return TRUE; +} + +static gboolean expose(GtkWidget * widget, GdkEventExpose * event, + struct preview * preview) +{ + cairo_t * cr; + cairo_surface_t * dst; + int x; + int y; + + cr = gdk_cairo_create(widget->window); + + if (!preview->enabled) { + cairo_scale(cr, 1.0 * widget->allocation.width / PREVIEW_WIDTH, + 1.0 * widget->allocation.height / PREVIEW_HEIGHT); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_paint(cr); + + cairo_set_source_rgb(cr, 0.8, 0.1, 0.1); + cairo_set_line_width(cr, 0.5); + + cairo_move_to(cr, 1, 1); + cairo_line_to(cr, PREVIEW_WIDTH - 1, PREVIEW_HEIGHT - 1); + cairo_move_to(cr, PREVIEW_WIDTH - 1, 1); + cairo_line_to(cr, 1, PREVIEW_HEIGHT - 1); + + cairo_stroke (cr); + } else { + dst = cairo_get_target(cr); + draw_background(cr); + cairo_scale(cr, 1.0 * preview->pixel_width / PREVIEW_WIDTH, + 1.0 * preview->pixel_height / PREVIEW_HEIGHT); + for (y = 0; y < PREVIEW_HEIGHT; y++) { + for (x = 0; x < PREVIEW_WIDTH; x++) { + draw_cell(cr, &preview->blocks[x][y], x, y); + } + } + } + + cairo_destroy (cr); + + return TRUE; +} + +struct preview * create_preview(struct tetris * tetris, GtkWidget * container) +{ + struct preview * preview; + GtkWidget * widget; + + if (NULL == (preview = g_malloc0(sizeof (struct preview)))) { + g_warning("g_malloc failed."); + return NULL; + } + preview->tetris = tetris; + preview->enabled = TRUE; + + widget = gtk_drawing_area_new(); + + g_object_ref(widget); + preview->widget = widget; + /* FIXME: We should scale with the rest of the UI, but that requires + * changes to the widget layout - i.e. wrap the preview in an + * fixed-aspect box. */ + gtk_widget_set_size_request( + widget, PREVIEW_SIZE * 20, PREVIEW_SIZE * 20); + + g_signal_connect(widget, "expose_event", G_CALLBACK(expose), preview); + g_signal_connect(widget, "configure_event", + G_CALLBACK(configure), preview); + + gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0); + + return preview; +} + +void destroy_preview(struct preview * preview) +{ + if (NULL == preview) { + return; + } + g_object_unref(preview->widget); + /* preview->widget will be destroyed by its parent. */ + g_free(preview); +} + +void enable_preview(struct preview * preview, gboolean enabled) +{ + preview->enabled = enabled; + gtk_widget_queue_draw(preview->widget); +} + +void preview_block(struct preview * preview) +{ + struct tetris * tetris = preview->tetris; + int blocknr = tetris->blocknr_next; + int blockrot = tetris->rot_next; + int x; + int y; + + for (x = 1; x < PREVIEW_WIDTH - 1; x++) { + for (y = 1; y < PREVIEW_HEIGHT - 1; y++) { + if ((blocknr != -1) && + BLOCK_TABLE[blocknr][blockrot][x - 1][y - 1]) { + preview->blocks[x][y].what = LAYING; + preview->blocks[x][y].color = blocknr % BLOCK_TYPES; + } else { + preview->blocks[x][y].what = EMPTY; + } + } + } + gtk_widget_queue_draw(preview->widget); +} + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/preview.h b/packages/cdebconf-tetris/preview.h new file mode 100644 index 0000000..0b5f533 --- /dev/null +++ b/packages/cdebconf-tetris/preview.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _PREVIEW_H_ +#define _PREVIEW_H_ + +#include <gtk/gtk.h> + +struct preview; + +#include "tetris.h" + +struct preview * create_preview(struct tetris * tetris, GtkWidget * container); + +void destroy_preview(struct preview * preview); + +void enable_preview(struct preview * preview, gboolean enabled); + +void preview_block(struct preview * preview); + +#endif /* !_PREVIEW_H_ */ + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/score.c b/packages/cdebconf-tetris/score.c new file mode 100644 index 0000000..7039039 --- /dev/null +++ b/packages/cdebconf-tetris/score.c @@ -0,0 +1,182 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "score.h" + +#include <gtk/gtk.h> + +struct score_frame { + GtkWidget * score_widget; + GtkWidget * lines_widget; + GtkWidget * level_widget; +}; + +struct score_frame * create_score_frame(struct tetris * tetris, + GtkWidget * container) +{ + struct score_frame * score_frame; + GtkWidget * table; + GtkWidget * score_label; + GtkWidget * score_widget; + GtkWidget * lines_label; + GtkWidget * lines_widget; + GtkWidget * level_label; + GtkWidget * level_widget; + + if (NULL == (score_frame = g_malloc0(sizeof (struct score_frame)))) { + g_warning("g_malloc0 failed."); + return NULL; + } + + table = gtk_table_new(3, 2, FALSE /* not homogeneous */); + + score_label = gtk_label_new(_("Score:")); + gtk_misc_set_alignment(GTK_MISC(score_label), 0.0, 0.5); + gtk_table_attach_defaults(GTK_TABLE(table), score_label, 0, 1, 0, 1); + + score_widget = gtk_label_new("0" /* XXX */); + gtk_misc_set_alignment(GTK_MISC(score_widget), 1.0, 0.5); + gtk_table_attach_defaults(GTK_TABLE(table), score_widget, 1, 2, 0, 1); + + g_object_ref(score_widget); + score_frame->score_widget = score_widget; + + lines_label = gtk_label_new(_("Lines:")); + gtk_misc_set_alignment(GTK_MISC(lines_label), 0.0, 0.5); + gtk_table_attach_defaults(GTK_TABLE(table), lines_label, 0, 1, 1, 2); + + lines_widget = gtk_label_new(NULL); + gtk_misc_set_alignment(GTK_MISC(lines_widget), 1.0, 0.5); + gtk_table_attach_defaults(GTK_TABLE(table), lines_widget, 1, 2, 1, 2); + + g_object_ref(lines_widget); + score_frame->lines_widget = lines_widget; + + level_label = gtk_label_new(_("Level:")); + gtk_misc_set_alignment(GTK_MISC(level_label), 0.0, 0.5); + gtk_table_attach_defaults(GTK_TABLE(table), level_label, 0, 1, 2, 3); + + level_widget = gtk_label_new(NULL); + gtk_misc_set_alignment(GTK_MISC(level_widget), 1.0, 0.5); + gtk_table_attach_defaults(GTK_TABLE(table), level_widget, 1, 2, 2, 3); + + g_object_ref(level_widget); + score_frame->level_widget = level_widget; + + gtk_box_pack_end(GTK_BOX(container), table, TRUE, FALSE, 0); + + return score_frame; +} + +void destroy_score_frame(struct score_frame * score_frame) +{ + if (NULL == score_frame) { + return; + } + g_object_unref(score_frame->level_widget); + g_object_unref(score_frame->lines_widget); + g_object_unref(score_frame->score_widget); + /* widgets will be destroyed by their parents. */ + g_free(score_frame); +} + +static void set_score(struct tetris * tetris, int score) +{ + struct score_frame * score_frame = tetris->score_frame; + gchar * s; + + tetris->score = score; + s = g_strdup_printf("%7d", tetris->score); + gtk_label_set_text(GTK_LABEL(score_frame->score_widget), s); + g_free(s); +} + +static void inc_score(struct tetris * tetris, int increment) +{ + set_score(tetris, tetris->score + increment); +} + +void score_last_line_bonus(struct tetris * tetris) +{ + inc_score(tetris, 10000 * tetris->level); +} + +static void set_level(struct tetris * tetris, int level) +{ + struct score_frame * score_frame = tetris->score_frame; + gchar * s; + + tetris->level = level; + s = g_strdup_printf("%7d", tetris->level); + gtk_label_set_text(GTK_LABEL(score_frame->level_widget), s); + g_free(s); +} + +static void set_lines(struct tetris * tetris, int lines) +{ + struct score_frame * score_frame = tetris->score_frame; + gchar * s; + + tetris->lines = lines; + s = g_strdup_printf("%7d", tetris->lines); + gtk_label_set_text(GTK_LABEL(score_frame->lines_widget), s); + g_free(s); +} + +int score_lines(struct tetris * tetris, int newlines) +{ + int level = tetris->level; + int linescore = 0; + + switch (newlines) { + case 0: + return level; + case 1: + linescore = 40; + break; + case 2: + linescore = 100; + break; + case 3: + linescore = 300; + break; + case 4: + linescore = 1200; + break; + } + inc_score(tetris, level * linescore); + + /* check the level */ + set_lines(tetris, tetris->lines + newlines); + set_level(tetris, STARTING_LEVEL + tetris->lines / 10); + + return level; +} + +void reset_score(struct tetris * tetris) +{ + set_lines(tetris, 0); + set_score(tetris, 0); + set_level(tetris, STARTING_LEVEL); +} + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/score.h b/packages/cdebconf-tetris/score.h new file mode 100644 index 0000000..cc3bcc0 --- /dev/null +++ b/packages/cdebconf-tetris/score.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _SCORE_H_ +#define _SCORE_H_ + +#include <gtk/gtk.h> + +struct score_frame; + +#include "tetris.h" + +struct score_frame * create_score_frame(struct tetris * tetris, + GtkWidget * container); + +void destroy_score_frame(struct score_frame * score_frame); + +int score_lines(struct tetris * tetris, int newlines); + +void score_last_line_bonus(struct tetris * tetris); + +void reset_score(struct tetris * tetris); + +#endif /* !_SCORE_H_ */ + +/* vim: et sw=4 si + */ diff --git a/packages/cdebconf-tetris/tetris.h b/packages/cdebconf-tetris/tetris.h new file mode 100644 index 0000000..d19d2d5 --- /dev/null +++ b/packages/cdebconf-tetris/tetris.h @@ -0,0 +1,77 @@ +/* + * Copyright © 2007 Jérémy Bobbio <lunar@debian.org> + * + * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _TETRIS_H_ +#define _TETRIS_H_ + +#include <glib.h> + +#include <cdebconf/frontend.h> + +struct tetris; + +#include "blocks.h" +#include "score.h" +#include "preview.h" + +#define LINES 20 +#define COLUMNS 11 + +#define STARTING_LEVEL 1 + +#define KEY_PAUSE GDK_p +#define KEY_DOWN GDK_Down +#define KEY_LEFT GDK_Left +#define KEY_RIGHT GDK_Right +#define KEY_UP GDK_Up +#define KEY_DROP GDK_space + +struct tetris { + struct frontend * fe; + struct field * field; + struct preview * preview; + GtkWidget * widget; + GtkWidget * pause_button; + GtkWidget * game_button; + GtkWidget * continue_button; + struct score_frame * score_frame; + gboolean paused; + int timeout_id; + gboolean one_pause; + gboolean in_play; + gboolean fast_fall; + gboolean drop_block; + int level; + int score; + int lines; + int blocknr_next; + int rot_next; + int rot; + int blocknr; + int posx; + int posy; + struct block blocks[COLUMNS][LINES]; +}; + +#endif /* !_TETRIS_H_ */ + +/* vim: et sw=4 si + */ -- Jérémy Bobbio .''`. lunar@debian.org : :Ⓐ : # apt-get install anarchism `. `'` `-
Attachment:
signature.asc
Description: Digital signature