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