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.
33 #include "GarbageGenerator.h"
35 #include "BlockManager.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 ( )
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
]) {
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
++);
81 // send the gray garbage
83 if (combo
.special_magnitude
>= GC_MIN_PATTERN_LENGTH
) {
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
++);
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),
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
++);
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
);
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
);
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
,
182 * Used for solo games.
185 if (waiting_count
== GC_GARBAGE_QUEUE_SIZE
) return;
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
);
199 void GarbageGenerator::dealSpecialLocalGarbage ( int flavor
, int time_stamp
)
202 case GF_GRAY
: case GF_WHITE
: case GF_COLOR_2
:
203 dealLocalGarbage(1, GC_PLAY_WIDTH
, flavor
, time_stamp
);
207 dealLocalGarbage(1, 2, GF_BLACK
, time_stamp
);
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
);
216 for (int n
= 5 + Random::number(3); n
--; )
217 dealLocalGarbage(1, 1, GF_COLOR_1
, time_stamp
);
221 dealLocalGarbage(1, 4, GF_COLOR_3
, time_stamp
);
225 dealLocalGarbage(1, 3, GF_COLOR_4
, time_stamp
);
229 dealLocalGarbage(3, 2, GF_COLOR_5
, time_stamp
);
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
];
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
)) {
250 // otherwise, reset the alarm
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
);
262 if (MetaState::mode
& CM_AI
)
263 ComputerPlayer::addGarbage(height
, width
, flavor
);
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
);
273 if (MetaState::mode
& CM_AI
)
274 ComputerPlayer::addGarbage(1, GC_PLAY_WIDTH
, flavor
);
276 dealSpecialLocalGarbage(flavor
, Game::time_step
);