3 * Daniel Nelson - 8/21/0
5 * Copyright (C) 2000 Daniel Nelson
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
25 * The block object, of which each block is one.
30 #include "BlockManager.h"
31 #include "ComboTabulator.h"
36 #include "SparkleManager.h"
41 void Block::initializeStatic ( int _x
, int _y
, int _flavor
)
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
)
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
)
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
)
104 if (alarm
== Game::time_step
) {
106 // change the game state
107 Game::awaking_count
--;
109 // change our state; startFalling() and eliminations check for
113 // if we're going to fall
114 if (Grid::stateAt(x
, y
- 1) & GR_EMPTY
)
115 startFalling(current_combo
, true);
119 Grid::changeState(x
, y
, this, GR_BLOCK
);
121 // register for elimination checking
122 Grid::requestEliminationCheck(*this, current_combo
);
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
140 // if the hang alarm has gone off
143 // if we're at the bottom of a grid element
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
151 f_y
= GC_STEPS_PER_GRID
;
154 Grid::remove(x
, y
+ 1, this);
155 Grid::addBlock(x
, y
, this, GR_FALLING
);
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
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.
185 // change the game state
187 Game::dying_count_2
--;
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
);
207 SparkleManager::createBlockDeathSpark(x
, y
, X::wildFlavor(*this),
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();
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;
237 // set the hang alarm and update the grid
240 Grid::changeState(x
, y
, this, GR_FALLING
);
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
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
264 Game::dying_count_2
++;
266 // let the combo know we're in
267 beginComboInvolvement(combo
);
272 // set the alarm; the alarm works this way due to display needs
273 alarm
= GC_DYING_DELAY
;
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);
288 Grid::changeState(x
, y
, this, GR_IMMUTABLE
);
291 void Block::finishSwapping ( int s_x
)
298 Grid::addBlock(x
, y
, this, GR_BLOCK
);