Fixes for datatype size on amd64.
[crack-attack.git] / src / Block.cxx
blobb96a032604642edecc1c88e3139cda47c8baf310
1 /*
2 * Block.cxx
3 * Daniel Nelson - 8/21/0
5 * Copyright (C) 2000 Daniel Nelson
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * Daniel Nelson - aluminumangel.org
22 * 174 W. 18th Ave.
23 * Columbus, OH 43210
25 * The block object, of which each block is one.
28 #include "Block.h"
30 #include "Game.h"
31 #include "BlockManager.h"
32 #include "ComboTabulator.h"
33 #include "Garbage.h"
34 #include "Grid.h"
35 #include "Random.h"
36 #include "Swapper.h"
37 #include "SparkleManager.h"
38 #include "X.h"
39 #include "Sound.h"
42 void Block::initializeStatic ( int _x, int _y, int _flavor )
44 x = _x;
45 y = _y;
46 flavor = _flavor;
47 f_y = 0;
49 state = BS_STATIC;
50 alarm = 0;
51 // pop_alarm = 0;
52 current_combo = null;
54 // add ourselves to the grid
55 Grid::addBlock(x, y, this, GR_BLOCK);
57 // if we're wild, the extreme code needs to know
58 if (flavor == BF_WILD)
59 X::activateWild(*this);
60 else if (BlockManager::isSpecialColorFlavor(flavor))
61 X::activateSpecialColor(*this);
64 void Block::initializeAwaking ( int _x, int _y, int _flavor, int pop_delay,
65 int awake_delay, ComboTabulator *combo, int _pop_color )
67 x = _x;
68 y = _y;
69 flavor = _flavor;
70 f_y = 0;
72 state = BS_AWAKING;
73 alarm = Game::time_step + awake_delay;
74 pop_alarm = Game::time_step + pop_delay;
75 pop_direction = BlockManager::generatePopDirection();
76 pop_color = _pop_color;
77 current_combo = combo;
79 // let the combo know we're involved
80 current_combo->incrementInvolvement();
82 // change the game state
83 Game::awaking_count++;
85 // add ourselves to the grid
86 Grid::addBlock(x, y, this, GR_IMMUTABLE);
89 void Block::timeStep ( )
91 if (state & BS_STATIC) {
92 // We may have to fall.
94 if (Grid::stateAt(x, y - 1) & GR_EMPTY)
95 startFalling();
96 else
97 return;
99 } else if (state & BS_AWAKING) {
100 // The alarm has been set to go off when we're done awaking. When the
101 // pop alarm goes off, we only switch our appearence.
102 if (pop_alarm == Game::time_step) {
103 #ifdef AUDIO_ENABLED
104 Sound::play( GC_SOUND_BLOCK_AWAKING, 5 );
105 #endif
106 pop_alarm = 0;
109 if (alarm == Game::time_step) {
111 // change the game state
112 Game::awaking_count--;
114 // change our state; startFalling() and eliminations check for
115 // BS_STATIC state
116 state = BS_STATIC;
118 // if we're going to fall
119 if (Grid::stateAt(x, y - 1) & GR_EMPTY)
120 startFalling(current_combo, true);
122 else {
123 // update the grid
124 Grid::changeState(x, y, this, GR_BLOCK);
126 // register for elimination checking
127 Grid::requestEliminationCheck(*this, current_combo);
130 } else
131 return;
134 // Deal with all other states.
136 if (state & BS_FALLING) {
137 // We are assured that the timeStep() of any blocks below us has already
138 // been called. Note that to start a fall, all we have to do is set our
139 // state to BS_FALLING. This code will deal with the rest.
141 if (alarm == Game::time_step)
142 // hang alarm goes off
143 alarm = 0;
145 // if the hang alarm has gone off
146 if (alarm == 0) {
148 // if we're at the bottom of a grid element
149 if (f_y == 0) {
151 // if we're still going to fall
152 if (Grid::stateAt(x, y - 1) & GR_EMPTY) {
154 // shift our grid position down to the next row
155 y--;
156 f_y = GC_STEPS_PER_GRID;
158 // update the grid
159 Grid::remove(x, y + 1, this);
160 Grid::addBlock(x, y, this, GR_FALLING);
162 // if we've landed
163 } else {
165 // change our state
166 state = BS_STATIC;
167 #ifdef AUDIO_ENABLED
168 Sound::play( GC_SOUND_BLOCK_FALLEN, 2 );
169 #endif
171 // update the grid
172 Grid::changeState(x, y, this, GR_BLOCK);
174 // register for elimination checking
175 Grid::requestEliminationCheck(*this, current_combo);
177 // if the block below us is swapping, we may have to switch it's combo
178 if (current_combo)
179 Swapper::notifyLanding(x, y, *this, current_combo);
183 // if we still are, fall
184 if (state & BS_FALLING)
185 f_y -= GC_FALL_VELOCITY;
188 } else if (state & BS_DYING) {
189 // The alarm has been set to go off when we're done dying.
191 if (--alarm == 0) {
193 // change the game state
194 Game::dying_count--;
195 Game::dying_count_2--;
197 // update the grid
198 Grid::remove(x, y, this);
200 // tell our upward neighbor to start a combo fall
201 if (y < GC_PLAY_HEIGHT - 1) {
202 if (Grid::stateAt(x, y + 1) & GR_BLOCK)
203 Grid::blockAt(x, y + 1).startFalling(current_combo);
204 else if (Grid::stateAt(x, y + 1) & GR_GARBAGE)
205 Grid::garbageAt(x, y + 1).startFalling(current_combo);
208 // let the combo know we're out
209 current_combo->decrementInvolvement();
211 // generate some sparkles; pop_alarm stores the number
212 if (flavor != BF_WILD)
213 SparkleManager::createBlockDeathSpark(x, y, flavor, pop_alarm);
214 else
215 SparkleManager::createBlockDeathSpark(x, y, X::wildFlavor(*this),
216 pop_alarm);
218 // if we're wild, the extreme code needs to know
219 if (flavor == BF_WILD)
220 X::deactivateWild(*this);
221 else if (BlockManager::isSpecialColorFlavor(flavor))
222 X::deactivateSpecialColor();
224 // delete ourselves
225 BlockManager::deleteBlock(this);
227 // if we just started dying
228 } else if (alarm == GC_DYING_DELAY - 1)
229 // grab the elimination magnitude from our combo
230 pop_alarm = current_combo->latest_magnitude;
234 void Block::startFalling ( ComboTabulator *combo, bool no_hang )
236 * Although blocks will fall on their own, this must be called to syncronize
237 * and connect that falling with a elimination combo.
240 if (!(state & BS_STATIC)) return;
242 // change our state
243 state = BS_FALLING;
245 // set the hang alarm and update the grid
246 if (no_hang) {
247 alarm = 0;
248 Grid::changeState(x, y, this, GR_FALLING);
250 } else {
251 alarm = Game::time_step + GC_HANG_DELAY;
252 Grid::changeState(x, y, this, GR_HANGING | GR_FALLING);
255 // let the combo know we're involved
256 if (combo)
257 beginComboInvolvement(combo);
259 // tell our upward neighbor to start a combo fall
260 if (y < GC_PLAY_HEIGHT - 1) {
261 if (Grid::stateAt(x, y + 1) & GR_BLOCK)
262 Grid::blockAt(x, y + 1).startFalling(current_combo, no_hang);
263 else if (Grid::stateAt(x, y + 1) & GR_GARBAGE)
264 Grid::garbageAt(x, y + 1).startFalling(current_combo, no_hang);
268 void Block::startDying ( ComboTabulator *combo, int spark_number )
270 // change the game state
271 Game::dying_count++;
272 Game::dying_count_2++;
273 #ifdef AUDIO_ENABLED
274 Sound::play( GC_SOUND_BLOCK_DYING, spark_number / 3 );
275 #endif
277 // let the combo know we're in
278 beginComboInvolvement(combo);
280 // change our state
281 state = BS_DYING;
283 // set the alarm; the alarm works this way due to display needs
284 alarm = GC_DYING_DELAY;
286 // update the grid
287 Grid::changeState(x, y, this, GR_IMMUTABLE);
289 // generate a random rotation axis
290 Random::angle(axis_x, axis_y);
293 void Block::startSwapping ( int direction )
295 // change our state and swap direction
296 state = BS_SWAPPING | (direction & SA_RIGHT ? BS_SWAP_DIRECTION_MASK : 0);
298 // update the grid
299 Grid::changeState(x, y, this, GR_IMMUTABLE);
302 void Block::finishSwapping ( int s_x )
304 // change our state
305 state = BS_STATIC;
306 x = s_x;
308 // update the grid
309 Grid::addBlock(x, y, this, GR_BLOCK);