Mercurial > hg > index.fcgi > lj > lj046-2players
diff src/ljreplay.c @ 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/ljreplay.c Fri Mar 13 00:39:12 2009 -0700 1.3 @@ -0,0 +1,335 @@ 1.4 +/* Replay functionality for LOCKJAW, an implementation of the Soviet Mind Game 1.5 + 1.6 +Copyright (C) 2006-2008 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 +#include "ljreplay.h" 1.29 +#include <stdio.h> 1.30 + 1.31 +#define FORMAT_VERSION 0x20080525 1.32 +#define LAST_FORMAT_VERSION 20080420 1.33 +#define DEBUG_OFFSETS 0 1.34 + 1.35 +#if DEBUG_OFFSETS 1.36 +#include <allegro.h> 1.37 +#endif 1.38 + 1.39 +struct LJReplayFrame { 1.40 + char length; 1.41 + char reserved; 1.42 + unsigned short keys; 1.43 + LJInput x; 1.44 +}; 1.45 + 1.46 +struct LJReplay { 1.47 + FILE *file; 1.48 +}; 1.49 + 1.50 +static void fput32(unsigned int src, FILE *dst) { 1.51 + fputc(src >> 24, dst); 1.52 + fputc(src >> 16, dst); 1.53 + fputc(src >> 8, dst); 1.54 + fputc(src, dst); 1.55 +} 1.56 + 1.57 +static unsigned int fget32(FILE *src) { 1.58 + int c0 = fgetc(src) & 0xFF; 1.59 + c0 = (c0 << 8) | (fgetc(src) & 0xFF); 1.60 + c0 = (c0 << 8) | (fgetc(src) & 0xFF); 1.61 + c0 = (c0 << 8) | (fgetc(src) & 0xFF); 1.62 + return c0; 1.63 +} 1.64 +static void fput16(unsigned int src, FILE *dst) { 1.65 + fputc(src >> 8, dst); 1.66 + fputc(src, dst); 1.67 +} 1.68 + 1.69 +static unsigned int fget16(FILE *src) { 1.70 + int c0 = fgetc(src) & 0xFF; 1.71 + c0 = (c0 << 8) | (fgetc(src) & 0xFF); 1.72 + return c0; 1.73 +} 1.74 + 1.75 +static void LJField_serialize(const LJField *p, FILE *fp) { 1.76 + fput32(FORMAT_VERSION, fp); 1.77 + 1.78 + for (int y = 0; y < LJ_PF_HT; ++y) { 1.79 + for (int x = 0; x < LJ_PF_WID; ++x) { 1.80 + fputc(p->b[y][x], fp); 1.81 + } 1.82 + } 1.83 + for (int y = 0; y < LJ_PF_HT; ++y) { 1.84 + for (int x = 0; x < LJ_PF_WID; ++x) { 1.85 + fputc(p->c[y][x], fp); 1.86 + } 1.87 + } 1.88 + fput32(p->clearedLines, fp); 1.89 + fput32(p->sounds, fp); 1.90 + fput32(p->tempRows, fp); 1.91 + for (int y = 0; y < 1 + LJ_NEXT_PIECES; ++y) { 1.92 + fputc(p->curPiece[y], fp); 1.93 + } 1.94 + for (int y = 0; y < 2 * MAX_BAG_LEN; ++y) { 1.95 + fputc(p->permuPiece[y], fp); 1.96 + } 1.97 + fputc(p->permuPhase, fp); 1.98 + for (int y = 0; y < LJ_MAX_LINES_PER_PIECE; ++y) { 1.99 + fput16(p->nLineClears[y], fp); 1.100 + } 1.101 + fput32(p->y, fp); 1.102 + fputc(p->state, fp); 1.103 + fputc(p->stateTime, fp); 1.104 + fputc(p->theta, fp); 1.105 + fputc(p->x, fp); 1.106 + fputc(p->hardDropY, fp); 1.107 + fputc(p->alreadyHeld, fp); 1.108 + fputc(p->isSpin, fp); 1.109 + fputc(p->nLinesThisPiece, fp); 1.110 + fputc(p->canRotate, fp); 1.111 + 1.112 +#if DEBUG_OFFSETS 1.113 + allegro_message("before score, offset = %u\n", (unsigned int)ftell(fp)); 1.114 +#endif 1.115 + fput32(p->score, fp); 1.116 + fput32(p->lines, fp); 1.117 + fput32(p->gameTime, fp); 1.118 + fput32(p->activeTime, fp); 1.119 + fput16(p->holdPiece, fp); 1.120 + fputc(p->chain, fp); 1.121 + fputc(p->garbage, fp); 1.122 + fputc(p->garbageX, fp); 1.123 + fput16(p->nPieces, fp); 1.124 + fput16(p->outGarbage, fp); 1.125 + 1.126 + fputc(p->gimmick, fp); 1.127 + fput32(p->speedState.level, fp); 1.128 + fput32(p->bpmCounter, fp); 1.129 + fput32(p->speedupCounter, fp); 1.130 + fput32(p->goalCount, fp); 1.131 + fput32(p->seed, fp); 1.132 + fput32(p->speed.gravity, fp); 1.133 + fputc(p->speedState.curve, fp); 1.134 + fputc(p->goalType, fp); 1.135 + fputc(p->speed.entryDelay, fp); 1.136 + fputc(p->areStyle, fp); 1.137 + fputc(p->lockReset, fp); 1.138 + fputc(p->speed.lockDelay, fp); 1.139 + fputc(p->speed.lineDelay, fp); 1.140 + fputc(p->ceiling, fp); 1.141 + fputc(p->enterAbove, fp); 1.142 + fputc(p->leftWall, fp); 1.143 + fputc(p->rightWall, fp); 1.144 + fputc(p->pieceSet, fp); 1.145 + fputc(p->randomizer, fp); 1.146 + fputc(p->rotationSystem, fp); 1.147 + fputc(p->garbageRandomness, fp); 1.148 + fputc(p->tSpinAlgo, fp); 1.149 + fputc(p->clearGravity, fp); 1.150 + fputc(p->gluing, fp); 1.151 + fputc(p->scoreStyle, fp); 1.152 + fputc(p->setLockDelay, fp); 1.153 + fputc(p->upwardKicks, fp); 1.154 + fputc(p->maxUpwardKicks, fp); 1.155 + fputc(p->setLineDelay, fp); 1.156 + fputc(p->garbageStyle, fp); 1.157 + fputc(p->holdStyle, fp); 1.158 + fputc(p->bottomBlocks, fp); 1.159 + 1.160 + fput16(p->multisquares, fp); 1.161 + fput16(p->monosquares, fp); 1.162 + 1.163 +#if DEBUG_OFFSETS 1.164 + allegro_message("final offset = %u\n", (unsigned int)ftell(fp)); 1.165 +#endif 1.166 +} 1.167 + 1.168 +static int LJField_deserialize(LJField *p, FILE *fp) { 1.169 + int format = fget32(fp); 1.170 + if (format != FORMAT_VERSION 1.171 + && format != LAST_FORMAT_VERSION) { 1.172 + return -1; 1.173 + } 1.174 + 1.175 + for (int y = 0; y < LJ_PF_HT; ++y) { 1.176 + for (int x = 0; x < LJ_PF_WID; ++x) { 1.177 + p->b[y][x] = fgetc(fp); 1.178 + } 1.179 + } 1.180 + for (int y = 0; y < LJ_PF_HT; ++y) { 1.181 + for (int x = 0; x < LJ_PF_WID; ++x) { 1.182 + p->c[y][x] = fgetc(fp); 1.183 + } 1.184 + } 1.185 + p->clearedLines = fget32(fp); 1.186 + p->sounds = fget32(fp); 1.187 + p->tempRows = fget32(fp); 1.188 + for (int y = 0; y < 1 + LJ_NEXT_PIECES; ++y) { 1.189 + p->curPiece[y] = fgetc(fp); 1.190 + } 1.191 + for (int y = 0; y < 2 * MAX_BAG_LEN; ++y) { 1.192 + p->permuPiece[y] = fgetc(fp); 1.193 + } 1.194 + p->permuPhase = fgetc(fp); 1.195 + for (int y = 0; y < LJ_MAX_LINES_PER_PIECE; ++y) { 1.196 + p->nLineClears[y] = fget16(fp); 1.197 + } 1.198 + p->y = fget32(fp); 1.199 + p->state = fgetc(fp); 1.200 + p->stateTime = fgetc(fp); 1.201 + p->theta = fgetc(fp); 1.202 + p->x = fgetc(fp); 1.203 + p->hardDropY = fgetc(fp); 1.204 + p->alreadyHeld = fgetc(fp); 1.205 + p->isSpin = fgetc(fp); 1.206 + p->nLinesThisPiece = fgetc(fp); 1.207 + p->canRotate = fgetc(fp); 1.208 + 1.209 +#if DEBUG_OFFSETS 1.210 + allegro_message("before score, offset = %u\n", (unsigned int)ftell(fp)); 1.211 +#endif 1.212 + p->score = fget32(fp); 1.213 + p->lines = fget32(fp); 1.214 + p->gameTime = fget32(fp); 1.215 + p->activeTime = fget32(fp); 1.216 + p->holdPiece = fget16(fp); 1.217 + p->chain = fgetc(fp); 1.218 + p->garbage = fgetc(fp); 1.219 + p->garbageX = fgetc(fp); 1.220 + p->nPieces = fget16(fp); 1.221 + p->outGarbage = fget16(fp); 1.222 + 1.223 + p->gimmick = fgetc(fp); 1.224 + p->speedState.level = fget32(fp); 1.225 + p->bpmCounter = fget32(fp); 1.226 + p->speedupCounter = fget32(fp); 1.227 + p->goalCount = fget32(fp); 1.228 + p->seed = fget32(fp); 1.229 + p->speed.gravity = fget32(fp); 1.230 + p->speedState.curve = fgetc(fp); 1.231 + p->goalType = fgetc(fp); 1.232 + p->speed.entryDelay = fgetc(fp); 1.233 + p->areStyle = fgetc(fp); 1.234 + p->lockReset = fgetc(fp); 1.235 + p->speed.lockDelay = fgetc(fp); 1.236 + p->speed.lineDelay = fgetc(fp); 1.237 + p->ceiling = fgetc(fp); 1.238 + p->enterAbove = fgetc(fp); 1.239 + p->leftWall = fgetc(fp); 1.240 + p->rightWall = fgetc(fp); 1.241 + p->pieceSet = fgetc(fp); 1.242 + p->randomizer = fgetc(fp); 1.243 + p->rotationSystem = fgetc(fp); 1.244 + p->garbageRandomness = fgetc(fp); 1.245 + p->tSpinAlgo = fgetc(fp); 1.246 + p->clearGravity = fgetc(fp); 1.247 + p->gluing = fgetc(fp); 1.248 + p->scoreStyle = fgetc(fp); 1.249 + p->setLockDelay = fgetc(fp); 1.250 + p->upwardKicks = fgetc(fp); 1.251 + p->maxUpwardKicks = fgetc(fp); 1.252 + p->setLineDelay = fgetc(fp); 1.253 + p->garbageStyle = fgetc(fp); 1.254 + p->holdStyle = fgetc(fp); 1.255 + p->bottomBlocks = fgetc(fp); 1.256 + 1.257 + if (format == FORMAT_VERSION) { 1.258 + p->multisquares = fget16(fp); 1.259 + p->monosquares = fget16(fp); 1.260 + } 1.261 +#if DEBUG_OFFSETS 1.262 + allegro_message("final offset = %u\n", (unsigned int)ftell(fp)); 1.263 +#endif 1.264 + return 0; 1.265 +} 1.266 + 1.267 + 1.268 +LJReplay *newReplay(const char *filename, LJField *p) { 1.269 + LJReplay *r = malloc(sizeof(struct LJReplay)); 1.270 + 1.271 + if (!r) { 1.272 + return NULL; 1.273 + } 1.274 + r->file = fopen(filename, "wb"); 1.275 + if (!r->file) { 1.276 + free(r); 1.277 + return NULL; 1.278 + } 1.279 + LJField_serialize(p, r->file); 1.280 + return r; 1.281 +} 1.282 + 1.283 +void replayRecord(LJReplay *r, LJBits keys, const LJInput *in) { 1.284 + fputc(0, r->file); 1.285 + fputc(0, r->file); 1.286 + fputc(keys >> 8, r->file); 1.287 + fputc(keys, r->file); 1.288 + fputc(in->rotation, r->file); 1.289 + fputc(in->movement, r->file); 1.290 + fputc(in->gravity, r->file); 1.291 + fputc(in->other, r->file); 1.292 +} 1.293 + 1.294 +LJReplay *openReplay(const char *filename, LJField *p) { 1.295 + LJReplay *r = malloc(sizeof(struct LJReplay)); 1.296 + 1.297 + if (!r) { 1.298 + return NULL; 1.299 + } 1.300 + r->file = fopen(filename, "rb"); 1.301 + if (!r->file) { 1.302 + free(r); 1.303 + return NULL; 1.304 + } 1.305 + 1.306 + /* This deserialization is still NOT robust. */ 1.307 + if (LJField_deserialize(p, r->file) < 0) { 1.308 + fclose(r->file); 1.309 + free(r); 1.310 + return 0; 1.311 + } 1.312 + return r; 1.313 +} 1.314 + 1.315 +int getReplayFrame(LJReplay *r, LJInput *d) { 1.316 + fgetc(r->file); 1.317 + fgetc(r->file); 1.318 + int keys = fgetc(r->file); 1.319 + 1.320 + if (keys == EOF) { 1.321 + return LJREPLAY_EOF; 1.322 + } 1.323 + keys = (keys << 8 & 0xFF) | (fgetc(r->file) & 0xFF); 1.324 + d->rotation = fgetc(r->file); 1.325 + d->movement = fgetc(r->file); 1.326 + d->gravity = fgetc(r->file); 1.327 + d->other = fgetc(r->file); 1.328 + return keys; 1.329 +} 1.330 + 1.331 +void replayClose(LJReplay *r) { 1.332 + if (r) { 1.333 + if (r->file) { 1.334 + fclose(r->file); 1.335 + } 1.336 + free(r); 1.337 + } 1.338 +}