rev |
line source |
paulo@0
|
1 /* Input handling for LOCKJAW Tetromino Game
|
paulo@0
|
2
|
paulo@0
|
3 Copyright (C) 2006 Damian Yerrick <tepples+lj@spamcop.net>
|
paulo@0
|
4
|
paulo@0
|
5 This work is free software; you can redistribute it and/or modify
|
paulo@0
|
6 it under the terms of the GNU General Public License as published by
|
paulo@0
|
7 the Free Software Foundation; either version 2 of the License, or
|
paulo@0
|
8 (at your option) any later version.
|
paulo@0
|
9
|
paulo@0
|
10 This program is distributed in the hope that it will be useful,
|
paulo@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
paulo@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
paulo@0
|
13 GNU General Public License for more details.
|
paulo@0
|
14
|
paulo@0
|
15 You should have received a copy of the GNU General Public License
|
paulo@0
|
16 along with this program; if not, write to the Free Software
|
paulo@0
|
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
paulo@0
|
18
|
paulo@0
|
19 Original game concept and design by Alexey Pajitnov.
|
paulo@0
|
20 The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg,
|
paulo@0
|
21 or The Tetris Company LLC.
|
paulo@0
|
22
|
paulo@0
|
23 */
|
paulo@0
|
24 #include "lj.h"
|
paulo@0
|
25 #include "ljcontrol.h"
|
paulo@0
|
26 #include "ljreplay.h"
|
paulo@0
|
27 #include "pcjoy.h"
|
paulo@0
|
28
|
paulo@0
|
29 // first is rotation (+1 = 90 deg clockwise)
|
paulo@0
|
30 // second is movement (+1 = right 1 block)
|
paulo@0
|
31 // third is gravity (+1 = down 1/8 block)
|
paulo@0
|
32 // fourth is extra actions (hold, lock)
|
paulo@0
|
33 LJInput macros[8] = {
|
paulo@0
|
34 { -1, 0, 0, 0 }, // default: alt. rotate left
|
paulo@0
|
35 { -2, 0, 0, 0 }, // default: rotate left twice
|
paulo@0
|
36 { 0, -9, 0, 0 }, // default: far left
|
paulo@0
|
37 { 0, 9, 0, 0 }, // default: far right
|
paulo@0
|
38 { 0, 0, 20*8, 0 }, // default: firm drop
|
paulo@0
|
39 { 0, 0, 0, LJI_HOLD }, // default: alternate hold
|
paulo@0
|
40 { 0, 0, 0, 0 },
|
paulo@0
|
41 { 0, 0, 0, 0 }
|
paulo@0
|
42 };
|
paulo@0
|
43
|
paulo@0
|
44 void addMacrosToInput(LJInput *dst, LJBits keys) {
|
paulo@0
|
45 int rotation = dst->rotation;
|
paulo@0
|
46 int movement = dst->movement;
|
paulo@0
|
47 int gravity = dst->gravity;
|
paulo@0
|
48 int other = dst->other;
|
paulo@0
|
49 int macro;
|
paulo@0
|
50
|
paulo@0
|
51 keys >>= 8;
|
paulo@0
|
52 for (macro = 0;
|
paulo@0
|
53 macro < 8;
|
paulo@0
|
54 keys >>= 1, ++macro) {
|
paulo@0
|
55 if (keys & 1) {
|
paulo@0
|
56 rotation += macros[macro].rotation;
|
paulo@0
|
57 movement += macros[macro].movement;
|
paulo@0
|
58 gravity += macros[macro].gravity;
|
paulo@0
|
59 other |= macros[macro].other;
|
paulo@0
|
60 }
|
paulo@0
|
61 }
|
paulo@0
|
62
|
paulo@0
|
63 // Clip rotation to [-3, +3]
|
paulo@0
|
64 rotation -= rotation / 4 * 4;
|
paulo@0
|
65
|
paulo@0
|
66 // Clip movement to playfield width
|
paulo@0
|
67 if (movement < (int)-LJ_PF_WID) {
|
paulo@0
|
68 movement = -LJ_PF_WID;
|
paulo@0
|
69 } else if (movement > (int)LJ_PF_WID) {
|
paulo@0
|
70 movement = LJ_PF_WID;
|
paulo@0
|
71 }
|
paulo@0
|
72
|
paulo@0
|
73 // Clip gravity to playfield height
|
paulo@0
|
74 if (gravity > LJ_PF_HT * 8) {
|
paulo@0
|
75 gravity = LJ_PF_HT * 8;
|
paulo@0
|
76 }
|
paulo@0
|
77
|
paulo@0
|
78 dst->rotation = rotation;
|
paulo@0
|
79 dst->movement = movement;
|
paulo@0
|
80 dst->gravity = gravity;
|
paulo@0
|
81 dst->other = other;
|
paulo@0
|
82 }
|
paulo@0
|
83
|
paulo@0
|
84 static const LJFixed softDropSpeeds[3] = {
|
paulo@0
|
85 LJITOFIX(1),
|
paulo@0
|
86 LJITOFIX(1)/2,
|
paulo@0
|
87 LJITOFIX(1)/3
|
paulo@0
|
88 };
|
paulo@0
|
89
|
paulo@0
|
90 void addKeysToInput(LJInput *dst, LJBits keys, const LJField *p, LJControl *c) {
|
paulo@0
|
91 int actualKeys = keys;
|
paulo@0
|
92
|
paulo@0
|
93 if (c->replaySrc) {
|
paulo@0
|
94 keys = getReplayFrame(c->replaySrc, dst);
|
paulo@0
|
95 if (keys == LJREPLAY_EOF) {
|
paulo@0
|
96 keys = actualKeys;
|
paulo@0
|
97 replayClose(c->replaySrc);
|
paulo@0
|
98 c->replaySrc = NULL;
|
paulo@0
|
99 }
|
paulo@0
|
100 }
|
paulo@0
|
101
|
paulo@0
|
102 int lastFrameKeys = c->lastKeys;
|
paulo@0
|
103
|
paulo@0
|
104 // If diagonal presses are disabled, ignore any changes
|
paulo@0
|
105 if (!c->allowDiagonals
|
paulo@0
|
106 && (keys & (VKEY_UP | VKEY_DOWN))
|
paulo@0
|
107 && (keys & (VKEY_LEFT | VKEY_RIGHT))) {
|
paulo@0
|
108 keys &= ~(VKEY_UP | VKEY_DOWN | VKEY_LEFT | VKEY_RIGHT);
|
paulo@0
|
109 keys |= lastFrameKeys
|
paulo@0
|
110 & (VKEY_UP | VKEY_DOWN | VKEY_LEFT | VKEY_RIGHT);
|
paulo@0
|
111 }
|
paulo@0
|
112
|
paulo@0
|
113 LJBits newKeys = keys & ~lastFrameKeys;
|
paulo@0
|
114 c->lastKeys = keys;
|
paulo@0
|
115
|
paulo@0
|
116 // Count presses for Baboo!, excluding console buttons
|
paulo@0
|
117 c->presses += countOnes(newKeys & 0x0000FFFF);
|
paulo@0
|
118
|
paulo@0
|
119 // Only once the side effect of counting presses for Baboo!
|
paulo@0
|
120 // is complete can we break out of a replay.
|
paulo@0
|
121 if (c->replaySrc) {
|
paulo@0
|
122 return;
|
paulo@0
|
123 }
|
paulo@0
|
124
|
paulo@0
|
125 LJBits releasedKeys = ~keys & lastFrameKeys;
|
paulo@0
|
126
|
paulo@0
|
127 // At this point, c->lastKeys holds the keys actually held
|
paulo@0
|
128 // by the player this frame, and lastFrameKeys holds the keys
|
paulo@0
|
129 // actually held by the player last frame.
|
paulo@0
|
130
|
paulo@0
|
131 // Handle keys that must be re-pressed
|
paulo@0
|
132 releasedKeys &= ~c->repressKeys;
|
paulo@0
|
133 c->repressKeys &= keys;
|
paulo@0
|
134 keys &= ~c->repressKeys;
|
paulo@0
|
135
|
paulo@0
|
136 // If locking in a mode without ARE, require
|
paulo@0
|
137 // down to be re-pressed before next piece
|
paulo@0
|
138 if (p->sounds & LJSND_LOCK
|
paulo@0
|
139 && p->speed.entryDelay <= c->dasDelay) {
|
paulo@0
|
140 c->repressKeys |= VKEY_DOWN;
|
paulo@0
|
141
|
paulo@0
|
142 // Treat up the same way when hard drop lock is set to lock on release.
|
paulo@0
|
143 if (c->hardDropLock != LJZANGI_SLIDE
|
paulo@0
|
144 || p->lockReset == LJLOCK_NOW
|
paulo@0
|
145 || p->speed.lockDelay <= c->dasDelay) {
|
paulo@0
|
146 c->repressKeys |= VKEY_UP | VKEY_MACRO(4);
|
paulo@0
|
147 }
|
paulo@0
|
148 }
|
paulo@0
|
149
|
paulo@0
|
150 // Initial Rotation System (IRS):
|
paulo@0
|
151 // When a piece spawns from next or hold, and a rotation or macro
|
paulo@0
|
152 // key is held, treat the key as if they had just been pressed.
|
paulo@0
|
153 // Treat hard drop the same way when ARE is turned on.
|
paulo@0
|
154 if ((p->sounds & (LJSND_SPAWN | LJSND_HOLD))
|
paulo@0
|
155 && c->initialRotate) {
|
paulo@0
|
156 newKeys |= c->lastKeys
|
paulo@0
|
157 & (VKEY_ROTL | VKEY_ROTR | VKEY_MACROS);
|
paulo@0
|
158 if (p->speed.entryDelay > 0) {
|
paulo@0
|
159 newKeys |= c->lastKeys
|
paulo@0
|
160 & VKEY_UP;
|
paulo@0
|
161 }
|
paulo@0
|
162 }
|
paulo@0
|
163
|
paulo@0
|
164 // if we're pretending that keys are not pressed,
|
paulo@0
|
165 // pretend consistently
|
paulo@0
|
166 newKeys &= keys;
|
paulo@0
|
167
|
paulo@0
|
168 // TGM does not perform sideways movement on
|
paulo@0
|
169 // the first frame after a piece is spawned.
|
paulo@0
|
170 if (c->initialDAS == 0 &&
|
paulo@0
|
171 (p->sounds & (LJSND_SPAWN | LJSND_HOLD))) {
|
paulo@0
|
172
|
paulo@0
|
173 } else if (keys & VKEY_LEFT) {
|
paulo@0
|
174 if (c->dasCounter > -(int)c->dasDelay) {
|
paulo@0
|
175 if (c->dasCounter >= 0) {
|
paulo@0
|
176 c->dasCounter = -1;
|
paulo@0
|
177 dst->movement = -1;
|
paulo@0
|
178 } else {
|
paulo@0
|
179 c->dasCounter -= 1;
|
paulo@0
|
180 }
|
paulo@0
|
181 } else {
|
paulo@0
|
182 int dasSpeed = c->dasSpeed;
|
paulo@0
|
183 if (dasSpeed) {
|
paulo@0
|
184 dst->movement = -1;
|
paulo@0
|
185 c->dasCounter += dasSpeed - 1;
|
paulo@0
|
186 } else {
|
paulo@0
|
187 dst->movement = -(int)LJ_PF_WID;
|
paulo@0
|
188 }
|
paulo@0
|
189 }
|
paulo@0
|
190 } else if (keys & VKEY_RIGHT) {
|
paulo@0
|
191 if (c->dasCounter < c->dasDelay) {
|
paulo@0
|
192 if (c->dasCounter <= 0) {
|
paulo@0
|
193 c->dasCounter = 1;
|
paulo@0
|
194 dst->movement = 1;
|
paulo@0
|
195 } else {
|
paulo@0
|
196 c->dasCounter += 1;
|
paulo@0
|
197 }
|
paulo@0
|
198 } else {
|
paulo@0
|
199 int dasSpeed = c->dasSpeed;
|
paulo@0
|
200 if (dasSpeed) {
|
paulo@0
|
201 dst->movement = 1;
|
paulo@0
|
202 c->dasCounter -= dasSpeed - 1;
|
paulo@0
|
203 } else {
|
paulo@0
|
204 dst->movement = (int)LJ_PF_WID;
|
paulo@0
|
205 }
|
paulo@0
|
206 }
|
paulo@0
|
207 } else {
|
paulo@0
|
208 c->dasCounter = 0;
|
paulo@0
|
209 }
|
paulo@0
|
210
|
paulo@0
|
211 if(keys & VKEY_DOWN) {
|
paulo@0
|
212 int g = softDropSpeeds[c->softDropSpeed];
|
paulo@0
|
213
|
paulo@0
|
214 // dither speed to 1/8G units
|
paulo@0
|
215 g += ljitofix(p->gameTime % 3) / 24;
|
paulo@0
|
216 dst->gravity += g >> 13;
|
paulo@0
|
217
|
paulo@0
|
218 if ((newKeys & VKEY_DOWN)
|
paulo@0
|
219 || c->softDropLock == LJZANGI_LOCK) {
|
paulo@0
|
220 dst->other |= LJI_LOCK;
|
paulo@0
|
221 }
|
paulo@0
|
222 }
|
paulo@0
|
223
|
paulo@0
|
224 if (newKeys & VKEY_ROTL) {
|
paulo@0
|
225 dst->rotation -= 1;
|
paulo@0
|
226 }
|
paulo@0
|
227 if (newKeys & VKEY_ROTR) {
|
paulo@0
|
228 dst->rotation += 1;
|
paulo@0
|
229 }
|
paulo@0
|
230 if (newKeys & VKEY_HOLD) {
|
paulo@0
|
231 dst->other |= LJI_HOLD;
|
paulo@0
|
232 }
|
paulo@0
|
233 if (newKeys & VKEY_UP) {
|
paulo@0
|
234 dst->gravity = LJ_PF_HT << 3;
|
paulo@0
|
235 if (p->state == LJS_LANDED
|
paulo@0
|
236 || c->hardDropLock == LJZANGI_LOCK) {
|
paulo@0
|
237 dst->other |= LJI_LOCK;
|
paulo@0
|
238 }
|
paulo@0
|
239 }
|
paulo@0
|
240
|
paulo@0
|
241 if (c->hardDropLock == LJZANGI_LOCK_RELEASE) {
|
paulo@0
|
242 if (releasedKeys & VKEY_UP) {
|
paulo@0
|
243 dst->other |= LJI_LOCK;
|
paulo@0
|
244 }
|
paulo@0
|
245 }
|
paulo@0
|
246 if (c->softDropLock == LJZANGI_LOCK_RELEASE) {
|
paulo@0
|
247 if (releasedKeys & VKEY_DOWN) {
|
paulo@0
|
248 dst->other |= LJI_LOCK;
|
paulo@0
|
249 }
|
paulo@0
|
250 }
|
paulo@0
|
251
|
paulo@0
|
252 addMacrosToInput(dst, newKeys);
|
paulo@0
|
253
|
paulo@0
|
254 // Baboo! ends with a hard drop
|
paulo@0
|
255 if (p->gimmick == LJGM_BABY && c->presses >= 300) {
|
paulo@0
|
256 dst->gravity = LJ_PF_HT << 3;
|
paulo@0
|
257 dst->other |= LJI_LOCK;
|
paulo@0
|
258 }
|
paulo@0
|
259
|
paulo@0
|
260 if (c->replayDst) {
|
paulo@0
|
261 replayRecord(c->replayDst, actualKeys, dst);
|
paulo@0
|
262 }
|
paulo@0
|
263 }
|