source: trunk/monsterz/fusion.cpp @ 344

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

Rough Fusion gameplay almost complete.

  • Property svn:keywords set to Id
File size: 10.1 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;
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)
68  : data(new FusionData())
69{
70    data->dim = dim;
71    data->npieces = npieces;
72    data->board = Tiler::Register(PNG_BOARD, 384, 384, 1.0f);
73    data->tiles = Tiler::Register(PNG_TILES, 48, 48, 1.0f);
74
75    data->emitter = new Emitter(data->tiles, float3(0, -0.0006f, 0));
76    Ticker::Ref(data->emitter);
77
78    data->thumbs = new Thumbs(npieces);
79    Ticker::Ref(data->thumbs);
80
81    for (int j = 0; j < data->dim.j; j++)
82        for (int i = 0; i < data->dim.i; i++)
83            data->pairs[i][j].id = 0;
84
85    data->current[0].id = 1 + rand() % data->npieces;
86    data->current[1].id = 1 + rand() % data->npieces;
87    data->current[0].piece = new Piece(data->emitter, int2(3, 8),
88                                       80 + 20 * data->current[0].id);
89    data->current[1].piece = new Piece(data->emitter, int2(4, 8),
90                                       80 + 20 * data->current[1].id);
91    Ticker::Ref(data->current[0].piece);
92    Ticker::Ref(data->current[1].piece);
93    data->current[0].piece->SetPos(int2(3, 7) * 48);
94    data->current[1].piece->SetPos(int2(4, 7) * 48);
95
96    data->mashes = NULL;
97
98    data->next[0] = 1 + rand() % data->npieces;
99    data->next[1] = 1 + rand() % data->npieces;
100    data->rotation = 0;
101
102    data->state = FusionData::IDLE;
103
104    position = int3(24, 72, 1);
105    bbox[0] = position;
106    bbox[1] = bbox[0] + int3(384, 384, 0);
107
108    Input::TrackMouse(this);
109}
110
111void Fusion::TickGame(float deltams)
112{
113    Entity::TickGame(deltams);
114
115    int3 buttons = Input::GetMouseButtons();
116
117    /* Get rid of finished mashes */
118    for (Mash **it = &data->mashes; *it; )
119    {
120        if ((*it)->IsDead())
121        {
122            Ticker::Unref(*it);
123            *it = (*it)->nextmash;
124        }
125        else
126            it = &(*it)->nextmash;
127    }
128
129    int column = -1;
130
131    if (clicked[2])
132    {
133        column = data->current[0].piece->GetCell().x;
134        data->rotation = (data->rotation + 1) % 2;
135        if (column - data->rotation > data->dim.i - 1)
136            column = data->dim.i - 1 - data->rotation;
137        if (!data->rotation)
138        {
139            FusionData::Pair tmp = data->current[0];
140            data->current[0] = data->current[1];
141            data->current[1] = tmp;
142            if (column == data->dim.i - 1)
143                column = 6;
144        }
145    }
146
147    if (mousepos.x != -1
148        && mousepos.x / 48 != data->current[0].piece->GetCell().x)
149    {
150        column = mousepos.x / 48;
151        column = column < 0 ? 0 : column > data->dim.i - 2 + data->rotation ? data->dim.i - 2 + data->rotation : column;
152    }
153
154    if (column != -1)
155    {
156        if (data->rotation)
157        {
158            data->current[0].piece->SetCell(int2(column, 6));
159            data->current[1].piece->SetCell(int2(column, 7));
160        }
161        else
162        {
163            data->current[0].piece->SetCell(int2(column, 7));
164            data->current[1].piece->SetCell(int2(column + 1, 7));
165        }
166
167        data->current[0].piece->Move(data->current[0].piece->GetCell() * 48);
168        data->current[1].piece->Move(data->current[1].piece->GetCell() * 48);
169    }
170
171    if (clicked[0])
172    {
173        for (int t = 0; t < 2; t++)
174        {
175            int i = data->current[t].piece->GetCell().i;
176            for (int j = 0; j < 7; j++)
177                if (data->pairs[i][j].id == 0)
178                {
179                    data->current[t].piece->SetCell(int2(i, j));
180                    data->current[t].piece->Move(int2(i, j) * 48);
181                    data->pairs[i][j] = data->current[t];
182                    break;
183                }
184        }
185
186        data->current[0].id = data->next[0];
187        data->current[1].id = data->next[1];
188        data->current[0].piece = new Piece(data->emitter, int2(3, 7),
189                                           80 + 20 * data->current[0].id);
190        data->current[1].piece = new Piece(data->emitter, int2(4, 7),
191                                           80 + 20 * data->current[1].id);
192        Ticker::Ref(data->current[0].piece);
193        Ticker::Ref(data->current[1].piece);
194        data->current[0].piece->SetPos(int2(3, 8) * 48);
195        data->current[1].piece->SetPos(int2(4, 8) * 48);
196        data->current[0].piece->Move(data->current[0].piece->GetCell() * 48);
197        data->current[1].piece->Move(data->current[1].piece->GetCell() * 48);
198        data->next[0] = 1 + rand() % data->npieces;
199        data->next[1] = 1 + rand() % data->npieces;
200        data->rotation = 0;
201
202        Resolve();
203    }
204
205    switch (data->state)
206    {
207    case FusionData::IDLE:
208        break;
209    }
210}
211
212void Fusion::TickDraw(float deltams)
213{
214    Entity::TickDraw(deltams);
215
216    Scene::GetDefault()->AddTile((data->board << 16) | 0,
217                                 position.x, position.y, 1, 0);
218}
219
220void Fusion::Resolve()
221{
222    int list[MAX_PIECES][MAX_PIECES];
223    int count[MAX_PIECES * MAX_PIECES];
224
225    for (int j = 0; j < data->dim.j; j++)
226        for (int i = 0; i < data->dim.i; i++)
227            list[i][j] = -1;
228    memset(count, 0, sizeof(count));
229
230    int seq = 0, effect = 0;
231
232    printf("\npairs:\n");
233    for (int j = data->dim.j; j--;)
234    {
235        for (int i = 0; i < data->dim.i; i++)
236            printf("% 2i ", data->pairs[i][j].id);
237        printf("\n");
238    }
239
240    /* Count connected tiles */
241    for (int j = 0; j < data->dim.j; j++)
242        for (int i = 0; i < data->dim.i; i++)
243        {
244            if (!data->pairs[i][j].id)
245                continue;
246
247            if (list[i][j] != -1)
248                continue;
249
250            list[i][j] = seq;
251            count[seq] = TagNeighbours(list, i, j);
252            if (count[seq] >= 3)
253                effect = 1;
254            seq++;
255        }
256
257    printf("hits:\n");
258    for (int j = data->dim.j; j--;)
259    {
260        for (int i = 0; i < data->dim.i; i++)
261            printf("% 2i ", list[i][j]);
262        printf("\n");
263    }
264
265    /* Only continue if there is an effect */
266    if (!effect)
267        return;
268
269    /* Add tiles to a mash; add mash to our list */
270    Mash *mash = new Mash(data->emitter);
271    Ticker::Ref(mash);
272
273    for (int j = 0; j < data->dim.j; j++)
274        for (int i = 0; i < data->dim.i; i++)
275        {
276            if (list[i][j] == -1)
277                continue;
278            if (count[list[i][j]] < 3)
279                continue;
280
281            mash->AddPiece(data->pairs[i][j].piece);
282            data->pairs[i][j].piece = NULL;
283        }
284
285    mash->nextmash = data->mashes;
286    data->mashes = mash;
287
288    /* Create new pieces where necessary */
289    for (int j = 0; j < data->dim.j; j++)
290        for (int i = 0; i < data->dim.i; i++)
291        {
292            if (list[i][j] == -1)
293                continue;
294            if (count[list[i][j]] < 3)
295            {
296                if (!data->pairs[i][j].piece)
297                    data->pairs[i][j].id = 0;
298                continue;
299            }
300
301            data->pairs[i][j].id++;
302            data->pairs[i][j].piece = new Piece(data->emitter, int2(i, j), 80 + 20 * data->pairs[i][j].id);
303            Ticker::Ref(data->pairs[i][j].piece);
304            data->pairs[i][j].piece->SetPos(int2(i, j) * 48);
305            count[list[i][j]] = 0;
306            list[i][j] = -1;
307        }
308
309    printf("hits 2:\n");
310    for (int j = data->dim.j; j--;)
311    {
312        for (int i = 0; i < data->dim.i; i++)
313            printf("% 2i ", list[i][j]);
314        printf("\n");
315    }
316
317    /* Move everything down */
318    for (int j = data->dim.j; j--;) for (int i = 0; i < data->dim.i; i++)
319    {
320        if (list[i][j] == -1 || data->pairs[i][j].piece)
321            continue;
322
323        for (int j2 = j + 1; j2 < data->dim.j; j2++)
324        {
325            data->pairs[i][j2 - 1] = data->pairs[i][j2];
326            if (data->pairs[i][j2 - 1].id)
327            {
328                data->pairs[i][j2 - 1].piece->SetCell(int2(i, j2 - 1));
329                data->pairs[i][j2 - 1].piece->Move(int2(i, j2 - 1) * 48);
330            }
331            list[i][j2 - 1] = list[i][j2];
332        }
333
334        data->pairs[i][data->dim.j - 1].id = 0;
335        list[i][data->dim.j - 1] = -1;
336    }
337
338    /* Start again (FIXME: make this a while() loop) */
339    Resolve();
340}
341
342int Fusion::TagNeighbours(int list[MAX_PIECES][MAX_PIECES], int i, int j)
343{
344    int2 const off[] = { int2(-1, 0), int2(1, 0), int2(0, -1), int2(0, 1) };
345
346    int count = 1;
347
348    for (int n = 0; n < 4; n++)
349    {
350        int i2 = i + off[n].i;
351        int j2 = j + off[n].j;
352
353        if (i2 >= 0 && i2 < data->dim.i && j2 >= 0 && j2 < data->dim.j
354             && data->pairs[i2][j2].id == data->pairs[i][j].id
355             && list[i2][j2] == -1)
356        {
357            list[i2][j2] = list[i][j];
358            count += TagNeighbours(list, i2, j2);
359        }
360    }
361    return count;
362}
363
364Fusion::~Fusion()
365{
366    Input::UntrackMouse(this);
367
368    Ticker::Unref(data->thumbs);
369    while (data->mashes)
370    {
371        Ticker::Unref(data->mashes);
372        data->mashes = data->mashes->nextmash;
373    }
374    for (int j = 0; j < data->dim.j; j++)
375        for (int i = 0; i < data->dim.i; i++)
376            if (data->pairs[i][j].id)
377                Ticker::Unref(data->pairs[i][j].piece);
378    Ticker::Unref(data->current[0].piece);
379    Ticker::Unref(data->current[1].piece);
380    Ticker::Unref(data->emitter);
381    Tiler::Deregister(data->board);
382    Tiler::Deregister(data->tiles);
383    delete data;
384}
385
Note: See TracBrowser for help on using the repository browser.