source: trunk/monsterz/fusion.cpp @ 346

Last change on this file since 346 was 346, checked in by sam, 10 years ago

Remove unused variable.

  • Property svn:keywords set to Id
File size: 9.7 KB
Line 
1//
2// Monsterz
3//
4// Copyright: (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <cstdio>
16#include <cmath>
17#include <cstdlib>
18#include <cstring>
19#include <ctime>
20
21#include "core.h"
22#include "fusion.h"
23#include "piece.h"
24#include "thumbs.h"
25#include "mash.h"
26#include "monsterz.h"
27
28/*
29 * Fusion implementation class
30 */
31
32class FusionData
33{
34    friend class Fusion;
35
36private:
37    int2 dim;
38    int npieces, maxnpieces;
39    int board, tiles;
40
41    struct Pair
42    {
43        int id;
44        Piece *piece;
45    }
46    pairs[MAX_WIDTH][MAX_HEIGHT], current[2];
47    int next[2], rotation;
48
49    Text *scoretext;
50    int score;
51
52    Mash *mashes;
53    Emitter *emitter;
54    Thumbs *thumbs;
55
56    enum
57    {
58        IDLE,
59    }
60    state;
61};
62
63/*
64 * Public Fusion class
65 */
66
67Fusion::Fusion(int2 dim, int npieces, int maxnpieces)
68  : data(new FusionData())
69{
70    data->dim = dim;
71    data->npieces = npieces;
72    data->maxnpieces = maxnpieces;
73    data->board = Tiler::Register(PNG_BOARD, 384, 384, 1.0f);
74    data->tiles = Tiler::Register(PNG_TILES, 48, 48, 1.0f);
75
76    data->emitter = new Emitter(data->tiles, float3(0, -0.0006f, 0));
77    Ticker::Ref(data->emitter);
78
79    data->thumbs = new Thumbs(npieces);
80    Ticker::Ref(data->thumbs);
81
82    for (int j = 0; j < data->dim.j; j++)
83        for (int i = 0; i < data->dim.i; i++)
84            data->pairs[i][j].id = 0;
85
86    data->current[0].id = 1 + rand() % data->npieces;
87    data->current[1].id = 1 + rand() % data->npieces;
88    data->current[0].piece = new Piece(data->emitter, int2(3, 8),
89                                       80 + 20 * data->current[0].id);
90    data->current[1].piece = new Piece(data->emitter, int2(4, 8),
91                                       80 + 20 * data->current[1].id);
92    Ticker::Ref(data->current[0].piece);
93    Ticker::Ref(data->current[1].piece);
94    data->current[0].piece->SetPos(int2(3, 7) * 48);
95    data->current[1].piece->SetPos(int2(4, 7) * 48);
96
97    data->mashes = NULL;
98
99    data->next[0] = 1 + rand() % data->npieces;
100    data->next[1] = 1 + rand() % data->npieces;
101    data->rotation = 0;
102
103    data->state = FusionData::IDLE;
104
105    position = int3(24, 72, 1);
106    bbox[0] = position;
107    bbox[1] = bbox[0] + int3(384, 384, 0);
108
109    Input::TrackMouse(this);
110}
111
112void Fusion::TickGame(float deltams)
113{
114    Entity::TickGame(deltams);
115
116    /* Get rid of finished mashes */
117    for (Mash **it = &data->mashes; *it; )
118    {
119        if ((*it)->IsDead())
120        {
121            Ticker::Unref(*it);
122            *it = (*it)->nextmash;
123        }
124        else
125            it = &(*it)->nextmash;
126    }
127
128    int column = -1;
129
130    if (clicked[2])
131    {
132        column = data->current[0].piece->GetCell().x;
133        data->rotation = (data->rotation + 1) % 2;
134        if (column - data->rotation > data->dim.i - 1)
135            column = data->dim.i - 1 - data->rotation;
136        if (!data->rotation)
137        {
138            FusionData::Pair tmp = data->current[0];
139            data->current[0] = data->current[1];
140            data->current[1] = tmp;
141            if (column == data->dim.i - 1)
142                column = 6;
143        }
144    }
145
146    if (mousepos.x != -1
147        && mousepos.x / 48 != data->current[0].piece->GetCell().x)
148    {
149        column = mousepos.x / 48;
150        column = column < 0 ? 0 : column > data->dim.i - 2 + data->rotation ? data->dim.i - 2 + data->rotation : column;
151    }
152
153    if (column != -1)
154    {
155        if (data->rotation)
156        {
157            data->current[0].piece->SetCell(int2(column, 6));
158            data->current[1].piece->SetCell(int2(column, 7));
159        }
160        else
161        {
162            data->current[0].piece->SetCell(int2(column, 7));
163            data->current[1].piece->SetCell(int2(column + 1, 7));
164        }
165
166        data->current[0].piece->Move(data->current[0].piece->GetCell() * 48);
167        data->current[1].piece->Move(data->current[1].piece->GetCell() * 48);
168    }
169
170    if (clicked[0])
171    {
172        for (int t = 0; t < 2; t++)
173        {
174            int i = data->current[t].piece->GetCell().i;
175            for (int j = 0; j < 7; j++)
176                if (data->pairs[i][j].id == 0)
177                {
178                    data->current[t].piece->SetCell(int2(i, j));
179                    data->current[t].piece->Move(int2(i, j) * 48);
180                    data->pairs[i][j] = data->current[t];
181                    break;
182                }
183        }
184
185        data->current[0].id = data->next[0];
186        data->current[1].id = data->next[1];
187        data->current[0].piece = new Piece(data->emitter, int2(3, 7),
188                                           80 + 20 * data->current[0].id);
189        data->current[1].piece = new Piece(data->emitter, int2(4, 7),
190                                           80 + 20 * data->current[1].id);
191        Ticker::Ref(data->current[0].piece);
192        Ticker::Ref(data->current[1].piece);
193        data->current[0].piece->SetPos(int2(3, 8) * 48);
194        data->current[1].piece->SetPos(int2(4, 8) * 48);
195        data->current[0].piece->Move(data->current[0].piece->GetCell() * 48);
196        data->current[1].piece->Move(data->current[1].piece->GetCell() * 48);
197        data->next[0] = 1 + rand() % data->npieces;
198        data->next[1] = 1 + rand() % data->npieces;
199        data->rotation = 0;
200
201        Resolve();
202    }
203
204    switch (data->state)
205    {
206    case FusionData::IDLE:
207        break;
208    }
209}
210
211void Fusion::TickDraw(float deltams)
212{
213    Entity::TickDraw(deltams);
214
215    Scene::GetDefault()->AddTile((data->board << 16) | 0,
216                                 position.x, position.y, 1, 0);
217}
218
219void Fusion::Resolve()
220{
221    int list[MAX_PIECES][MAX_PIECES];
222    int count[MAX_PIECES * MAX_PIECES];
223
224    for (int j = 0; j < data->dim.j; j++)
225        for (int i = 0; i < data->dim.i; i++)
226            list[i][j] = -1;
227    memset(count, 0, sizeof(count));
228
229    int seq = 0, effect = 0;
230
231    /* Count connected tiles */
232    for (int j = 0; j < data->dim.j; j++) for (int i = 0; i < data->dim.i; i++)
233    {
234        if (!data->pairs[i][j].id)
235            continue;
236
237        if (data->pairs[i][j].id >= data->maxnpieces)
238            continue;
239
240        if (list[i][j] != -1)
241            continue;
242
243        list[i][j] = seq;
244        count[seq] = TagNeighbours(list, i, j);
245        if (count[seq] >= 3)
246            effect = 1;
247        seq++;
248    }
249
250    /* Only continue if there is an effect */
251    if (!effect)
252        return;
253
254    /* Add tiles to a mash; add mash to our list */
255    Mash *mash = new Mash(data->emitter);
256    Ticker::Ref(mash);
257
258    for (int j = 0; j < data->dim.j; j++) for (int i = 0; i < data->dim.i; i++)
259    {
260        if (list[i][j] == -1)
261            continue;
262        if (count[list[i][j]] < 3)
263            continue;
264
265        mash->AddPiece(data->pairs[i][j].piece);
266        data->pairs[i][j].piece = NULL;
267    }
268
269    mash->nextmash = data->mashes;
270    data->mashes = mash;
271
272    /* Create new pieces where necessary */
273    for (int j = 0; j < data->dim.j; j++) for (int i = 0; i < data->dim.i; i++)
274    {
275        if (list[i][j] == -1)
276            continue;
277        if (count[list[i][j]] < 3)
278        {
279            if (!data->pairs[i][j].piece)
280                data->pairs[i][j].id = 0;
281            continue;
282        }
283
284        data->pairs[i][j].id++;
285        if (data->pairs[i][j].id > data->npieces
286                && data->pairs[i][j].id <= data->maxnpieces)
287        {
288            data->npieces++;
289            data->thumbs->SetMax(data->npieces);
290        }
291        data->pairs[i][j].piece = new Piece(data->emitter, int2(i, j), 80 + 20 * data->pairs[i][j].id);
292        Ticker::Ref(data->pairs[i][j].piece);
293        data->pairs[i][j].piece->SetPos(int2(i, j) * 48);
294        count[list[i][j]] = 0;
295        list[i][j] = -1;
296    }
297
298    /* Move everything down */
299    for (int j = data->dim.j; j--;) for (int i = 0; i < data->dim.i; i++)
300    {
301        if (list[i][j] == -1 || data->pairs[i][j].piece)
302            continue;
303
304        for (int j2 = j + 1; j2 < data->dim.j; j2++)
305        {
306            data->pairs[i][j2 - 1] = data->pairs[i][j2];
307            if (data->pairs[i][j2 - 1].id)
308            {
309                data->pairs[i][j2 - 1].piece->SetCell(int2(i, j2 - 1));
310                data->pairs[i][j2 - 1].piece->Move(int2(i, j2 - 1) * 48);
311            }
312            list[i][j2 - 1] = list[i][j2];
313        }
314
315        data->pairs[i][data->dim.j - 1].id = 0;
316        list[i][data->dim.j - 1] = -1;
317    }
318
319    /* Start again (FIXME: make this a while() loop) */
320    Resolve();
321}
322
323int Fusion::TagNeighbours(int list[MAX_PIECES][MAX_PIECES], int i, int j)
324{
325    int2 const off[] = { int2(-1, 0), int2(1, 0), int2(0, -1), int2(0, 1) };
326
327    int count = 1;
328
329    for (int n = 0; n < 4; n++)
330    {
331        int i2 = i + off[n].i;
332        int j2 = j + off[n].j;
333
334        if (i2 >= 0 && i2 < data->dim.i && j2 >= 0 && j2 < data->dim.j
335             && data->pairs[i2][j2].id == data->pairs[i][j].id
336             && list[i2][j2] == -1)
337        {
338            list[i2][j2] = list[i][j];
339            count += TagNeighbours(list, i2, j2);
340        }
341    }
342    return count;
343}
344
345Fusion::~Fusion()
346{
347    Input::UntrackMouse(this);
348
349    Ticker::Unref(data->thumbs);
350    while (data->mashes)
351    {
352        Ticker::Unref(data->mashes);
353        data->mashes = data->mashes->nextmash;
354    }
355    for (int j = 0; j < data->dim.j; j++)
356        for (int i = 0; i < data->dim.i; i++)
357            if (data->pairs[i][j].id)
358                Ticker::Unref(data->pairs[i][j].piece);
359    Ticker::Unref(data->current[0].piece);
360    Ticker::Unref(data->current[1].piece);
361    Ticker::Unref(data->emitter);
362    Tiler::Deregister(data->board);
363    Tiler::Deregister(data->tiles);
364    delete data;
365}
366
Note: See TracBrowser for help on using the repository browser.