comparison src/wktables.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:8981a7e69028
1 /* Wall kick tables for LOCKJAW, an implementation of the Soviet Mind Game
2
3 Copyright (C) 2006 Damian Yerrick <tepples+lj@spamcop.net>
4
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.
9
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.
14
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
18
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.
22
23 */
24
25 #define LJ_INTERNAL
26 #include "lj.h"
27
28
29 // These wall kicks are for rotation TO a given orientation.
30 // Based on http://www.the-shell.net/img/srs_study.html
31 static const LJRotSystem rotSRS = {
32 .kicksL = {1, 0, 0, -1, 0, 0, 0, -1, 0, -1},
33 .kicksR = {3, 2, 2, -1, 2, 2, 2, -1, 2, -3},
34 .kickTables = {
35
36 // 0: JLSTZ counterclockwise
37 {
38 { WK( 0, 0),WK( 1, 0),WK( 1,-1),WK( 0, 2),WK( 1, 2) }, // R->U
39 { WK( 0, 0),WK(-1, 0),WK(-1, 1),WK( 0,-2),WK(-1,-2) }, // D->R
40 { WK( 0, 0),WK(-1, 0),WK(-1,-1),WK( 0, 2),WK(-1, 2) }, // L->D
41 { WK( 0, 0),WK( 1, 0),WK( 1, 1),WK( 0,-2),WK( 1,-2) } // U->L
42 },
43
44 // 1: I counterclockwise
45 {
46 { WK( 0, 0),WK(-1, 0),WK( 2, 0),WK(-1,-2),WK( 2, 1) }, // R->U
47 { WK( 0, 0),WK( 1, 0),WK(-2, 0),WK( 1,-1),WK(-2, 1) }, // D->R
48 { WK( 0, 0),WK( 1, 0),WK(-2, 0),WK(-2,-1),WK( 1, 2) }, // L->D
49 { WK( 0, 0),WK(-1, 0),WK( 2, 0),WK( 2,-1),WK(-1, 2) } // U->L
50 },
51
52 // 2: JLSTZ clockwise
53 {
54 { WK( 0, 0),WK(-1, 0),WK(-1,-1),WK( 0, 2),WK(-1, 2) }, // L->U
55 { WK( 0, 0),WK(-1, 0),WK(-1, 1),WK( 0,-2),WK(-1,-2) }, // U->R
56 { WK( 0, 0),WK( 1, 0),WK( 1,-1),WK( 0, 2),WK( 1, 2) }, // R->D
57 { WK( 0, 0),WK( 1, 0),WK( 1, 1),WK( 0,-2),WK( 1,-2) }, // D->L
58 },
59
60 // 3: I clockwise
61 {
62 { WK( 0, 0),WK( 1, 0),WK(-2, 0),WK( 1,-2),WK(-2, 1) }, // L->U
63 { WK( 0, 0),WK( 1, 0),WK(-2, 0),WK(-2,-1),WK( 1, 2) }, // U->R
64 { WK( 0, 0),WK(-1, 0),WK( 2, 0),WK( 2,-1),WK(-1, 2) }, // R->D
65 { WK( 0, 0),WK(-1, 0),WK( 2, 0),WK(-1,-1),WK( 2, 1) } // D->L
66 }
67 }
68 };
69
70 // I: round to top right
71 // J, L, T: round to bottom
72 // S: round to bottom left (constant center column)
73 // Z: round to bottom right (constant center column)
74 static const LJRotSystem rotSega = {
75 .colorScheme = 1,
76 .entryOffset = {
77 WK( 0, 0),WK( 0, 1),WK( 0, 1),WK( 0, 0),WK( 0, 0),WK( 0, 1),WK( 0, 0),
78 WK( 0, 0),WK( 0, 0),WK( 0, 0)
79 },
80 .entryTheta = { 0, 2, 2, 0, 0, 2, 0, 0, 0, 2 },
81 .kicksL = {0, 1, 1, -1, 2, 1, 3, 0, -1, -1},
82 .kicksR = {4, 5, 5, -1, 6, 5, 7, 4, -1, -1},
83
84 .kickTables = {
85
86 // 0: I counterclockwise
87 {
88 { WK( 0, 0),WK_END }, // R->U
89 { WK( 0,-1),WK_END }, // D->R
90 { WK(-1, 1),WK_END }, // L->D
91 { WK( 1, 0),WK_END } // U->L
92 },
93
94 // 1: JLT counterclockwise
95 {
96 { WK( 0,-1),WK_END }, // R->U
97 { WK( 0, 0),WK_END }, // D->R
98 { WK( 0, 0),WK_END }, // L->D
99 { WK( 0, 1),WK_END } // U->L
100 },
101
102 // 2: S counterclockwise (round left, like Game Boy)
103 {
104 { WK( 1,-1),WK_END }, // R->U
105 { WK(-1, 0),WK_END }, // D->R
106 { WK( 0, 0),WK_END }, // L->D
107 { WK( 0, 1),WK_END } // U->L
108 },
109
110 // 3: Z counterclockwise (round right, like NES)
111 {
112 { WK( 0,-1),WK_END }, // R->U
113 { WK( 0, 0),WK_END }, // D->R
114 { WK(-1, 0),WK_END }, // L->D
115 { WK( 1, 1),WK_END } // U->L
116 },
117
118 // 4: I clockwise
119 {
120 { WK(-1, 0),WK_END }, // L->U
121 { WK( 0, 0),WK_END }, // U->R
122 { WK( 0, 1),WK_END }, // R->D
123 { WK( 1,-1),WK_END } // D->L
124 },
125
126 // 5: JLT clockwise
127 {
128 { WK( 0,-1),WK_END }, // L->U
129 { WK( 0, 1),WK_END }, // U->R
130 { WK( 0, 0),WK_END }, // R->D
131 { WK( 0, 0),WK_END } // D->L
132 },
133
134 // 6: S clockwise (round left)
135 {
136 { WK( 0,-1),WK_END }, // L->U
137 { WK(-1, 1),WK_END }, // U->R
138 { WK( 1, 0),WK_END }, // R->D
139 { WK( 0, 0),WK_END } // D->L
140 },
141
142 // 7: Z clockwise (round right)
143 {
144 { WK(-1,-1),WK_END }, // L->U
145 { WK( 0, 1),WK_END }, // U->R
146 { WK( 0, 0),WK_END }, // R->D
147 { WK( 1, 0),WK_END } // D->L
148 }
149 }
150 };
151
152 // Arika is based on Sega but with a few wall kicks.
153 // Each free-space kick should be followed by Right, then Left
154 // but for J, L, and T, kicks to vertical positions (point-right and
155 // point-left)
156 // T when rotating to point-up can also floor kick by one,
157 // and I when rotating to vertical can floor kick by one or two.
158 static const LJRotSystem rotArika = {
159 .colorScheme = 1,
160 .entryOffset = {
161 WK( 0, 0),WK( 0, 1),WK( 0, 1),WK( 0, 0),WK( 0, 0),WK( 0, 1),WK( 0, 0),
162 WK( 0, 0),WK( 0, 0),WK( 0, 0)
163 },
164 .entryTheta = { 0, 2, 2, 0, 0, 2, 0, 0, 0, 2 },
165 .kicksL = {0, 1, 1, -1, 2, 8, 3, 0, -1, -1},
166 .kicksR = {4, 5, 5, -1, 6, 9, 7, 4, -1, -1},
167 .kickTables = {
168
169 // 0: I counterclockwise
170 {
171 { WK( 0, 0),WK_END }, // R->U
172 { WK( 0,-1),WK( 0, 0),WK( 0, 1),WK_END }, // D->R
173 { WK(-1, 1),WK_END }, // L->D
174 { WK( 1, 0),WK( 1, 1),WK( 1, 2),WK_END } // U->L
175 },
176
177 // 1: JL counterclockwise
178 {
179 { WK( 0,-1),WK( 1,-1),WK(-1,-1),WK_END }, // R->U
180 { WK( 0, 0),ARIKA_IF_NOT_CENTER,WK( 1, 0),WK(-1, 0),WK_END }, // D->R
181 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK_END }, // L->D
182 { WK( 0, 1),ARIKA_IF_NOT_CENTER,WK( 1, 1),WK(-1, 1),WK_END } // U->L
183 },
184
185 // 2: S counterclockwise (round left, like Game Boy with WK)
186 {
187 { WK( 1,-1),WK( 2,-1),WK( 0,-1),WK_END }, // R->U
188 { WK(-1, 0),WK( 0, 0),WK(-2, 0),WK_END }, // D->R
189 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK_END }, // L->D
190 { WK( 0, 1),WK( 1, 1),WK(-1, 1),WK_END } // U->L
191 },
192
193 // 3: Z counterclockwise (round right, like NES with WK)
194 {
195 { WK( 0,-1),WK( 1,-1),WK(-1,-1),WK_END }, // R->U
196 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK_END }, // D->R
197 { WK(-1, 0),WK( 0, 0),WK(-2, 0),WK_END }, // L->D
198 { WK( 1, 1),WK( 2, 1),WK( 0, 1),WK_END } // U->L
199 },
200
201 // 4: I clockwise
202 {
203 { WK(-1, 0),WK_END }, // L->U
204 { WK( 0, 0),WK( 0, 1),WK( 0, 2),WK_END }, // U->R
205 { WK( 0, 1),WK_END }, // R->D
206 { WK( 1,-1),WK( 1, 0),WK( 1, 1),WK_END } // D->L
207 },
208
209 // 5: JLT clockwise
210 {
211 { WK( 0,-1),WK( 1,-1),WK(-1,-1),WK_END }, // L->U
212 { WK( 0, 1),ARIKA_IF_NOT_CENTER,WK( 1, 1),WK(-1, 1),WK_END }, // U->R
213 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK_END }, // R->D
214 { WK( 0, 0),ARIKA_IF_NOT_CENTER,WK( 1, 0),WK(-1, 0),WK_END } // D->L
215 },
216
217 // 6: S clockwise (round left)
218 {
219 { WK( 0,-1),WK( 1,-1),WK(-1,-1),WK_END }, // L->U
220 { WK(-1, 1),WK( 0, 1),WK(-2, 1),WK_END }, // U->R
221 { WK( 1, 0),WK( 2, 0),WK( 0, 0),WK_END }, // R->D
222 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK_END } // D->L
223 },
224
225 // 7: Z clockwise (round right)
226 {
227 { WK(-1,-1),WK( 0,-1),WK(-2,-1),WK_END }, // L->U
228 { WK( 0, 1),WK( 1, 1),WK(-1, 1),WK_END }, // U->R
229 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK_END }, // R->D
230 { WK( 1, 0),WK( 2, 0),WK( 0, 0),WK_END } // D->L
231 },
232
233 // 8: T counterclockwise (with TI floorkick)
234 {
235 { WK( 0,-1),WK( 1,-1),WK(-1,-1),WK( 0, 0),WK_END }, // R->U
236 { WK( 0, 0),ARIKA_IF_NOT_CENTER,WK( 1, 0),WK(-1, 0),WK_END }, // D->R
237 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK_END }, // L->D
238 { WK( 0, 1),ARIKA_IF_NOT_CENTER,WK( 1, 1),WK(-1, 1),WK_END } // U->L
239 },
240
241 // 9: T clockwise (with TI floorkick)
242 {
243 { WK( 0,-1),WK( 1,-1),WK(-1,-1),WK( 0, 0),WK_END }, // L->U
244 { WK( 0, 1),ARIKA_IF_NOT_CENTER,WK( 1, 1),WK(-1, 1),WK_END }, // U->R
245 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK_END }, // R->D
246 { WK( 0, 0),ARIKA_IF_NOT_CENTER,WK( 1, 0),WK(-1, 0),WK_END } // D->L
247 }
248 }
249 };
250
251 // All pieces are started with their left side in column 5 and flat side up.
252 // All pieces stick to the top of the bounding box.
253 // All 3-wide pieces stick to the left side of the bounding box.
254 // I sticks to the top when left and right and occupies the second column
255 // when up and down.
256 // Try here, then try kicking one space left. Discovered by zaphod77:
257 // http://www.tetrisconcept.com/forum/viewtopic.php?t=877
258 static const LJRotSystem rotTengen = {
259 .colorScheme = 1,
260 .entryOffset = {
261 WK( 1, 0),WK( 1, 1),WK( 1, 1),WK( 0, 0),WK( 1, 0),WK( 1, 1),WK( 1, 0),
262 WK( 0, 0),WK( 1, 0),WK( 0, 0)
263 },
264 .entryTheta = { 0, 2, 2, 0, 0, 2, 0, 0, 0, 2 },
265 .kicksL = {0, 3, 3, -1, 3, 3, 3, 0, 2, 5},
266 .kicksR = {1, 4, 4, -1, 4, 4, 4, 1, 3, 5},
267 .kickTables = {
268
269 // 0: I counterclockwise
270 {
271 { WK( 1, 1),WK( 0, 1),WK_END }, // R->U
272 { WK(-1,-2),WK(-2,-2),WK_END }, // D->R
273 { WK( 0, 2),WK(-1, 2),WK_END }, // L->D
274 { WK( 0,-1),WK(-1,-1),WK_END } // U->L
275 },
276
277 // 1: I clockwise
278 {
279 { WK( 0, 1),WK(-1, 1),WK_END }, // L->U
280 { WK(-1,-1),WK(-2,-1),WK_END }, // U->R
281 { WK( 1, 2),WK( 0, 2),WK_END }, // R->D
282 { WK( 0,-2),WK(-1,-2),WK_END } // D->L
283 },
284
285 // 2: I3
286 {
287 { WK( 0, 1),WK(-1, 1),WK_END }, // L->U
288 { WK( 0,-1),WK(-1,-1),WK_END }, // U->R
289 { WK( 0, 1),WK(-1, 1),WK_END }, // R->D
290 { WK( 0,-1),WK(-1,-1),WK_END } // D->L
291 },
292
293 // 3: JLSTZ counterclockwise
294 {
295 { WK( 1, 0),WK( 0, 0),WK_END }, // R->U
296 { WK(-1,-1),WK(-2,-1),WK_END }, // D->R
297 { WK( 0, 1),WK(-1, 1),WK_END }, // L->D
298 { WK( 0, 0),WK(-1, 0),WK_END } // U->L
299 },
300
301 // 4: JLSTZ clockwise
302 {
303 { WK( 0, 0),WK(-1, 0),WK_END }, // L->U
304 { WK(-1, 0),WK(-2, 0),WK_END }, // U->R
305 { WK( 1, 1),WK( 0, 1),WK_END }, // R->D
306 { WK( 0,-1),WK(-1,-1),WK_END } // D->L
307 },
308
309 // 5: L3
310 {
311 { WK( 0, 0),WK(-1, 0),WK_END }, // L->U
312 { WK(-1, 0),WK(-2, 0),WK_END }, // U->R
313 { WK( 1, 1),WK( 0, 1),WK_END }, // R->D
314 { WK( 0,-1),WK(-1,-1),WK_END } // D->L
315 }
316 }
317 };
318
319 // NES: No wall kick
320 // 3-wide pieces start out one block to the right
321 // I, S and Z round to the right and use effective positions R and D
322 static const LJRotSystem rotNES = {
323 .colorScheme = 1,
324 .entryOffset = {
325 WK( 0, 0),WK( 1, 1),WK( 1, 1),WK( 0, 0),WK( 1, 0),WK( 1, 1),WK( 1, 0),
326 WK( 0, 0),WK( 0, 0),WK( 0, 0)
327 },
328 .entryTheta = { 0, 2, 2, 0, 0, 2, 0, 0, 0, 2 },
329 .kicksL = {0, -1, -1, -1, 0, -1, 0, 0, -1, -1},
330 .kicksR = {1, -1, -1, -1, 1, -1, 1, 1, -1, -1},
331 .kickTables = {
332
333 // 0: counterclockwise (round right)
334 {
335 { WK( 0,-1),WK_END }, // R->U
336 { WK( 0, 0),WK_END }, // D->R
337 { WK(-1, 0),WK_END }, // L->D
338 { WK( 1, 1),WK_END } // U->L
339 },
340 // 1: clockwise (round right)
341 {
342 { WK(-1,-1),WK_END }, // L->U
343 { WK( 0, 1),WK_END }, // U->R
344 { WK( 0, 0),WK_END }, // R->D
345 { WK( 1, 0),WK_END } // D->L
346 }
347 }
348 };
349
350 // GB: No wall kick
351 // I, S and Z round to the left and use effective positions L and D
352 static const LJRotSystem rotGB = {
353 .colorScheme = 1,
354 .entryOffset = {
355 WK( 0, 0),WK( 0, 1),WK( 0, 1),WK( 0, 0),WK( 0, 0),WK( 0, 1),WK( 0, 0),
356 WK( 0, 0),WK( 0, 0),WK( 0, 0)
357 },
358 .entryTheta = { 0, 2, 2, 0, 0, 2, 0, 0, 0, 2 },
359 .kicksL = {0, -1, -1, -1, 0, -1, 0, 0, -1, -1},
360 .kicksR = {1, -1, -1, -1, 1, -1, 1, 1, -1, -1},
361 .kickTables = {
362
363 // 0: counterclockwise (round left)
364 {
365 { WK( 1,-1),WK_END }, // R->U
366 { WK(-1, 0),WK_END }, // D->R
367 { WK( 0, 0),WK_END }, // L->D
368 { WK( 0, 1),WK_END } // U->L
369 },
370 // 1: clockwise (round left)
371 {
372 { WK( 0,-1),WK_END }, // L->U
373 { WK(-1, 1),WK_END }, // U->R
374 { WK( 1, 0),WK_END }, // R->D
375 { WK( 0, 0),WK_END } // D->L
376 },
377 }
378 };
379
380
381 // The rotation system of LOCKJAW: The Overdose (GBA) and
382 // Tetramino (NES) TOD is simple. In free space it behaves like SRS.
383 // If that's blocked, kick right, kick left, kick up.
384 static const LJRotSystem rotTOD = {
385 .kicksL = {0, 0, 0, -1, 0, 0, 0, 0, 0, 0},
386 .kicksR = {0, 0, 0, -1, 0, 0, 0, 0, 0, 0},
387 .kickTables = {
388
389 // 0: JLSTZ counterclockwise
390 {
391 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK( 0, 1),WK_END }, // ->U
392 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK( 0, 1),WK_END }, // ->R
393 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK( 0, 1),WK_END }, // ->D
394 { WK( 0, 0),WK( 1, 0),WK(-1, 0),WK( 0, 1),WK_END } // ->L
395 },
396
397 // 1: I counterclockwise
398 {
399 { WK( 0, 0),WK(-1, 0),WK( 2, 0),WK(-1,-2),WK( 2, 1) }, // R->U
400 { WK( 0, 0),WK( 1, 0),WK(-2, 0),WK( 1,-1),WK(-2, 1) }, // D->R
401 { WK( 0, 0),WK( 1, 0),WK(-2, 0),WK(-2,-1),WK( 1, 2) }, // L->D
402 { WK( 0, 0),WK(-1, 0),WK( 2, 0),WK( 2,-1),WK(-1, 2) } // U->L
403 },
404
405 // 2: JLSTZ clockwise
406 {
407 { WK( 0, 0),WK(-1, 0),WK(-1,-1),WK( 0, 2),WK(-1, 2) }, // L->U
408 { WK( 0, 0),WK(-1, 0),WK(-1, 1),WK( 0,-2),WK(-1,-2) }, // U->R
409 { WK( 0, 0),WK( 1, 0),WK( 1,-1),WK( 0, 2),WK( 1, 2) }, // R->D
410 { WK( 0, 0),WK( 1, 0),WK( 1, 1),WK( 0,-2),WK( 1,-2) }, // D->L
411 },
412
413 // 3: I clockwise
414 {
415 { WK( 0, 0),WK( 1, 0),WK(-2, 0),WK( 1,-2),WK(-2, 1) }, // L->U
416 { WK( 0, 0),WK( 1, 0),WK(-2, 0),WK(-2,-1),WK( 1, 2) }, // U->R
417 { WK( 0, 0),WK(-1, 0),WK( 2, 0),WK( 2,-1),WK(-1, 2) }, // R->D
418 { WK( 0, 0),WK(-1, 0),WK( 2, 0),WK(-1,-1),WK( 2, 1) } // D->L
419 }
420 }
421 };
422
423 static const LJRotSystem rotTDX = {
424 .entryOffset = {
425 WK( 0, 0),WK( 1, 1),WK( 1, 1),WK( 0, 0),WK( 1, 0),WK( 1, 1),WK( 1, 0),
426 WK( 0, 0),WK( 0, 0),WK( 0, 0)
427 },
428 .entryTheta = { 0, 2, 2, 0, 0, 2, 0, 0, 0, 2 },
429 .kicksL = {0, 0, 0, -1, 0, 0, 0, 0, 0, 0},
430 .kicksR = {1, 1, 1, -1, 1, 1, 1, 1, 1, 1},
431 .kickTables = {
432
433 // 0: counterclockwise
434 {
435 { WK( 0, 0),WK( 1,-1),WK_END }, // R->U
436 { WK( 0, 0),WK(-1,-1),WK_END }, // D->R
437 { WK( 0, 0),WK(-1, 1),WK_END }, // L->D
438 { WK( 0, 0),WK( 1, 1),WK_END } // U->L
439 },
440
441 // 1: clockwise
442 {
443 { WK( 0, 0),WK(-1,-1),WK_END }, // L->U
444 { WK( 0, 0),WK(-1, 1),WK_END }, // U->R
445 { WK( 0, 0),WK( 1, 1),WK_END }, // R->D
446 { WK( 0, 0),WK( 1,-1),WK_END } // D->L
447 }
448 }
449 };
450
451 const LJRotSystem *const rotSystems[N_ROTATION_SYSTEMS] = {
452 &rotSRS, &rotSega, &rotArika, &rotTengen,
453 &rotNES, &rotGB, &rotTOD, &rotTDX
454 };