annotate src/macro.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
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 }