Really low graphics patch thanks to Stephan Beyer
[crack-attack.git] / src / Block.cxx
blob30600888a25e96555a0595f996e490683341d847
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 "Game.h"
29 #include "Block.h"
30 #include "BlockManager.h"
31 #include "ComboTabulator.h"
32 #include "Garbage.h"
33 #include "Grid.h"
34 #include "Random.h"
35 #include "Swapper.h"
36 #include "SparkleManager.h"
37 #include "X.h"
39 using namespace std;
41 void Block::initializeStatic ( int _x, int _y, int _flavor )
43 x = _x;
44 y = _y;
45 flavor = _flavor;
46 f_y = 0;
48 state = BS_STATIC;
49 alarm = 0;
50 // pop_alarm = 0;
51 current_combo = null;
53 // add ourselves to the grid
54 Grid::addBlock(x, y, this, GR_BLOCK);
56 // if we're wild, the extreme code needs to know
57 if (flavor == BF_WILD)
58 X::activateWild(*this);
59 else if (BlockManager::isSpecialColorFlavor(flavor))
60 X::activateSpecialColor(*this);
63 void Block::initializeAwaking ( int _x, int _y, int _flavor, int pop_delay,
64 int awake_delay, ComboTabulator *combo, int _pop_color )
66 x = _x;
67 y = _y;
68 flavor = _flavor;
69 f_y = 0;
71 state = BS_AWAKING;
72 alarm = Game::time_step + awake_delay;
73 pop_alarm = Game::time_step + pop_delay;
74 pop_direction = BlockManager::generatePopDirection();
75 pop_color = _pop_color;
76 current_combo = combo;
78 // let the combo know we're involved
79 current_combo->incrementInvolvement();
81 // change the game state
82 Game::awaking_count++;
84 // add ourselves to the grid
85 Grid::addBlock(x, y, this, GR_IMMUTABLE);
88 void Block::timeStep ( )
90 if (state & BS_STATIC) {
91 // We may have to fall.
93 if (Grid::stateAt(x, y - 1) & GR_EMPTY)
94 startFalling();
95 else
96 return;
98 } else if (state & BS_AWAKING) {
99 // The alarm has been set to go off when we're done awaking. When the
100 // pop alarm goes off, we only switch our appearence.
101 if (pop_alarm == Game::time_step)
102 pop_alarm = 0;
104 if (alarm == Game::time_step) {
106 // change the game state
107 Game::awaking_count--;
109 // change our state; startFalling() and eliminations check for
110 // BS_STATIC state
111 state = BS_STATIC;
113 // if we're going to fall
114 if (Grid::stateAt(x, y - 1) & GR_EMPTY)
115 startFalling(current_combo, true);
117 else {
118 // update the grid
119 Grid::changeState(x, y, this, GR_BLOCK);
121 // register for elimination checking
122 Grid::requestEliminationCheck(*this, current_combo);
125 } else
126 return;
129 // Deal with all other states.
131 if (state & BS_FALLING) {
132 // We are assured that the timeStep() of any blocks below us has already
133 // been called. Note that to start a fall, all we have to do is set our
134 // state to BS_FALLING. This code will deal with the rest.
136 if (alarm == Game::time_step)
137 // hang alarm goes off
138 alarm = 0;
140 // if the hang alarm has gone off
141 if (alarm == 0) {
143 // if we're at the bottom of a grid element
144 if (f_y == 0) {
146 // if we're still going to fall
147 if (Grid::stateAt(x, y - 1) & GR_EMPTY) {
149 // shift our grid position down to the next row
150 y--;
151 f_y = GC_STEPS_PER_GRID;
153 // update the grid
154 Grid::remove(x, y + 1, this);
155 Grid::addBlock(x, y, this, GR_FALLING);
157 // if we've landed
158 } else {
160 // change our state
161 state = BS_STATIC;
163 // update the grid
164 Grid::changeState(x, y, this, GR_BLOCK);
166 // register for elimination checking
167 Grid::requestEliminationCheck(*this, current_combo);
169 // if the block below us is swapping, we may have to switch it's combo
170 if (current_combo)
171 Swapper::notifyLanding(x, y, *this, current_combo);
175 // if we still are, fall
176 if (state & BS_FALLING)
177 f_y -= GC_FALL_VELOCITY;
180 } else if (state & BS_DYING) {
181 // The alarm has been set to go off when we're done dying.
183 if (--alarm == 0) {
185 // change the game state
186 Game::dying_count--;
187 Game::dying_count_2--;
189 // update the grid
190 Grid::remove(x, y, this);
192 // tell our upward neighbor to start a combo fall
193 if (y < GC_PLAY_HEIGHT - 1) {
194 if (Grid::stateAt(x, y + 1) & GR_BLOCK)
195 Grid::blockAt(x, y + 1).startFalling(current_combo);
196 else if (Grid::stateAt(x, y + 1) & GR_GARBAGE)
197 Grid::garbageAt(x, y + 1).startFalling(current_combo);
200 // let the combo know we're out
201 current_combo->decrementInvolvement();
203 // generate some sparkles; pop_alarm stores the number
204 if (flavor != BF_WILD)
205 SparkleManager::createBlockDeathSpark(x, y, flavor, pop_alarm);
206 else
207 SparkleManager::createBlockDeathSpark(x, y, X::wildFlavor(*this),
208 pop_alarm);
210 // if we're wild, the extreme code needs to know
211 if (flavor == BF_WILD)
212 X::deactivateWild(*this);
213 else if (BlockManager::isSpecialColorFlavor(flavor))
214 X::deactivateSpecialColor();
216 // delete ourselves
217 BlockManager::deleteBlock(this);
219 // if we just started dying
220 } else if (alarm == GC_DYING_DELAY - 1)
221 // grab the elimination magnitude from our combo
222 pop_alarm = current_combo->latest_magnitude;
226 void Block::startFalling ( ComboTabulator *combo, bool no_hang )
228 * Although blocks will fall on their own, this must be called to syncronize
229 * and connect that falling with a elimination combo.
232 if (!(state & BS_STATIC)) return;
234 // change our state
235 state = BS_FALLING;
237 // set the hang alarm and update the grid
238 if (no_hang) {
239 alarm = 0;
240 Grid::changeState(x, y, this, GR_FALLING);
242 } else {
243 alarm = Game::time_step + GC_HANG_DELAY;
244 Grid::changeState(x, y, this, GR_HANGING | GR_FALLING);
247 // let the combo know we're involved
248 if (combo)
249 beginComboInvolvement(combo);
251 // tell our upward neighbor to start a combo fall
252 if (y < GC_PLAY_HEIGHT - 1) {
253 if (Grid::stateAt(x, y + 1) & GR_BLOCK)
254 Grid::blockAt(x, y + 1).startFalling(current_combo, no_hang);
255 else if (Grid::stateAt(x, y + 1) & GR_GARBAGE)
256 Grid::garbageAt(x, y + 1).startFalling(current_combo, no_hang);
260 void Block::startDying ( ComboTabulator *combo, int spark_number )
262 // change the game state
263 Game::dying_count++;
264 Game::dying_count_2++;
266 // let the combo know we're in
267 beginComboInvolvement(combo);
269 // change our state
270 state = BS_DYING;
272 // set the alarm; the alarm works this way due to display needs
273 alarm = GC_DYING_DELAY;
275 // update the grid
276 Grid::changeState(x, y, this, GR_IMMUTABLE);
278 // generate a random rotation axis
279 Random::angle(axis_x, axis_y);
282 void Block::startSwapping ( int direction )
284 // change our state and swap direction
285 state = BS_SWAPPING | (direction & SA_RIGHT ? BS_SWAP_DIRECTION_MASK : 0);
287 // update the grid
288 Grid::changeState(x, y, this, GR_IMMUTABLE);
291 void Block::finishSwapping ( int s_x )
293 // change our state
294 state = BS_STATIC;
295 x = s_x;
297 // update the grid
298 Grid::addBlock(x, y, this, GR_BLOCK);