Mercurial > hg > index.fcgi > lj > lj046
diff src/lj.h @ 0:c84446dfb3f5
initial add
author | paulo@localhost |
---|---|
date | Fri, 13 Mar 2009 00:39:12 -0700 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/lj.h Fri Mar 13 00:39:12 2009 -0700 1.3 @@ -0,0 +1,507 @@ 1.4 +/* Header file for the engine of LOCKJAW, an implementation of the Soviet Mind Game 1.5 + 1.6 +Copyright (C) 2006 Damian Yerrick <tepples+lj@spamcop.net> 1.7 + 1.8 +This work is free software; you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation; either version 2 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with this program; if not, write to the Free Software 1.20 +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1.21 + 1.22 +Original game concept and design by Alexey Pajitnov. 1.23 +The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg, 1.24 +or The Tetris Company LLC. 1.25 + 1.26 +*/ 1.27 + 1.28 +#ifndef LJ_H 1.29 +#define LJ_H 1.30 + 1.31 +#include <stdlib.h> 1.32 +#include "ljtypes.h" 1.33 + 1.34 +enum { 1.35 + CONNECT_U = 0x01, 1.36 + CONNECT_R = 0x02, 1.37 + CONNECT_D = 0x04, 1.38 + CONNECT_L = 0x08, 1.39 + CONNECT_UD = CONNECT_U | CONNECT_D, 1.40 + CONNECT_UL = CONNECT_U | CONNECT_L, 1.41 + CONNECT_DL = CONNECT_D | CONNECT_L, 1.42 + CONNECT_UR = CONNECT_U | CONNECT_R, 1.43 + CONNECT_DR = CONNECT_D | CONNECT_R, 1.44 + CONNECT_LR = CONNECT_L | CONNECT_R, 1.45 + CONNECT_UDL = CONNECT_UD | CONNECT_L, 1.46 + CONNECT_UDR = CONNECT_UD | CONNECT_R, 1.47 + CONNECT_ULR = CONNECT_UL | CONNECT_R, 1.48 + CONNECT_DLR = CONNECT_DL | CONNECT_R, 1.49 + CONNECT_UDLR = CONNECT_UD | CONNECT_LR, 1.50 + CONNECT_MASK = CONNECT_UDLR, 1.51 + COLOR_MASK = 0xF0 1.52 +}; 1.53 + 1.54 +typedef unsigned char LJBlock; 1.55 + 1.56 +typedef enum LJState { 1.57 + LJS_INACTIVE, 1.58 + LJS_NEW_PIECE, /* delay is ARE */ 1.59 + LJS_FALLING, /* delay is fall delay; NOT IMPLEMENTED */ 1.60 + LJS_LANDED, /* delay is lock delay */ 1.61 + LJS_LINES, /* delay is line delay */ 1.62 + LJS_LINES_FALLING, /* delay is fall delay per line; NOT IMPLEMENTED */ 1.63 + LJS_GAMEOVER, /* game over animation */ 1.64 + LJS_EXPLODE /* used for bombliss extension */ 1.65 +} LJState; 1.66 + 1.67 +// for other 1.68 +enum { 1.69 + LJI_HOLD = 0x01, 1.70 + LJI_LOCK = 0x02 1.71 +}; 1.72 + 1.73 +// for dirty bits 1.74 +enum { 1.75 + LJ_DIRTY_NEXT = 0x01000000, 1.76 + LJ_DIRTY_SCORE = 0x02000000 1.77 +}; 1.78 + 1.79 +// for gimmick (game mode) 1.80 +enum { 1.81 + LJGM_ATYPE, // marathon 1.82 + LJGM_BTYPE, // 40 lines 1.83 + LJGM_ULTRA, // 180 seconds 1.84 + LJGM_DRILL, // clear bottom line 1.85 + LJGM_ITEMS, // no rotation + no next + fast drop + garbage + banana 1.86 + LJGM_BABY, // 300 keypresses 1.87 + LJGM_N_GIMMICKS 1.88 +}; 1.89 + 1.90 +enum { 1.91 + LJP_I = 0, 1.92 + LJP_J, 1.93 + LJP_L, 1.94 + LJP_O, 1.95 + LJP_S, 1.96 + LJP_T, 1.97 + LJP_Z, 1.98 + LJP_I2, 1.99 + LJP_I3, 1.100 + LJP_L3, 1.101 + LJP_GARBAGE = 7, 1.102 + LJP_MASK = 0x0F 1.103 +}; 1.104 + 1.105 +enum { 1.106 + LJSND_ROTATE = 0x0001, 1.107 + LJSND_SHIFT = 0x0002, 1.108 + LJSND_DROP = 0x0004, 1.109 + LJSND_LAND = 0x0008, 1.110 + LJSND_LOCK = 0x0010, 1.111 + LJSND_LINE = 0x0020, // a line was scored 1.112 + LJSND_SETB2B = 0x0040, // this line is b2b worthy (tetris or t-spin) 1.113 + LJSND_B2B = 0x0080, // this line AND last line were b2b worthy 1.114 + LJSND_SPAWN = 0x0100, // next piece was moved up 1.115 + LJSND_HOLD = 0x0200, // hold piece was activated 1.116 + LJSND_IRS = 0x0400, // initial rotation: spawn last frame and rotation this frame 1.117 + LJSND_SQUARE = 0x0800, // formed 4x4 square 1.118 + LJSND_COUNTDOWN = 0x4000, // countdown value changed 1.119 + LJSND_SECTIONUP = 0x8000, // section increased 1.120 +}; 1.121 + 1.122 +enum { 1.123 + LJRAND_PURE, 1.124 + LJRAND_BAG, 1.125 + LJRAND_BAGPLUS1, 1.126 + LJRAND_2BAG, 1.127 + LJRAND_HIST_INF, 1.128 + LJRAND_HIST_6, 1.129 + LJRAND_N_RANDS 1.130 +}; 1.131 + 1.132 +enum { 1.133 + LJRAND_4BLK, 1.134 + LJRAND_JLOSTZ, 1.135 + LJRAND_SZ, 1.136 + LJRAND_I, 1.137 + LJRAND_234BLK, 1.138 + LJRAND_T, 1.139 + LJRAND_N_PIECE_SETS 1.140 +}; 1.141 + 1.142 +enum { 1.143 + LJTS_OFF = 0, 1.144 + LJTS_TNT, 1.145 + LJTS_TDS, 1.146 + LJTS_TDS_NO_KICK, 1.147 + LJTS_N_ALGOS 1.148 +}; 1.149 + 1.150 +enum { 1.151 + LJSPD_ZERO = 0, 1.152 + LJSPD_RHYTHMZERO, 1.153 + LJSPD_EXP, 1.154 + LJSPD_RHYTHM, 1.155 + LJSPD_TGM, 1.156 + LJSPD_DEATH, 1.157 + LJSPD_DEATH300, 1.158 + LJSPD_NES, 1.159 + LJSPD_GB, 1.160 + LJSPD_GBHEART, 1.161 + LJSPD_N_CURVES 1.162 +}; 1.163 + 1.164 +enum { 1.165 + LJLOCK_NOW = 0, 1.166 + LJLOCK_SPAWN, 1.167 + LJLOCK_STEP, 1.168 + LJLOCK_MOVE, 1.169 + LJLOCK_N_STYLES 1.170 +}; 1.171 + 1.172 +enum { 1.173 + LJGRAV_NAIVE = 0, 1.174 + LJGRAV_STICKY, 1.175 + LJGRAV_STICKY_BY_COLOR, 1.176 + LJGRAV_CASCADE, 1.177 + LJGRAV_N_ALGOS 1.178 +}; 1.179 + 1.180 +enum { 1.181 + LJSCORE_LJ, 1.182 + LJSCORE_TNT64, 1.183 + LJSCORE_HOTLINE, 1.184 + LJSCORE_TDS, 1.185 + LJSCORE_NES, 1.186 + LJSCORE_LJ_NERF, 1.187 + LJSCORE_N_STYLES, 1.188 + LJSCORE_WORLDS, 1.189 + LJSCORE_TGM1, 1.190 + LJSCORE_IPOD 1.191 +}; 1.192 + 1.193 +enum { 1.194 + LJDROP_NOSCORE, 1.195 + LJDROP_NES, 1.196 + LJDROP_1CELL, 1.197 + LJDROP_1S_2H, 1.198 + LJDROP_N_STYLES 1.199 +}; 1.200 + 1.201 +enum { 1.202 + LJGARBAGE_NONE, 1.203 + LJGARBAGE_1, 1.204 + LJGARBAGE_2, 1.205 + LJGARBAGE_3, 1.206 + LJGARBAGE_4, 1.207 + LJGARBAGE_HRDERBY, 1.208 + LJGARBAGE_DRILL, 1.209 + LJGARBAGE_ZIGZAG, 1.210 + 1.211 + LJGARBAGE_N_STYLES 1.212 +}; 1.213 + 1.214 +enum { 1.215 + LJHOLD_NONE, 1.216 + LJHOLD_EMPTY, 1.217 + LJHOLD_TNT, 1.218 + LJHOLD_TO_NEXT, 1.219 + LJHOLD_N_STYLES 1.220 +}; 1.221 + 1.222 +enum { 1.223 + LJGLUING_NONE, 1.224 + LJGLUING_SQUARE, 1.225 + LJGLUING_STICKY, 1.226 + LJGLUING_STICKY_BY_COLOR, 1.227 + LJGLUING_N_STYLES 1.228 +}; 1.229 + 1.230 +// Guideline says 10 wide, but we want to support tetrinet mode 1.231 +#define LJ_PF_WID ((size_t)12) 1.232 +#define LJ_SPAWN_X ((LJ_PF_WID - 3) / 2) 1.233 +#define LJ_PF_HT ((size_t)24) 1.234 +#define LJ_PF_VIS_HT ((size_t)20) 1.235 +#define LJ_NEXT_PIECES 8 1.236 +#define LJ_MAX_LINES_PER_PIECE 8 1.237 + 1.238 +typedef struct LJBlkSpec 1.239 +{ 1.240 + signed char x, y, conn, reserved; 1.241 +} LJBlkSpec; 1.242 + 1.243 +typedef struct LJInput { 1.244 + signed char rotation, movement; 1.245 + unsigned char gravity; /* 5.3 format */ 1.246 + unsigned char other; 1.247 +} LJInput; 1.248 + 1.249 +typedef struct LJSpeedSetting { 1.250 + LJFixed gravity; 1.251 + unsigned char entryDelay, dasDelay, lockDelay, lineDelay; 1.252 +} LJSpeedSetting; 1.253 + 1.254 +typedef struct SpeedStateBase { 1.255 + unsigned char curve, section; 1.256 + unsigned char pad[2]; 1.257 + signed int level; 1.258 +} SpeedStateBase; 1.259 + 1.260 +#define MAX_BAG_LEN 10 1.261 +#define MAX_OMINO 4 1.262 + 1.263 +typedef struct LJField 1.264 +{ 1.265 + /* Game state */ 1.266 + LJBlock b[LJ_PF_HT][LJ_PF_WID]; 1.267 + LJBlock c[LJ_PF_HT][LJ_PF_WID]; 1.268 + LJBits clearedLines; 1.269 + LJBits sounds; 1.270 + LJBits tempRows; 1.271 + unsigned char curPiece[1 + LJ_NEXT_PIECES]; 1.272 + signed char permuPiece[2 * MAX_BAG_LEN], permuPhase; 1.273 + unsigned short nLineClears[LJ_MAX_LINES_PER_PIECE]; // [n-1] = # of n-line clears 1.274 + LJFixed y; 1.275 + LJState state; 1.276 + signed char stateTime; 1.277 + unsigned char theta; 1.278 + signed char x; 1.279 + signed char hardDropY; 1.280 + char alreadyHeld; 1.281 + char isSpin; 1.282 + char nLinesThisPiece; 1.283 + char canRotate; 1.284 + unsigned char upwardKicks; 1.285 + 1.286 + /* Persist from piece to piece */ 1.287 + int score, lines; 1.288 + unsigned int gameTime; // number of frames 1.289 + unsigned int activeTime; // number of frames 1.290 + signed short holdPiece; 1.291 + char chain; 1.292 + signed char garbage; 1.293 + unsigned char dropDist; 1.294 + unsigned char garbageX; 1.295 + unsigned short nPieces, outGarbage; 1.296 + unsigned short monosquares, multisquares; 1.297 + 1.298 + /* Determined by gimmick */ 1.299 + signed char gimmick; 1.300 + signed int bpmCounter; 1.301 + unsigned int speedupCounter; 1.302 + unsigned int goalCount; 1.303 + unsigned int seed; 1.304 + unsigned char goalType; 1.305 + 1.306 + LJSpeedSetting speed; 1.307 + SpeedStateBase speedState; 1.308 + 1.309 + unsigned char lockReset; // lockdown reset rule type 1.310 + unsigned char areStyle; 1.311 + unsigned char setLockDelay; // Overridden lock delay (255 = never) 1.312 + unsigned char setLineDelay; // Overridden line delay 1.313 + unsigned char garbageStyle; 1.314 + unsigned char ceiling; 1.315 + unsigned char enterAbove; 1.316 + unsigned char leftWall, rightWall; 1.317 + unsigned char pieceSet; 1.318 + unsigned char randomizer; 1.319 + unsigned char rotationSystem; 1.320 + unsigned char garbageRandomness; // 64: change garbageX in 1/4 of rows; 255: change all 1.321 + unsigned char tSpinAlgo; // 0: off, 1: TNT, 2: TDS 1.322 + unsigned char clearGravity; 1.323 + unsigned char gluing; // 0: off; 1: square 1.324 + unsigned char scoreStyle; 1.325 + unsigned char dropScoreStyle; 1.326 + unsigned char maxUpwardKicks; 1.327 + unsigned char holdStyle; 1.328 + unsigned char bottomBlocks; 1.329 + unsigned char reloaded; // 0: played through; 1: reloaded from saved state 1.330 +} LJField; 1.331 + 1.332 +/** 1.333 + * Names of the supported rotation systems (wktables.c). 1.334 + */ 1.335 +enum { 1.336 + LJROT_SRS, 1.337 + LJROT_SEGA, 1.338 + LJROT_ARIKA, 1.339 + LJROT_ATARI, 1.340 + LJROT_NES, 1.341 + LJROT_GB, 1.342 + LJROT_TOD, 1.343 + LJROT_TDX, 1.344 + N_ROTATION_SYSTEMS 1.345 +}; 1.346 + 1.347 +#define N_PIECE_SHAPES 10 1.348 +#define KICK_TABLE_LEN 5 1.349 +extern const char pieceColors[N_PIECE_SHAPES]; 1.350 +typedef unsigned char WallKickTable[4][KICK_TABLE_LEN]; 1.351 +typedef struct LJRotSystem { 1.352 + /** 1.353 + * Color scheme for this rotation system (0: SRS; 1: Sega) 1.354 + * Use colorset 0 (SRS) if all free-space kicks are WK(0, 0). 1.355 + * Otherwise, your rotation system has what Eddie Rogers has called 1.356 + * a topknot, and you should use Sega colors. 1.357 + */ 1.358 + unsigned char colorScheme; 1.359 + unsigned char reserved1[3]; 1.360 + unsigned char entryOffset[N_PIECE_SHAPES]; 1.361 + unsigned char entryTheta[N_PIECE_SHAPES]; 1.362 + /* These control which kick table is used for each piece. 1.363 + * If negative, no kick table is present. 1.364 + */ 1.365 + signed char kicksL[N_PIECE_SHAPES]; 1.366 + signed char kicksR[N_PIECE_SHAPES]; 1.367 + WallKickTable kickTables[]; 1.368 +} LJRotSystem; 1.369 + 1.370 +extern const LJRotSystem *const rotSystems[N_ROTATION_SYSTEMS]; 1.371 + 1.372 +#ifdef LJ_INTERNAL 1.373 + // Used for defining wall kick tables: 1.374 + // WK(x, y) builds a 1-byte record with 2 coordinates, at 4 bits 1.375 + // per coordinate. 1.376 + // WKX() and WKY() retrieve the X or Y coordinate from this record. 1.377 + // The ((stuff ^ 8) - 8) is sign extension magick 1.378 + #define WK(x, y) (((x) & 0x0F) | ((y) & 0x0F) << 4) 1.379 + #define WKX(wk) ((((wk) & 0x0F) ^ 8) - 8) 1.380 + #define WKY(wk) WKX((wk) >> 4) 1.381 + // If ARIKA_IF_NOT_CENTER is specified, check the free space 1.382 + // rotation for blocks in columns other than 1, and stop if 1.383 + // none of them are filled. This obsoletes the old SKIP_IF. 1.384 + #define SKIP_IF 0x80 1.385 + #define SKIP_IF3 0x82 1.386 + 1.387 + #define ARIKA_IF_NOT_CENTER 0x83 1.388 + #define WK_END 0x8F 1.389 +#if 0 1.390 + extern const WallKickTable *const wkTablesL[N_ROTATION_SYSTEMS][N_PIECE_SHAPES]; 1.391 + extern const WallKickTable *const wkTablesR[N_ROTATION_SYSTEMS][N_PIECE_SHAPES]; 1.392 +#endif 1.393 +#endif 1.394 + 1.395 +/** 1.396 + * Expands a tetromino to the blocks that make it up. 1.397 + * @param out an array of length 4 1.398 + * @param p the field into which the tetromino will be spawned 1.399 + * (used for default spawn orientation) 1.400 + * @param piece a piece number 1.401 + * @param xBase x coordinate of base position of the tetromino 1.402 + * @param yBase y coordinate of base position of the tetromino 1.403 + * @param theta the orientation of the tetromino 1.404 + * (0-3: use this; 4: use default spawn rotation) 1.405 + */ 1.406 +void expandPieceToBlocks(LJBlkSpec out[], 1.407 + const LJField *p, 1.408 + int piece, int xBase, int yBase, int theta); 1.409 + 1.410 +/** 1.411 + * Tests whether a particular block is occupied. 1.412 + * @param p the playfield 1.413 + * @param x the column 1.414 + * @param y the row (0 = bottom) 1.415 + * @return zero iff the space is open 1.416 + */ 1.417 +int isOccupied(const LJField *p, int x, int y); 1.418 + 1.419 +/** 1.420 + * Tests whether a particular tetromino would overlap one or more 1.421 + * blocks, a side wall, or the floor 1.422 + * @param p the playfield 1.423 + * @param x the column of the left side of the piece's bounding 4x4 1.424 + * @param y the row of the bottom of the piece's bounding 4x4 (0 = bottom) 1.425 + * @return zero iff the space is open 1.426 + */ 1.427 +int isCollision(const LJField *p, int x, int y, int theta); 1.428 + 1.429 +/** 1.430 + * Blanks a playfield and prepares it for a new game. 1.431 + * @param p the playfield 1.432 + */ 1.433 +void newGame(LJField *p); 1.434 + 1.435 +/** 1.436 + * Runs one frame of S.M.G. 1.437 + * @param p the playfield 1.438 + * @param in the player's input 1.439 + * @return the rows that were modified 1.440 + */ 1.441 +LJBits frame(LJField *p, const LJInput *in); 1.442 + 1.443 +/** 1.444 + * Applies gimmicks to a new game. 1.445 + * @param p the playfield 1.446 + * @param in the player's input 1.447 + */ 1.448 +void initGimmicks(LJField *p); 1.449 + 1.450 +/** 1.451 + * Runs gimmicks for one frame of S.M.G. 1.452 + * @param p the playfield 1.453 + * @param c the control settings 1.454 + * @return the rows that were modified 1.455 + */ 1.456 +struct LJControl; 1.457 +LJBits gimmicks(LJField *p, struct LJControl *c); 1.458 + 1.459 +/** 1.460 + * Sets up the randomizer. 1.461 + * @return the number of this piece 1.462 + */ 1.463 +void initRandomize(LJField *p); 1.464 + 1.465 +/** 1.466 + * Chooses a pseudo-random piece. 1.467 + * @param the field on which the piece will be generated 1.468 + * @return the number of this piece 1.469 + * (0=i, 1=j, 2=l, 3=o, 4=s, 5=t, 6=z) 1.470 + */ 1.471 +unsigned int randomize(LJField *p); 1.472 + 1.473 +/** 1.474 + * Counts the number of 1 bits in a bitfield. 1.475 + * @param p the bitfield 1.476 + * @return the number of bits in p with a value of 1. 1.477 + */ 1.478 +unsigned int countOnes(LJBits b); 1.479 + 1.480 +/** 1.481 + * Shuffles the columns of blocks in the playfield. 1.482 + * @param p the playfield 1.483 + */ 1.484 +void shuffleColumns(LJField *p); 1.485 + 1.486 +/** 1.487 + * Random number generator. Use this for all random events 1.488 + * that affect the game state. 1.489 + * @param field 1.490 + * @return uniformly distributed number in 0 to 0x7FFF 1.491 + */ 1.492 +unsigned int ljRand(LJField *p); 1.493 + 1.494 +/** 1.495 + * List of lines used for hotline scoring. 1.496 + * A line clear completed at row hotlineRows[i] is worth 100*(i + 1). 1.497 + */ 1.498 +extern const char hotlineRows[LJ_PF_HT]; 1.499 + 1.500 +/** 1.501 + * Counts the number of trailing zero bits on an integer. 1.502 + * For instance, 00000000 00000000 00000001 11111000 1.503 + * has 3 trailing zeroes. 1.504 + */ 1.505 +unsigned int bfffo(LJBits rowBits); 1.506 + 1.507 +void setupZigzagField(LJField *p, size_t height); 1.508 +unsigned int calcZigzagGrade(const LJField *p); 1.509 + 1.510 +#endif