Game end works this way now:
[crack-attack.git] / src / GarbageGenerator.cxx
bloba22b8c1d7f35fb9a11a036212d23392161355137
1 /*
2 * GarbageGenerator.cxx
3 * Daniel Nelson - 8/25/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 * Displays and sends garbage to the opponent.
28 #include <iostream>
30 using namespace std;
32 #include "Game.h"
33 #include "GarbageGenerator.h"
34 #include "Block.h"
35 #include "BlockManager.h"
36 #include "Garbage.h"
37 #include "GarbageManager.h"
38 #include "ComboTabulator.h"
39 #include "Communicator.h"
40 #include "SparkleManager.h"
41 #include "SignManager.h"
42 #include "ComputerPlayer.h"
44 GarbageQueueElement GarbageGenerator::garbage_queue[GC_GARBAGE_QUEUE_SIZE];
45 int GarbageGenerator::waiting_count;
47 void GarbageGenerator::gameStart ( )
49 waiting_count = 0;
50 for (int n = GC_GARBAGE_QUEUE_SIZE; n--; )
51 garbage_queue[n].active = false;
54 void GarbageGenerator::comboElimination ( ComboTabulator &combo )
56 int sibling = (combo.multiplier > 1 ? 1 : 0);
58 // used by blocks to determine death spark number
59 combo.latest_magnitude = combo.special_magnitude + combo.magnitude
60 + combo.multiplier - 1;
62 // send the special garbage
64 bool special_sign = true;
65 for (int n = BF_NUMBER_SPECIAL; n--; ) {
66 if (combo.special[n]) {
67 special_sign = false;
68 SignManager::createSign(combo.x, combo.y, ST_SPECIAL, n + 1);
70 if (BlockManager::isColorlessCode(n))
71 combo.special_magnitude -= combo.special[n];
73 while (combo.special[n]--) {
74 sendSpecialGarbage(GarbageManager::mapBlockCodeToGarbageFlavor(n));
75 SparkleManager::createRewardMote(combo.x, combo.y, n + 4, sibling++);
77 combo.special[n] = 0;
81 // send the gray garbage
83 if (combo.special_magnitude >= GC_MIN_PATTERN_LENGTH) {
84 if (special_sign)
85 SignManager::createSign(combo.x, combo.y, ST_SPECIAL, 0);
87 combo.special_magnitude -= GC_MIN_PATTERN_LENGTH - 2;
88 while (--combo.special_magnitude) {
90 sendSpecialGarbage(GF_GRAY);
91 SparkleManager::createRewardMote(combo.x, combo.y, 3, sibling++);
94 } else
95 combo.special_magnitude = 0;
97 // send the normal garbage
99 if (combo.magnitude > GC_MIN_PATTERN_LENGTH) {
100 SignManager::createSign(combo.x, combo.y, ST_MAGNITUDE,
101 combo.magnitude - 4);
103 if (combo.magnitude <= GC_PLAY_WIDTH) {
105 sendGarbage(1, combo.magnitude - 1, GF_NORMAL);
106 SparkleManager::createRewardMote(combo.x, combo.y,
107 combo.magnitude - 4, sibling++);
109 } else if (combo.magnitude < 2 * GC_PLAY_WIDTH - 1) {
111 sendGarbage(1, combo.magnitude - (combo.magnitude >> 1),
112 GF_NORMAL);
113 SparkleManager::createRewardMote(combo.x, combo.y,
114 combo.magnitude - (combo.magnitude >> 1) - 3, sibling++);
116 sendGarbage(1, combo.magnitude >> 1, GF_NORMAL);
117 SparkleManager::createRewardMote(combo.x, combo.y,
118 (combo.magnitude >> 1) - 3, sibling++);
120 } else {
121 combo.magnitude += GC_MIN_PATTERN_LENGTH;
122 while (combo.magnitude > GC_PLAY_WIDTH - 1) {
124 sendGarbage(1, GC_PLAY_WIDTH - 1, GF_NORMAL);
125 SparkleManager::createRewardMote(combo.x, combo.y,
126 GC_PLAY_WIDTH - 4, sibling++);
128 combo.magnitude -= GC_PLAY_WIDTH - 1;
131 if (combo.magnitude >= GC_MIN_PATTERN_LENGTH) {
133 sendGarbage(1, combo.magnitude, GF_NORMAL);
134 SparkleManager::createRewardMote(combo.x, combo.y,
135 combo.magnitude - 3, sibling);
140 combo.magnitude = 0;
143 void GarbageGenerator::comboComplete ( ComboTabulator &combo )
145 // send the multiplier garbage
146 if (combo.multiplier > 1)
147 sendGarbage(combo.multiplier - 1, GC_PLAY_WIDTH, GF_NORMAL);
150 void GarbageGenerator::addToQueue ( CommunicationBuffer &buffer )
152 addToQueue(buffer.garbage, buffer.count);
155 void GarbageGenerator::addToQueue (uint32 height, uint32 width, uint32 flavor, uint32 stamp)
157 assert(height <= GC_PLAY_HEIGHT);
158 assert(width <= GC_PLAY_WIDTH);
159 if (!GarbageManager::isSpecialFlavor(flavor))
160 dealLocalGarbage(height, width, flavor, stamp);
161 else
162 dealSpecialLocalGarbage(flavor, stamp);
165 void GarbageGenerator::addToQueue ( GarbageQueueElement &element )
167 int stamp = Game::time_step;
168 GarbageQueueElement e = element;
169 addToQueue(e.height, e.width, e.flavor, stamp);
172 void GarbageGenerator::addToQueue ( BufferElement *garbage, size_t size ) {
173 for (size_t n = 0; n < size; n++) {
174 BufferElement e = garbage[n];
175 addToQueue(e.height, e.width, e.flavor, e.time_stamp);
179 void GarbageGenerator::dealLocalGarbage ( int height, int width, int flavor,
180 int time_stamp )
182 * Used for solo games.
185 if (waiting_count == GC_GARBAGE_QUEUE_SIZE) return;
187 int i = 0;
188 while (garbage_queue[i].active) i++;
190 garbage_queue[i].active = true;
191 garbage_queue[i].height = height;
192 garbage_queue[i].width = width;
193 garbage_queue[i].flavor = flavor;
194 garbage_queue[i].alarm = determineDropTime(time_stamp);
196 waiting_count++;
199 void GarbageGenerator::dealSpecialLocalGarbage ( int flavor, int time_stamp )
201 switch (flavor) {
202 case GF_GRAY: case GF_WHITE: case GF_COLOR_2:
203 dealLocalGarbage(1, GC_PLAY_WIDTH, flavor, time_stamp);
204 break;
206 case GF_BLACK:
207 dealLocalGarbage(1, 2, GF_BLACK, time_stamp);
208 break;
210 case GF_COLOR_1:
211 if (Random::chanceIn2(4)) {
212 dealLocalGarbage(2, 2, GF_COLOR_1, time_stamp);
213 for (int n = 1 + Random::number(3); n--; )
214 dealLocalGarbage(1, 1, GF_COLOR_1, time_stamp);
215 } else
216 for (int n = 5 + Random::number(3); n--; )
217 dealLocalGarbage(1, 1, GF_COLOR_1, time_stamp);
218 break;
220 case GF_COLOR_3:
221 dealLocalGarbage(1, 4, GF_COLOR_3, time_stamp);
222 break;
224 case GF_COLOR_4:
225 dealLocalGarbage(1, 3, GF_COLOR_4, time_stamp);
226 break;
228 case GF_COLOR_5:
229 dealLocalGarbage(3, 2, GF_COLOR_5, time_stamp);
230 break;
234 void GarbageGenerator::timeStep ( )
236 int c = waiting_count;
238 for (int n = 0; c; n++)
239 if (garbage_queue[n].active) {
240 GarbageQueueElement &e = garbage_queue[n];
241 c--;
243 // if this garbage's ready, let's try to drop it
244 if (e.alarm < Game::time_step) {
245 // if we successfully drop it, take it away
246 if (GarbageManager::newFallingGarbage(e.height, e.width, e.flavor)) {
247 waiting_count--;
248 e.active = false;
250 // otherwise, reset the alarm
251 } else
252 e.alarm = Game::time_step + GC_AVERAGE_GARBAGE_DROP_DELAY;
257 void GarbageGenerator::sendGarbage ( int height, int width, int flavor )
259 if (!(MetaState::mode & CM_SOLO))
260 Communicator::sendGarbage(height, width, flavor);
261 else
262 if (MetaState::mode & CM_AI)
263 ComputerPlayer::addGarbage(height, width, flavor);
264 else
265 dealLocalGarbage(height, width, flavor, Game::time_step);
268 void GarbageGenerator::sendSpecialGarbage ( int flavor )
270 if (!(MetaState::mode & CM_SOLO))
271 Communicator::sendGarbage(0, 0, flavor);
272 else
273 if (MetaState::mode & CM_AI)
274 ComputerPlayer::addGarbage(1, GC_PLAY_WIDTH, flavor);
275 else
276 dealSpecialLocalGarbage(flavor, Game::time_step);