3 * Daniel Nelson - 8/25/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 * Displays and sends garbage to the opponent.
28 #include "GarbageGenerator.h"
34 #include "BlockManager.h"
36 #include "GarbageManager.h"
37 #include "ComboTabulator.h"
38 #include "Communicator.h"
39 #include "SparkleManager.h"
40 #include "SignManager.h"
41 #include "ComputerPlayer.h"
43 GarbageQueueElement
GarbageGenerator::garbage_queue
[GC_GARBAGE_QUEUE_SIZE
];
44 int GarbageGenerator::waiting_count
;
46 void GarbageGenerator::gameStart ( )
49 for (int n
= GC_GARBAGE_QUEUE_SIZE
; n
--; )
50 garbage_queue
[n
].active
= false;
53 void GarbageGenerator::comboElimination ( ComboTabulator
&combo
)
55 int sibling
= (combo
.multiplier
> 1 ? 1 : 0);
57 // used by blocks to determine death spark number
58 combo
.latest_magnitude
= combo
.special_magnitude
+ combo
.magnitude
59 + combo
.multiplier
- 1;
61 // send the special garbage
63 bool special_sign
= true;
64 for (int n
= BF_NUMBER_SPECIAL
; n
--; ) {
65 if (combo
.special
[n
]) {
67 SignManager::createSign(combo
.x
, combo
.y
, ST_SPECIAL
, n
+ 1);
69 if (BlockManager::isColorlessCode(n
))
70 combo
.special_magnitude
-= combo
.special
[n
];
72 while (combo
.special
[n
]--) {
73 sendSpecialGarbage(GarbageManager::mapBlockCodeToGarbageFlavor(n
));
74 SparkleManager::createRewardMote(combo
.x
, combo
.y
, n
+ 4, sibling
++);
80 // send the gray garbage
82 if (combo
.special_magnitude
>= GC_MIN_PATTERN_LENGTH
) {
84 SignManager::createSign(combo
.x
, combo
.y
, ST_SPECIAL
, 0);
86 combo
.special_magnitude
-= GC_MIN_PATTERN_LENGTH
- 2;
87 while (--combo
.special_magnitude
) {
89 sendSpecialGarbage(GF_GRAY
);
90 SparkleManager::createRewardMote(combo
.x
, combo
.y
, 3, sibling
++);
94 combo
.special_magnitude
= 0;
96 // send the normal garbage
98 if (combo
.magnitude
> GC_MIN_PATTERN_LENGTH
) {
99 SignManager::createSign(combo
.x
, combo
.y
, ST_MAGNITUDE
,
100 combo
.magnitude
- 4);
102 if (combo
.magnitude
<= GC_PLAY_WIDTH
) {
104 sendGarbage(1, combo
.magnitude
- 1, GF_NORMAL
);
105 SparkleManager::createRewardMote(combo
.x
, combo
.y
,
106 combo
.magnitude
- 4, sibling
++);
108 } else if (combo
.magnitude
< 2 * GC_PLAY_WIDTH
- 1) {
110 sendGarbage(1, combo
.magnitude
- (combo
.magnitude
>> 1),
112 SparkleManager::createRewardMote(combo
.x
, combo
.y
,
113 combo
.magnitude
- (combo
.magnitude
>> 1) - 3, sibling
++);
115 sendGarbage(1, combo
.magnitude
>> 1, GF_NORMAL
);
116 SparkleManager::createRewardMote(combo
.x
, combo
.y
,
117 (combo
.magnitude
>> 1) - 3, sibling
++);
120 combo
.magnitude
+= GC_MIN_PATTERN_LENGTH
;
121 while (combo
.magnitude
> GC_PLAY_WIDTH
- 1) {
123 sendGarbage(1, GC_PLAY_WIDTH
- 1, GF_NORMAL
);
124 SparkleManager::createRewardMote(combo
.x
, combo
.y
,
125 GC_PLAY_WIDTH
- 4, sibling
++);
127 combo
.magnitude
-= GC_PLAY_WIDTH
- 1;
130 if (combo
.magnitude
>= GC_MIN_PATTERN_LENGTH
) {
132 sendGarbage(1, combo
.magnitude
, GF_NORMAL
);
133 SparkleManager::createRewardMote(combo
.x
, combo
.y
,
134 combo
.magnitude
- 3, sibling
);
142 void GarbageGenerator::comboComplete ( ComboTabulator
&combo
)
144 // send the multiplier garbage
145 if (combo
.multiplier
> 1)
146 sendGarbage(combo
.multiplier
- 1, GC_PLAY_WIDTH
, GF_NORMAL
);
149 void GarbageGenerator::addToQueue ( GarbageBuffer
&buffer
)
151 addToQueue(buffer
.garbage
, buffer
.count
);
154 void GarbageGenerator::addToQueue (uint32 height
, uint32 width
, uint32 flavor
, uint32 stamp
)
156 assert(height
<= GC_PLAY_HEIGHT
);
157 assert(width
<= GC_PLAY_WIDTH
);
158 if (!GarbageManager::isSpecialFlavor(flavor
))
159 dealLocalGarbage(height
, width
, flavor
, stamp
);
161 dealSpecialLocalGarbage(flavor
, stamp
);
164 void GarbageGenerator::addToQueue ( GarbageQueueElement
&element
)
166 int stamp
= Game::time_step
;
167 GarbageQueueElement e
= element
;
168 addToQueue(e
.height
, e
.width
, e
.flavor
, stamp
);
171 void GarbageGenerator::addToQueue ( BufferElement
*garbage
, size_t size
) {
172 for (size_t n
= 0; n
< size
; n
++) {
173 BufferElement e
= garbage
[n
];
174 addToQueue(e
.height
, e
.width
, e
.flavor
, e
.time_stamp
);
178 void GarbageGenerator::dealLocalGarbage ( int height
, int width
, int flavor
,
181 * Used for solo games.
184 if (waiting_count
== GC_GARBAGE_QUEUE_SIZE
) return;
187 while (garbage_queue
[i
].active
) i
++;
189 garbage_queue
[i
].active
= true;
190 garbage_queue
[i
].height
= height
;
191 garbage_queue
[i
].width
= width
;
192 garbage_queue
[i
].flavor
= flavor
;
193 garbage_queue
[i
].alarm
= determineDropTime(time_stamp
);
198 void GarbageGenerator::dealSpecialLocalGarbage ( int flavor
, int time_stamp
)
201 case GF_GRAY
: case GF_WHITE
: case GF_COLOR_2
:
202 dealLocalGarbage(1, GC_PLAY_WIDTH
, flavor
, time_stamp
);
206 dealLocalGarbage(1, 2, GF_BLACK
, time_stamp
);
210 if (Random::chanceIn2(4)) {
211 dealLocalGarbage(2, 2, GF_COLOR_1
, time_stamp
);
212 for (int n
= 1 + Random::number(3); n
--; )
213 dealLocalGarbage(1, 1, GF_COLOR_1
, time_stamp
);
215 for (int n
= 5 + Random::number(3); n
--; )
216 dealLocalGarbage(1, 1, GF_COLOR_1
, time_stamp
);
220 dealLocalGarbage(1, 4, GF_COLOR_3
, time_stamp
);
224 dealLocalGarbage(1, 3, GF_COLOR_4
, time_stamp
);
228 dealLocalGarbage(3, 2, GF_COLOR_5
, time_stamp
);
233 void GarbageGenerator::timeStep ( )
235 int c
= waiting_count
;
237 for (int n
= 0; c
; n
++)
238 if (garbage_queue
[n
].active
) {
239 GarbageQueueElement
&e
= garbage_queue
[n
];
242 // if this garbage's ready, let's try to drop it
243 if (e
.alarm
< Game::time_step
) {
244 // if we successfully drop it, take it away
245 if (GarbageManager::newFallingGarbage(e
.height
, e
.width
, e
.flavor
)) {
249 // otherwise, reset the alarm
251 e
.alarm
= Game::time_step
+ GC_AVERAGE_GARBAGE_DROP_DELAY
;
256 void GarbageGenerator::sendGarbage ( int height
, int width
, int flavor
)
258 if (!(MetaState::mode
& CM_SOLO
))
259 Communicator::sendGarbage(height
, width
, flavor
);
261 if (MetaState::mode
& CM_AI
)
262 ComputerPlayer::addGarbage(height
, width
, flavor
);
264 dealLocalGarbage(height
, width
, flavor
, Game::time_step
);
267 void GarbageGenerator::sendSpecialGarbage ( int flavor
)
269 if (!(MetaState::mode
& CM_SOLO
))
270 Communicator::sendGarbage(0, 0, flavor
);
272 if (MetaState::mode
& CM_AI
)
273 ComputerPlayer::addGarbage(1, GC_PLAY_WIDTH
, flavor
);
275 dealSpecialLocalGarbage(flavor
, Game::time_step
);