view src/macro.c @ 1:38c62fded078

initial builds (linux and lj.nds)
author paulo@localhost
date Fri, 13 Mar 2009 01:10:13 -0700
parents
children
line source
1 /* Input handling for LOCKJAW Tetromino Game
3 Copyright (C) 2006 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 */
24 #include "lj.h"
25 #include "ljcontrol.h"
26 #include "ljreplay.h"
27 #include "pcjoy.h"
29 // first is rotation (+1 = 90 deg clockwise)
30 // second is movement (+1 = right 1 block)
31 // third is gravity (+1 = down 1/8 block)
32 // fourth is extra actions (hold, lock)
33 LJInput macros[8] = {
34 { -1, 0, 0, 0 }, // default: alt. rotate left
35 { -2, 0, 0, 0 }, // default: rotate left twice
36 { 0, -9, 0, 0 }, // default: far left
37 { 0, 9, 0, 0 }, // default: far right
38 { 0, 0, 20*8, 0 }, // default: firm drop
39 { 0, 0, 0, LJI_HOLD }, // default: alternate hold
40 { 0, 0, 0, 0 },
41 { 0, 0, 0, 0 }
42 };
44 void addMacrosToInput(LJInput *dst, LJBits keys) {
45 int rotation = dst->rotation;
46 int movement = dst->movement;
47 int gravity = dst->gravity;
48 int other = dst->other;
49 int macro;
51 keys >>= 8;
52 for (macro = 0;
53 macro < 8;
54 keys >>= 1, ++macro) {
55 if (keys & 1) {
56 rotation += macros[macro].rotation;
57 movement += macros[macro].movement;
58 gravity += macros[macro].gravity;
59 other |= macros[macro].other;
60 }
61 }
63 // Clip rotation to [-3, +3]
64 rotation -= rotation / 4 * 4;
66 // Clip movement to playfield width
67 if (movement < (int)-LJ_PF_WID) {
68 movement = -LJ_PF_WID;
69 } else if (movement > (int)LJ_PF_WID) {
70 movement = LJ_PF_WID;
71 }
73 // Clip gravity to playfield height
74 if (gravity > LJ_PF_HT * 8) {
75 gravity = LJ_PF_HT * 8;
76 }
78 dst->rotation = rotation;
79 dst->movement = movement;
80 dst->gravity = gravity;
81 dst->other = other;
82 }
84 static const LJFixed softDropSpeeds[3] = {
85 LJITOFIX(1),
86 LJITOFIX(1)/2,
87 LJITOFIX(1)/3
88 };
90 void addKeysToInput(LJInput *dst, LJBits keys, const LJField *p, LJControl *c) {
91 int actualKeys = keys;
93 if (c->replaySrc) {
94 keys = getReplayFrame(c->replaySrc, dst);
95 if (keys == LJREPLAY_EOF) {
96 keys = actualKeys;
97 replayClose(c->replaySrc);
98 c->replaySrc = NULL;
99 }
100 }
102 int lastFrameKeys = c->lastKeys;
104 // If diagonal presses are disabled, ignore any changes
105 if (!c->allowDiagonals
106 && (keys & (VKEY_UP | VKEY_DOWN))
107 && (keys & (VKEY_LEFT | VKEY_RIGHT))) {
108 keys &= ~(VKEY_UP | VKEY_DOWN | VKEY_LEFT | VKEY_RIGHT);
109 keys |= lastFrameKeys
110 & (VKEY_UP | VKEY_DOWN | VKEY_LEFT | VKEY_RIGHT);
111 }
113 LJBits newKeys = keys & ~lastFrameKeys;
114 c->lastKeys = keys;
116 // Count presses for Baboo!, excluding console buttons
117 c->presses += countOnes(newKeys & 0x0000FFFF);
119 // Only once the side effect of counting presses for Baboo!
120 // is complete can we break out of a replay.
121 if (c->replaySrc) {
122 return;
123 }
125 LJBits releasedKeys = ~keys & lastFrameKeys;
127 // At this point, c->lastKeys holds the keys actually held
128 // by the player this frame, and lastFrameKeys holds the keys
129 // actually held by the player last frame.
131 // Handle keys that must be re-pressed
132 releasedKeys &= ~c->repressKeys;
133 c->repressKeys &= keys;
134 keys &= ~c->repressKeys;
136 // If locking in a mode without ARE, require
137 // down to be re-pressed before next piece
138 if (p->sounds & LJSND_LOCK
139 && p->speed.entryDelay <= c->dasDelay) {
140 c->repressKeys |= VKEY_DOWN;
142 // Treat up the same way when hard drop lock is set to lock on release.
143 if (c->hardDropLock != LJZANGI_SLIDE
144 || p->lockReset == LJLOCK_NOW
145 || p->speed.lockDelay <= c->dasDelay) {
146 c->repressKeys |= VKEY_UP | VKEY_MACRO(4);
147 }
148 }
150 // Initial Rotation System (IRS):
151 // When a piece spawns from next or hold, and a rotation or macro
152 // key is held, treat the key as if they had just been pressed.
153 // Treat hard drop the same way when ARE is turned on.
154 if ((p->sounds & (LJSND_SPAWN | LJSND_HOLD))
155 && c->initialRotate) {
156 newKeys |= c->lastKeys
157 & (VKEY_ROTL | VKEY_ROTR | VKEY_MACROS);
158 if (p->speed.entryDelay > 0) {
159 newKeys |= c->lastKeys
160 & VKEY_UP;
161 }
162 }
164 // if we're pretending that keys are not pressed,
165 // pretend consistently
166 newKeys &= keys;
168 // TGM does not perform sideways movement on
169 // the first frame after a piece is spawned.
170 if (c->initialDAS == 0 &&
171 (p->sounds & (LJSND_SPAWN | LJSND_HOLD))) {
173 } else if (keys & VKEY_LEFT) {
174 if (c->dasCounter > -(int)c->dasDelay) {
175 if (c->dasCounter >= 0) {
176 c->dasCounter = -1;
177 dst->movement = -1;
178 } else {
179 c->dasCounter -= 1;
180 }
181 } else {
182 int dasSpeed = c->dasSpeed;
183 if (dasSpeed) {
184 dst->movement = -1;
185 c->dasCounter += dasSpeed - 1;
186 } else {
187 dst->movement = -(int)LJ_PF_WID;
188 }
189 }
190 } else if (keys & VKEY_RIGHT) {
191 if (c->dasCounter < c->dasDelay) {
192 if (c->dasCounter <= 0) {
193 c->dasCounter = 1;
194 dst->movement = 1;
195 } else {
196 c->dasCounter += 1;
197 }
198 } else {
199 int dasSpeed = c->dasSpeed;
200 if (dasSpeed) {
201 dst->movement = 1;
202 c->dasCounter -= dasSpeed - 1;
203 } else {
204 dst->movement = (int)LJ_PF_WID;
205 }
206 }
207 } else {
208 c->dasCounter = 0;
209 }
211 if(keys & VKEY_DOWN) {
212 int g = softDropSpeeds[c->softDropSpeed];
214 // dither speed to 1/8G units
215 g += ljitofix(p->gameTime % 3) / 24;
216 dst->gravity += g >> 13;
218 if ((newKeys & VKEY_DOWN)
219 || c->softDropLock == LJZANGI_LOCK) {
220 dst->other |= LJI_LOCK;
221 }
222 }
224 if (newKeys & VKEY_ROTL) {
225 dst->rotation -= 1;
226 }
227 if (newKeys & VKEY_ROTR) {
228 dst->rotation += 1;
229 }
230 if (newKeys & VKEY_HOLD) {
231 dst->other |= LJI_HOLD;
232 }
233 if (newKeys & VKEY_UP) {
234 dst->gravity = LJ_PF_HT << 3;
235 if (p->state == LJS_LANDED
236 || c->hardDropLock == LJZANGI_LOCK) {
237 dst->other |= LJI_LOCK;
238 }
239 }
241 if (c->hardDropLock == LJZANGI_LOCK_RELEASE) {
242 if (releasedKeys & VKEY_UP) {
243 dst->other |= LJI_LOCK;
244 }
245 }
246 if (c->softDropLock == LJZANGI_LOCK_RELEASE) {
247 if (releasedKeys & VKEY_DOWN) {
248 dst->other |= LJI_LOCK;
249 }
250 }
252 addMacrosToInput(dst, newKeys);
254 // Baboo! ends with a hard drop
255 if (p->gimmick == LJGM_BABY && c->presses >= 300) {
256 dst->gravity = LJ_PF_HT << 3;
257 dst->other |= LJI_LOCK;
258 }
260 if (c->replayDst) {
261 replayRecord(c->replayDst, actualKeys, dst);
262 }
263 }