📄 nxsnake.c
字号:
/* * Copyright (c) 2003 Century Software, Inc. All Rights Reserved. * * This file is part of the PIXIL Operating Environment * * The use, copying and distribution of this file is governed by one * of two licenses, the PIXIL Commercial License, or the GNU General * Public License, version 2. * * Licensees holding a valid PIXIL Commercial License may use this file * in accordance with the PIXIL Commercial License Agreement provided * with the Software. Others are governed under the terms of the GNU * General Public License version 2. * * This file may be distributed and/or modified under the terms of the * GNU General Public License version 2 as published by the Free * Software Foundation and appearing in the file LICENSE.GPL included * in the packaging of this file. * * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. * * RESTRICTED RIGHTS LEGEND * * Use, duplication, or disclosure by the government is subject to * restriction as set forth in paragraph (b)(3)(b) of the Rights in * Technical Data and Computer Software clause in DAR 7-104.9(a). * * See http://www.pixil.org/gpl/ for GPL licensing * information. * * See http://www.pixil.org/license.html or * email cetsales@centurysoftware.com for information about the PIXIL * Commercial License Agreement, or if any conditions of this licensing * are not clear to you. */#include <pixil_config.h>#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <time.h>#include <getopt.h>#ifdef CONFIG_PAR#include <par/par.h>#endif#define MWINCLUDECOLORS#include "nano-X.h"#include "nxsnake.h"#include "text.h"#include "levels.h"#define BGCOLOR WHITE#define FGCOLOR (GR_RGB(0x00, 0x66, 0xCC))#define TXTCOLOR BLACKstatic GR_WINDOW_ID tileset_pixmap = 0;static GR_REGION_ID level_clipmask = 0;static int draw_fullscreen = 1;/* This matrix indicates where the snake, border and nibbles are *//* This is how the engine determines where the snake, nibbles and *//* borders are */unsigned char playground[YUNITS][XUNITS];snake_t global_snake;GR_WINDOW_ID swindow, offscreen;static int game_state = 0;static int current_level = 0;#define SNAKE_START_SPEED 110static unsigned long game_speed;static unsigned long start_speed = SNAKE_START_SPEED;struct{ int active; int x; int y;}nibble;int skipped = 0;#define MOVE_ILLEGAL 0#define MOVE_LEGAL 1#define MOVE_NIBBLE 2inline voidSET_SNAKE_DIRECTION(unsigned short *value, unsigned char dir){ *value &= 0x0FFF; *value |= ((dir & 0xF) << 12);}inline voidSET_SNAKE_OFFSET(unsigned short *value, unsigned short off){ *value &= 0xF000; *value |= (off & 0xFFF);}voidload_tileset(char *file){ char path[256]; GR_GC_ID gc = GrNewGC();#ifdef CONFIG_PAR db_handle *par_db = db_openDB(db_getDefaultDB(), PAR_DB_MODE_RDONLY); if (par_db) { par_getScreentopDir(par_db, "icondir", path, sizeof(path) - 1); db_closeDB(par_db); strcat(path, "/"); strcat(path, file); } else#endif { getcwd(path, 128); strcat(path, "/"); strcat(path, file); } tileset_pixmap = GrNewPixmap(XUNITSIZE * TILE_COUNT, YUNITSIZE, 0); GrDrawImageFromFile(tileset_pixmap, gc, 0, 0, XUNITSIZE * TILE_COUNT, YUNITSIZE, path, 0); GrDestroyGC(gc);}voiddraw_tile(int tile, int x, int y){ GR_GC_ID gc = GrNewGC(); GrCopyArea(offscreen, gc, x, y, XUNITSIZE, YUNITSIZE, tileset_pixmap, tile * XUNITSIZE, 0, MWROP_SRCCOPY); GrDestroyGC(gc);}voidinit_level(int l){ global_snake.speed = 1; global_snake.headx = level[l].startx; global_snake.heady = level[l].starty; global_snake.tailpointer = 0; global_snake.length = 5; global_snake.growth = 0; bzero(global_snake.body, 256 * sizeof(unsigned short)); SET_SNAKE_DIRECTION(&global_snake.body[0], level[l].dir); SET_SNAKE_OFFSET(&global_snake.body[0], global_snake.length);}intadvance_snake(void){ unsigned short netoff = 0; int pos = 0; unsigned char dir; unsigned short off; short newx; short newy; int ret; if (!global_snake.body[0]) return (MOVE_LEGAL); dir = GET_SNAKE_DIRECTION(global_snake.body[0]); newx = global_snake.headx; newy = global_snake.heady; switch (dir) { case SNAKE_DIR_LEFT: newx = global_snake.headx - 1; if (newx < 0) newx = XUNITS - 1; break; case SNAKE_DIR_RIGHT: newx = global_snake.headx + 1; if (newx >= XUNITS) newx = 0; break; case SNAKE_DIR_UP: newy = global_snake.heady - 1; if (newy < 0) newy = YUNITS - 1; break; case SNAKE_DIR_DOWN: newy = global_snake.heady + 1; if (newy >= YUNITS) newy = 0; break; } /* Now check the new position */ switch (playground[newy][newx]) { case PLAYGROUND_EMPTY: case PLAYGROUND_TAIL: ret = MOVE_LEGAL; break; case PLAYGROUND_BORDER: case PLAYGROUND_SNAKE: return (MOVE_ILLEGAL); case PLAYGROUND_NIBBLE: /* Yummy... */ global_snake.growth += 5; global_snake.score++; game_speed--; nibble.active = 0; ret = MOVE_NIBBLE; break; } /* Now advance the head. That means advancing the absolute x and y */ /* and adding one to the current offset */ global_snake.headx = newx; global_snake.heady = newy; /* Finally, handle the tail */ /* If we are growing, then handle that here (the tail doesn't move) */ if (global_snake.growth) { global_snake.growth--; global_snake.length++; off = GET_SNAKE_OFFSET(global_snake.body[0]); SET_SNAKE_OFFSET(&global_snake.body[0], off + 1); return (ret); } /* If there is only one segment, then handle that here */ if (!global_snake.tailpointer) { SET_SNAKE_OFFSET(&global_snake.body[0], global_snake.length); return (ret); } /* Otherwise, we need to move the whole snake */ off = GET_SNAKE_OFFSET(global_snake.body[0]); SET_SNAKE_OFFSET(&global_snake.body[0], off + 1); while (global_snake.body[pos]) { off = GET_SNAKE_OFFSET(global_snake.body[pos]); /* If the size ends here, then clear the rest of the */ /* snake */ if (netoff + off >= global_snake.length) { if (global_snake.tailpointer > pos + 1) printf ("OOPS! You have a gap between the length and the tail\n"); global_snake.body[pos + 1] = 0; global_snake.tailpointer = pos; SET_SNAKE_OFFSET(&global_snake.body[pos], global_snake.length - netoff); break; } netoff += off; pos++; } return (ret);}intredirect_snake(GR_EVENT_KEYSTROKE event){ unsigned char newdir = 0; int i = 0; unsigned char dir = GET_SNAKE_DIRECTION(global_snake.body[0]); switch (event.ch) { case MWKEY_UP: case MWKEY_KP8: newdir = SNAKE_DIR_UP; break; case MWKEY_DOWN: case MWKEY_KP2: newdir = SNAKE_DIR_DOWN; break; case MWKEY_LEFT: case MWKEY_KP4: newdir = SNAKE_DIR_LEFT; break; case MWKEY_RIGHT: case MWKEY_KP6: newdir = SNAKE_DIR_RIGHT; break; default: return (0); } if (dir == newdir) return (0); if (dir == SNAKE_DIR_LEFT && newdir == SNAKE_DIR_RIGHT) return (0); if (dir == SNAKE_DIR_RIGHT && newdir == SNAKE_DIR_LEFT) return (0); if (dir == SNAKE_DIR_UP && newdir == SNAKE_DIR_DOWN) return (0); if (dir == SNAKE_DIR_DOWN && newdir == SNAKE_DIR_UP) return (0); for (i = global_snake.tailpointer + 1; i > 0; i--) global_snake.body[i] = global_snake.body[i - 1]; global_snake.tailpointer++; SET_SNAKE_DIRECTION(&global_snake.body[0], newdir); SET_SNAKE_OFFSET(&global_snake.body[0], 0); /* No bounds checking, that will be done on the next advance */ return (1);}voidshow_buffer(void){ GR_GC_ID gc = GrNewGC();#ifdef NOTUSED if (draw_fullscreen == 0 && level_clipmask) GrSetGCRegion(gc, level_clipmask);#endif GrCopyArea(swindow, gc, 0, 0, WWIDTH, WHEIGHT, offscreen, 0, 0, MWROP_SRCCOPY); GrDestroyGC(gc);}voiddraw_string(char *array, int mode){ char *txtptr = array; int xpos, ypos; int maxwidth = 0, maxheight = 0; int i = 0; int count = 0; GR_GC_ID gc = GrNewGC(); GR_FONT_ID font = GrCreateFont((GR_CHAR *) GR_FONT_GUI_VAR, 0, 0); GrSetGCFont(gc, font); /* Count how many lines we have */ while (txtptr) { int tw, th, tb; if (strlen(txtptr) == 0) break; GrGetGCTextSize(gc, txtptr, -1, 0, &tw, &th, &tb); if (maxwidth < tw) maxwidth = tw; if (maxheight < th) maxheight = th; txtptr += 50; count++; } txtptr = array; maxwidth += 10; maxheight += 10; /* mode == 1, clear the screen, mode == 2, draw a box */ if (mode == 1) { GrSetGCForeground(gc, BGCOLOR); GrFillRect(offscreen, gc, 0, 0, WWIDTH, WHEIGHT); GrSetGCForeground(gc, TXTCOLOR); GrSetGCBackground(gc, BGCOLOR); } else { xpos = (PWIDTH / 2) - (maxwidth / 2); ypos = (PHEIGHT / 2) - ((count * maxheight) / 2); /* Draw a box */ GrSetGCForeground(gc, FGCOLOR); GrFillRect(offscreen, gc, xpos, ypos, maxwidth, (count * maxheight)); GrSetGCForeground(gc, BGCOLOR); GrRect(offscreen, gc, xpos + 3, ypos + 3, maxwidth - 6, (count * maxheight) - 6); GrSetGCBackground(gc, FGCOLOR); } ypos = (WHEIGHT / 2) - ((count * maxheight) / 2) + 5; while (1) { int tw, th, tb; if (strlen(txtptr) == 0) break; GrGetGCTextSize(gc, txtptr, -1, 0, &tw, &th, &tb); GrText(offscreen, gc, (WWIDTH / 2) - (tw / 2), ypos + (i * th), txtptr, -1, 0); i++; txtptr += 50; } GrDestroyGC(gc); GrDestroyFont(font);}/* Make a region that should clip out border */voidmake_clipmask(int l){ unsigned char *ptr = level[l].bitmap; GR_RECT rect; int x, y; if (level_clipmask) GrDestroyRegion(level_clipmask); level_clipmask = GrNewRegion(); for (y = 0; y < YUNITS; y++) { int state = 0; for (x = 0; x < XUNITS; x++) { if (*ptr != PLAYGROUND_BORDER && !state) { rect.x = (x * XUNITSIZE); rect.y = (y * YUNITSIZE); rect.height = YUNITSIZE; state = 1; } if (*ptr == PLAYGROUND_BORDER && state) { rect.width = (x * XUNITSIZE) - rect.x; GrUnionRectWithRegion(level_clipmask, &rect); state = 0; } ptr++; } if (state) { rect.width = (x * XUNITSIZE) - rect.x; GrUnionRectWithRegion(level_clipmask, &rect); } }}voiddraw_screen(int full){ int bstart, bend; int x = 0, y = 0; GR_GC_ID gc = GrNewGC(); /* Avoid drawing the background if we don't need to */ if (draw_fullscreen == 0 && level_clipmask) { GrSetGCRegion(gc, level_clipmask); } for (y = 0; y < YUNITS; y++) { bstart = -1; bend = 0; for (x = 0; x < XUNITS; x++) { if (playground[y][x] == PLAYGROUND_EMPTY) { if (bstart == -1) bend = bstart = x; else bend++; continue; } /* Draw the background block */ if (bstart != -1) { GrSetGCForeground(gc, BGCOLOR); GrFillRect(offscreen, gc, (bstart * XUNITSIZE), (y * YUNITSIZE), (bend - bstart + 1) * XUNITSIZE, YUNITSIZE); skipped += (bend - bstart); bstart = -1; bend = 0; } if (!full && playground[y][x] == PLAYGROUND_BORDER) continue; switch (playground[y][x]) { case PLAYGROUND_BORDER: draw_tile(TILE_BORDER, (x * XUNITSIZE), (y * YUNITSIZE)); /* GrSetGCForeground(gc, BLUE); */ break; case PLAYGROUND_SNAKE: case PLAYGROUND_TAIL: draw_tile(TILE_SNAKE, (x * XUNITSIZE), (y * YUNITSIZE)); /* GrSetGCForeground(gc, RED); */ break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -