Mercurial > hg > index.fcgi > lj > lj046
view src/ljreplay.c @ 3:17286938e22a
change DS alt. rotate key to rotate twice
author | paulo@localhost |
---|---|
date | Wed, 08 Apr 2009 21:50:13 -0700 |
parents | |
children |
line source
1 /* Replay functionality for LOCKJAW, an implementation of the Soviet Mind Game
3 Copyright (C) 2006-2008 Damian Yerrick <tepples+lj@spamcop.net>
5 This work is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 Original game concept and design by Alexey Pajitnov.
20 The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg,
21 or The Tetris Company LLC.
23 */
25 #include "ljreplay.h"
26 #include <stdio.h>
28 #define FORMAT_VERSION 0x20080525
29 #define LAST_FORMAT_VERSION 20080420
30 #define DEBUG_OFFSETS 0
32 #if DEBUG_OFFSETS
33 #include <allegro.h>
34 #endif
36 struct LJReplayFrame {
37 char length;
38 char reserved;
39 unsigned short keys;
40 LJInput x;
41 };
43 struct LJReplay {
44 FILE *file;
45 };
47 static void fput32(unsigned int src, FILE *dst) {
48 fputc(src >> 24, dst);
49 fputc(src >> 16, dst);
50 fputc(src >> 8, dst);
51 fputc(src, dst);
52 }
54 static unsigned int fget32(FILE *src) {
55 int c0 = fgetc(src) & 0xFF;
56 c0 = (c0 << 8) | (fgetc(src) & 0xFF);
57 c0 = (c0 << 8) | (fgetc(src) & 0xFF);
58 c0 = (c0 << 8) | (fgetc(src) & 0xFF);
59 return c0;
60 }
61 static void fput16(unsigned int src, FILE *dst) {
62 fputc(src >> 8, dst);
63 fputc(src, dst);
64 }
66 static unsigned int fget16(FILE *src) {
67 int c0 = fgetc(src) & 0xFF;
68 c0 = (c0 << 8) | (fgetc(src) & 0xFF);
69 return c0;
70 }
72 static void LJField_serialize(const LJField *p, FILE *fp) {
73 fput32(FORMAT_VERSION, fp);
75 for (int y = 0; y < LJ_PF_HT; ++y) {
76 for (int x = 0; x < LJ_PF_WID; ++x) {
77 fputc(p->b[y][x], fp);
78 }
79 }
80 for (int y = 0; y < LJ_PF_HT; ++y) {
81 for (int x = 0; x < LJ_PF_WID; ++x) {
82 fputc(p->c[y][x], fp);
83 }
84 }
85 fput32(p->clearedLines, fp);
86 fput32(p->sounds, fp);
87 fput32(p->tempRows, fp);
88 for (int y = 0; y < 1 + LJ_NEXT_PIECES; ++y) {
89 fputc(p->curPiece[y], fp);
90 }
91 for (int y = 0; y < 2 * MAX_BAG_LEN; ++y) {
92 fputc(p->permuPiece[y], fp);
93 }
94 fputc(p->permuPhase, fp);
95 for (int y = 0; y < LJ_MAX_LINES_PER_PIECE; ++y) {
96 fput16(p->nLineClears[y], fp);
97 }
98 fput32(p->y, fp);
99 fputc(p->state, fp);
100 fputc(p->stateTime, fp);
101 fputc(p->theta, fp);
102 fputc(p->x, fp);
103 fputc(p->hardDropY, fp);
104 fputc(p->alreadyHeld, fp);
105 fputc(p->isSpin, fp);
106 fputc(p->nLinesThisPiece, fp);
107 fputc(p->canRotate, fp);
109 #if DEBUG_OFFSETS
110 allegro_message("before score, offset = %u\n", (unsigned int)ftell(fp));
111 #endif
112 fput32(p->score, fp);
113 fput32(p->lines, fp);
114 fput32(p->gameTime, fp);
115 fput32(p->activeTime, fp);
116 fput16(p->holdPiece, fp);
117 fputc(p->chain, fp);
118 fputc(p->garbage, fp);
119 fputc(p->garbageX, fp);
120 fput16(p->nPieces, fp);
121 fput16(p->outGarbage, fp);
123 fputc(p->gimmick, fp);
124 fput32(p->speedState.level, fp);
125 fput32(p->bpmCounter, fp);
126 fput32(p->speedupCounter, fp);
127 fput32(p->goalCount, fp);
128 fput32(p->seed, fp);
129 fput32(p->speed.gravity, fp);
130 fputc(p->speedState.curve, fp);
131 fputc(p->goalType, fp);
132 fputc(p->speed.entryDelay, fp);
133 fputc(p->areStyle, fp);
134 fputc(p->lockReset, fp);
135 fputc(p->speed.lockDelay, fp);
136 fputc(p->speed.lineDelay, fp);
137 fputc(p->ceiling, fp);
138 fputc(p->enterAbove, fp);
139 fputc(p->leftWall, fp);
140 fputc(p->rightWall, fp);
141 fputc(p->pieceSet, fp);
142 fputc(p->randomizer, fp);
143 fputc(p->rotationSystem, fp);
144 fputc(p->garbageRandomness, fp);
145 fputc(p->tSpinAlgo, fp);
146 fputc(p->clearGravity, fp);
147 fputc(p->gluing, fp);
148 fputc(p->scoreStyle, fp);
149 fputc(p->setLockDelay, fp);
150 fputc(p->upwardKicks, fp);
151 fputc(p->maxUpwardKicks, fp);
152 fputc(p->setLineDelay, fp);
153 fputc(p->garbageStyle, fp);
154 fputc(p->holdStyle, fp);
155 fputc(p->bottomBlocks, fp);
157 fput16(p->multisquares, fp);
158 fput16(p->monosquares, fp);
160 #if DEBUG_OFFSETS
161 allegro_message("final offset = %u\n", (unsigned int)ftell(fp));
162 #endif
163 }
165 static int LJField_deserialize(LJField *p, FILE *fp) {
166 int format = fget32(fp);
167 if (format != FORMAT_VERSION
168 && format != LAST_FORMAT_VERSION) {
169 return -1;
170 }
172 for (int y = 0; y < LJ_PF_HT; ++y) {
173 for (int x = 0; x < LJ_PF_WID; ++x) {
174 p->b[y][x] = fgetc(fp);
175 }
176 }
177 for (int y = 0; y < LJ_PF_HT; ++y) {
178 for (int x = 0; x < LJ_PF_WID; ++x) {
179 p->c[y][x] = fgetc(fp);
180 }
181 }
182 p->clearedLines = fget32(fp);
183 p->sounds = fget32(fp);
184 p->tempRows = fget32(fp);
185 for (int y = 0; y < 1 + LJ_NEXT_PIECES; ++y) {
186 p->curPiece[y] = fgetc(fp);
187 }
188 for (int y = 0; y < 2 * MAX_BAG_LEN; ++y) {
189 p->permuPiece[y] = fgetc(fp);
190 }
191 p->permuPhase = fgetc(fp);
192 for (int y = 0; y < LJ_MAX_LINES_PER_PIECE; ++y) {
193 p->nLineClears[y] = fget16(fp);
194 }
195 p->y = fget32(fp);
196 p->state = fgetc(fp);
197 p->stateTime = fgetc(fp);
198 p->theta = fgetc(fp);
199 p->x = fgetc(fp);
200 p->hardDropY = fgetc(fp);
201 p->alreadyHeld = fgetc(fp);
202 p->isSpin = fgetc(fp);
203 p->nLinesThisPiece = fgetc(fp);
204 p->canRotate = fgetc(fp);
206 #if DEBUG_OFFSETS
207 allegro_message("before score, offset = %u\n", (unsigned int)ftell(fp));
208 #endif
209 p->score = fget32(fp);
210 p->lines = fget32(fp);
211 p->gameTime = fget32(fp);
212 p->activeTime = fget32(fp);
213 p->holdPiece = fget16(fp);
214 p->chain = fgetc(fp);
215 p->garbage = fgetc(fp);
216 p->garbageX = fgetc(fp);
217 p->nPieces = fget16(fp);
218 p->outGarbage = fget16(fp);
220 p->gimmick = fgetc(fp);
221 p->speedState.level = fget32(fp);
222 p->bpmCounter = fget32(fp);
223 p->speedupCounter = fget32(fp);
224 p->goalCount = fget32(fp);
225 p->seed = fget32(fp);
226 p->speed.gravity = fget32(fp);
227 p->speedState.curve = fgetc(fp);
228 p->goalType = fgetc(fp);
229 p->speed.entryDelay = fgetc(fp);
230 p->areStyle = fgetc(fp);
231 p->lockReset = fgetc(fp);
232 p->speed.lockDelay = fgetc(fp);
233 p->speed.lineDelay = fgetc(fp);
234 p->ceiling = fgetc(fp);
235 p->enterAbove = fgetc(fp);
236 p->leftWall = fgetc(fp);
237 p->rightWall = fgetc(fp);
238 p->pieceSet = fgetc(fp);
239 p->randomizer = fgetc(fp);
240 p->rotationSystem = fgetc(fp);
241 p->garbageRandomness = fgetc(fp);
242 p->tSpinAlgo = fgetc(fp);
243 p->clearGravity = fgetc(fp);
244 p->gluing = fgetc(fp);
245 p->scoreStyle = fgetc(fp);
246 p->setLockDelay = fgetc(fp);
247 p->upwardKicks = fgetc(fp);
248 p->maxUpwardKicks = fgetc(fp);
249 p->setLineDelay = fgetc(fp);
250 p->garbageStyle = fgetc(fp);
251 p->holdStyle = fgetc(fp);
252 p->bottomBlocks = fgetc(fp);
254 if (format == FORMAT_VERSION) {
255 p->multisquares = fget16(fp);
256 p->monosquares = fget16(fp);
257 }
258 #if DEBUG_OFFSETS
259 allegro_message("final offset = %u\n", (unsigned int)ftell(fp));
260 #endif
261 return 0;
262 }
265 LJReplay *newReplay(const char *filename, LJField *p) {
266 LJReplay *r = malloc(sizeof(struct LJReplay));
268 if (!r) {
269 return NULL;
270 }
271 r->file = fopen(filename, "wb");
272 if (!r->file) {
273 free(r);
274 return NULL;
275 }
276 LJField_serialize(p, r->file);
277 return r;
278 }
280 void replayRecord(LJReplay *r, LJBits keys, const LJInput *in) {
281 fputc(0, r->file);
282 fputc(0, r->file);
283 fputc(keys >> 8, r->file);
284 fputc(keys, r->file);
285 fputc(in->rotation, r->file);
286 fputc(in->movement, r->file);
287 fputc(in->gravity, r->file);
288 fputc(in->other, r->file);
289 }
291 LJReplay *openReplay(const char *filename, LJField *p) {
292 LJReplay *r = malloc(sizeof(struct LJReplay));
294 if (!r) {
295 return NULL;
296 }
297 r->file = fopen(filename, "rb");
298 if (!r->file) {
299 free(r);
300 return NULL;
301 }
303 /* This deserialization is still NOT robust. */
304 if (LJField_deserialize(p, r->file) < 0) {
305 fclose(r->file);
306 free(r);
307 return 0;
308 }
309 return r;
310 }
312 int getReplayFrame(LJReplay *r, LJInput *d) {
313 fgetc(r->file);
314 fgetc(r->file);
315 int keys = fgetc(r->file);
317 if (keys == EOF) {
318 return LJREPLAY_EOF;
319 }
320 keys = (keys << 8 & 0xFF) | (fgetc(r->file) & 0xFF);
321 d->rotation = fgetc(r->file);
322 d->movement = fgetc(r->file);
323 d->gravity = fgetc(r->file);
324 d->other = fgetc(r->file);
325 return keys;
326 }
328 void replayClose(LJReplay *r) {
329 if (r) {
330 if (r->file) {
331 fclose(r->file);
332 }
333 free(r);
334 }
335 }