source: trunk/monsterz/board.cpp @ 352

Last change on this file since 352 was 352, checked in by sam, 12 years ago

Merge the Fusion class back into Board.

  • Property svn:keywords set to Id
File size: 24.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 <ctime>
19#include <cstring>
20
21#include "core.h"
22#include "board.h"
23#include "piece.h"
24#include "thumbs.h"
25#include "mash.h"
26#include "monsterz.h"
27
28/*
29 * Board implementation class
30 */
31
32class BoardData
33{
34    friend class Board;
35
36private:
37    Board::game_t game;
38
39    int2 dim;
40    int minnpieces, npieces, maxnpieces;
41
42    int board, tiles, icons;
43    int click, whip;
44
45    struct Pair
46    {
47        int id;
48        Piece *piece;
49    }
50    pairs[MAX_WIDTH][MAX_HEIGHT];
51
52    /* Hunt */
53    struct Pair grabbed;
54    int nmoves;
55    int2 src_cell, dst_cell;
56
57    /* Fusion */
58    struct Pair current[2];
59    int next[2], rotation;
60
61    Text *scoretext;
62    int score;
63
64    Mash *mashes;
65    Emitter *emitter;
66    Thumbs *thumbs;
67
68    int2 oldmouse;
69    int3 oldbuttons;
70    float nextblink, whipdelay;
71
72    enum
73    {
74        HUNT_IDLE,
75        HUNT_BADCLICK,
76        HUNT_GRAB,
77        FUSION_IDLE,
78    }
79    state;
80};
81
82/*
83 * Public Board class
84 */
85
86Board::Board(game_t game, int2 dim, int minnpieces, int maxnpieces)
87  : data(new BoardData())
88{
89    data->game = game;
90
91    data->dim = dim;
92    data->minnpieces = minnpieces;
93    data->npieces = minnpieces;
94    data->maxnpieces = maxnpieces;
95    data->board = Tiler::Register(PNG_BOARD, 384, 384, 1.0f);
96    data->tiles = Tiler::Register(PNG_TILES, 48, 48, 1.0f);
97    data->icons = Tiler::Register(PNG_ICONS, 24, 24, 1.0f);
98    data->click = Sampler::Register(WAV_CLICK);
99    data->whip = Sampler::Register(WAV_WHIP);
100
101    data->emitter = new Emitter(data->tiles, float3(0, -0.0006f, 0));
102    Ticker::Ref(data->emitter);
103
104    data->thumbs = new Thumbs(0);
105    Ticker::Ref(data->thumbs);
106
107    switch (data->game)
108    {
109    case GAME_HUNT:
110        Fill();
111        data->thumbs->SetMax(data->npieces);
112        data->state = BoardData::HUNT_IDLE;
113        break;
114
115    case GAME_FUSION:
116        for (int j = 0; j < data->dim.j; j++)
117            for (int i = 0; i < data->dim.i; i++)
118                data->pairs[i][j].id = 0;
119
120        data->current[0].id = GetRandomId();
121        data->current[1].id = GetRandomId();
122        data->current[0].piece = new Piece(data->emitter, int2(3, 8),
123                                           80 + 20 * data->current[0].id);
124        data->current[1].piece = new Piece(data->emitter, int2(4, 8),
125                                           80 + 20 * data->current[1].id);
126        Ticker::Ref(data->current[0].piece);
127        Ticker::Ref(data->current[1].piece);
128        data->current[0].piece->SetPos(int2(3, 7) * 48);
129        data->current[1].piece->SetPos(int2(4, 7) * 48);
130
131        data->next[0] = GetRandomId();
132        data->next[1] = GetRandomId();
133        data->rotation = 0;
134
135        data->thumbs->SetMax(data->npieces + 1);
136        data->state = BoardData::FUSION_IDLE;
137        break;
138    }
139
140    data->mashes = NULL;
141    data->nextblink = 0.0f;
142    data->whipdelay = 0.0f;
143
144    data->scoretext = new Text(NULL, "monsterz/gfx/font2.png");
145    data->scoretext->SetAlign(Text::ALIGN_RIGHT);
146    data->scoretext->SetPos(int3(624, 432, 1));
147    Ticker::Ref(data->scoretext);
148    data->score = 0;
149
150    position = int3(24, 72, 1);
151    bbox[0] = position;
152    bbox[1] = bbox[0] + int3(384, 384, 0);
153
154    Input::TrackMouse(this);
155}
156
157void Board::TickGame(float deltams)
158{
159    Entity::TickGame(deltams);
160
161    int3 buttons = Input::GetMouseButtons();
162
163    /* If possible, make a random monster blink */
164    if (data->game == Board::GAME_HUNT && (data->nextblink -= deltams) < 0.0f)
165    {
166        data->pairs[rand() % data->dim.i]
167                   [rand() % data->dim.j].piece->Blink();
168        data->nextblink = (float)(200 + rand() % 500);
169    }
170
171    /* Do not whip too often, the sound may become annoying */
172    data->whipdelay -= deltams;
173
174    /* Get rid of finished mashes */
175    for (Mash **it = &data->mashes; *it; )
176    {
177        if ((*it)->IsDead())
178        {
179            Ticker::Unref(*it);
180            *it = (*it)->nextmash;
181        }
182        else
183            it = &(*it)->nextmash;
184    }
185
186    /* Update score */
187    data->scoretext->SetInt(data->score);
188
189    switch (data->state)
190    {
191    case BoardData::HUNT_IDLE:
192        /* Should we start dragging something? */
193        if (buttons[0] && !data->oldbuttons[0] && mousepos.x != -1)
194        {
195            int2 cell = mousepos / 48;
196            if (data->pairs[cell.x][cell.y].piece->Grab(int2(0, 0)))
197            {
198                Sampler::PlaySample(data->click);
199                data->grabbed = data->pairs[cell.x][cell.y];
200                data->src_cell = mousepos / 48;
201                data->dst_cell = int2(-1);
202                data->state = BoardData::HUNT_GRAB;
203            }
204            else
205                data->state = BoardData::HUNT_BADCLICK;
206        }
207        break;
208
209    case BoardData::HUNT_GRAB:
210        if (mousepos.x != -1)
211        {
212            /* Mouse is still in the window, keep grabbing */
213            data->grabbed.piece->Grab(mousepos - data->oldmouse);
214            int2 cur_pos = data->grabbed.piece->GetPos();
215            int2 cur_cell = (cur_pos + 24) / 48;
216            if (cur_cell.i < 0 || cur_cell.i >= data->dim.i
217                 || cur_cell.j < 0 || cur_cell.j >= data->dim.j
218                 || (cur_pos - cur_cell * 48).sqlen() > 24 * 24
219                 || (cur_cell - data->src_cell).sqlen() != 1)
220                cur_cell = int2(-1);
221            /* If potential target changed, update our cache. */
222            if (cur_cell != data->dst_cell)
223            {
224                if (data->whipdelay < 0.0f)
225                {
226                    Sampler::PlaySample(data->whip);
227                    data->whipdelay = DELAY_WHIP;
228                }
229                if (data->dst_cell != int2(-1))
230                    data->pairs[data->dst_cell.i]
231                               [data->dst_cell.j].piece->Ungrab(data->dst_cell * 48);
232                if (cur_cell != int2(-1))
233                    data->pairs[cur_cell.i]
234                               [cur_cell.j].piece->Ungrab(data->src_cell * 48);
235                data->dst_cell = cur_cell;
236            }
237        }
238        if (!buttons[0] || mousepos.x == -1
239             || (data->src_cell * 48
240                  - data->grabbed.piece->GetPos()).sqlen() > 100 * 100)
241        {
242            /* Mouse released, or exited window, or dragged too far. */
243            data->grabbed.piece->Ungrab(data->grabbed.piece->GetCell() * 48);
244            if (data->dst_cell != int2(-1))
245                Switch(data->src_cell, data->dst_cell);
246            data->state = BoardData::HUNT_IDLE;
247        }
248        break;
249
250    case BoardData::HUNT_BADCLICK:
251        if (!buttons[0])
252            data->state = BoardData::HUNT_IDLE;
253        break;
254
255    case BoardData::FUSION_IDLE:
256    {
257        int column = -1;
258
259        if (clicked[2])
260        {
261            column = data->current[0].piece->GetCell().x;
262            data->rotation = (data->rotation + 1) % 2;
263            if (column - data->rotation > data->dim.i - 1)
264                column = data->dim.i - 1 - data->rotation;
265            if (!data->rotation)
266            {
267                BoardData::Pair tmp = data->current[0];
268                data->current[0] = data->current[1];
269                data->current[1] = tmp;
270                if (column == data->dim.i - 1)
271                    column = 6;
272            }
273        }
274
275        if (mousepos.x != -1
276            && mousepos.x / 48 != data->current[0].piece->GetCell().x)
277        {
278            column = mousepos.x / 48;
279            column = column < 0 ? 0 : column > data->dim.i - 2 + data->rotation ? data->dim.i - 2 + data->rotation : column;
280        }
281
282        if (column != -1)
283        {
284            if (data->rotation)
285            {
286                data->current[0].piece->SetCell(int2(column, 6));
287                data->current[1].piece->SetCell(int2(column, 7));
288            }
289            else
290            {
291                data->current[0].piece->SetCell(int2(column, 7));
292                data->current[1].piece->SetCell(int2(column + 1, 7));
293            }
294
295            data->current[0].piece->Move(data->current[0].piece->GetCell() * 48);
296            data->current[1].piece->Move(data->current[1].piece->GetCell() * 48);
297        }
298
299        if (clicked[0])
300        {
301            for (int t = 0; t < 2; t++)
302            {
303                int i = data->current[t].piece->GetCell().i;
304                for (int j = 0; j < 7; j++)
305                    if (data->pairs[i][j].id == 0)
306                    {
307                        data->current[t].piece->SetCell(int2(i, j));
308                        data->current[t].piece->Move(int2(i, j) * 48);
309                        data->pairs[i][j] = data->current[t];
310                        data->thumbs->AddCount(data->current[t].id, 1);
311                        break;
312                    }
313            }
314
315            data->current[0].id = data->next[0];
316            data->current[1].id = data->next[1];
317            data->current[0].piece = new Piece(data->emitter, int2(3, 7),
318                                               80 + 20 * data->current[0].id);
319            data->current[1].piece = new Piece(data->emitter, int2(4, 7),
320                                               80 + 20 * data->current[1].id);
321            Ticker::Ref(data->current[0].piece);
322            Ticker::Ref(data->current[1].piece);
323            data->current[0].piece->SetPos(int2(3, 8) * 48);
324            data->current[1].piece->SetPos(int2(4, 8) * 48);
325            data->current[0].piece->Move(data->current[0].piece->GetCell() * 48);
326            data->current[1].piece->Move(data->current[1].piece->GetCell() * 48);
327            data->next[0] = GetRandomId();
328            data->next[1] = GetRandomId();
329            data->rotation = 0;
330
331            Resolve();
332        }
333        break;
334    }
335    }
336
337    data->oldmouse = mousepos;
338    data->oldbuttons = buttons;
339}
340
341void Board::TickDraw(float deltams)
342{
343    Entity::TickDraw(deltams);
344
345    Scene::GetDefault()->AddTile((data->board << 16) | 0,
346                                 position.x, position.y, 1, 0);
347
348    switch (data->game)
349    {
350    case GAME_HUNT:
351        break;
352    case GAME_FUSION:
353        Scene::GetDefault()->AddTile((data->icons << 16) | (data->next[0] - 1),
354                                     350, 400, 11, 0);
355        Scene::GetDefault()->AddTile((data->icons << 16) | (data->next[1] - 1),
356                                     380, 400, 11, 0);
357        break;
358    }
359}
360
361/* Fill the board with an initial position. We ensure no pieces are
362 * aligned and at least one move is possible. */
363void Board::Fill()
364{
365    srand(rand() ^ time(NULL));
366
367    int list[MAX_WIDTH][MAX_HEIGHT];
368    do
369    {
370        for (int j = 0; j < data->dim.j; j++)
371            for (int i = 0; i < data->dim.i; i++)
372                data->pairs[i][j].id = 1 + rand() % data->npieces;
373    } while (ListMashes(list) || !(data->nmoves = ListMoves(list)));
374
375    /* Spawn pieces */
376    for (int j = 0; j < data->dim.j; j++)
377        for (int i = 0; i < data->dim.i; i++)
378        {
379            int2 newpos = int2(i, j + data->dim.j) * 48;
380            int id = 80 + 20 * data->pairs[i][j].id;
381            data->pairs[i][j].piece = new Piece(data->emitter, int2(i, j), id);
382            data->pairs[i][j].piece->SetPos(newpos);
383            data->pairs[i][j].piece->Move(int2(i, j) * 48);
384            if (j)
385                data->pairs[i][j].piece->SetBelow(data->pairs[i][j - 1].piece);
386            Ticker::Ref(data->pairs[i][j].piece);
387        }
388}
389
390void Board::Switch(int2 cell_a, int2 cell_b)
391{
392    BoardData::Pair a = data->pairs[cell_a.i][cell_a.j];
393    BoardData::Pair b = data->pairs[cell_b.i][cell_b.j];
394    data->pairs[cell_a.i][cell_a.j] = b;
395    data->pairs[cell_b.i][cell_b.j] = a;
396
397    /* Check whether this is a valid move by testing all patterns.
398     * If the move is invalid, cancel the swap and bail out */
399    int list[MAX_WIDTH][MAX_HEIGHT];
400
401    if (!ListMashes(list))
402    {
403        data->pairs[cell_a.i][cell_a.j] = a;
404        data->pairs[cell_b.i][cell_b.j] = b;
405        a.piece->Ungrab(cell_a * 48);
406        b.piece->Ungrab(cell_b * 48);
407        return;
408    }
409
410    /* Perform the swap */
411    a.piece->SetCell(cell_b);
412    a.piece->Ungrab(cell_b * 48);
413    b.piece->SetCell(cell_a);
414    b.piece->Ungrab(cell_a * 48);
415
416    /* Swap above and below cells */
417    if (cell_a.i == cell_b.i)
418    {
419        Piece *tmpa = a.piece->GetAbove();
420        Piece *tmpb = b.piece->GetAbove();
421        if (tmpb == a.piece)
422        {
423            tmpb = b.piece->GetBelow();
424            b.piece->SetAbove(tmpa);
425            b.piece->SetBelow(a.piece);
426            a.piece->SetBelow(tmpb);
427        }
428        else /* tmpa == b.piece */
429        {
430            tmpa = a.piece->GetBelow();
431            a.piece->SetAbove(tmpb);
432            a.piece->SetBelow(b.piece);
433            b.piece->SetBelow(tmpa);
434        }
435    }
436    else
437    {
438        Piece *tmpa = a.piece->GetAbove();
439        Piece *tmpb = b.piece->GetAbove();
440        a.piece->SetAbove(tmpb);
441        b.piece->SetAbove(tmpa);
442        tmpa = a.piece->GetBelow();
443        tmpb = b.piece->GetBelow();
444        a.piece->SetBelow(tmpb);
445        b.piece->SetBelow(tmpa);
446    }
447
448    /* Remove matching pieces and store them in Mash objects */
449    do
450    {
451        Mash *mash = new Mash(data->emitter);
452        Ticker::Ref(mash);
453
454        for (int j = data->dim.j; j--;) for (int i = 0; i < data->dim.i; i++)
455        {
456            if (!list[i][j])
457                continue;
458
459            /* The mash becomes the new owner of the disappearing piece */
460            mash->AddPiece(data->pairs[i][j].piece);
461            data->thumbs->AddCount(data->pairs[i][j].id, 1);
462
463#if 0 // Test for piece creation
464            if (list[i][j] >= 2)
465            {
466                Piece *old = data->pairs[i][j].piece;
467                int id = 1 + rand() % data->npieces;
468                data->pairs[i][j].id = id;
469                data->pairs[i][j].piece = new Piece(data->emitter, int2(i, j), 80 + 20 * id);
470                data->pairs[i][j].piece->SetBelow(old->GetBelow());
471                data->pairs[i][j].piece->SetAbove(old->GetAbove());
472                Ticker::Ref(data->pieces[i][j].piece);
473                list[i][j] = 0;
474            }
475            else
476#endif
477            {
478                Piece *below = data->pairs[i][data->dim.j - 1].piece;
479
480                /* Change coordinates for the whole column above */
481                for (int j2 = j + 1; j2 < data->dim.j; j2++)
482                {
483                    data->pairs[i][j2 - 1] = data->pairs[i][j2];
484                    data->pairs[i][j2 - 1].piece->SetCell(int2(i, j2 - 1));
485                    data->pairs[i][j2 - 1].piece->Move(int2(i, j2 - 1) * 48);
486                    list[i][j2 - 1] = list[i][j2];
487                }
488
489                /* Spawn a new piece above all the others and attach it to
490                 * the board. */
491                int2 newpos = int2(i * 48, below->GetPos().y + 48);
492                int2 newcell = int2(i, data->dim.j - 1);
493                int id = 1 + rand() % data->npieces;
494                Piece *tmp = new Piece(data->emitter, newcell, 80 + 20 * id);
495                tmp->SetBelow(below);
496                tmp->SetPos(newpos);
497                tmp->Move(newcell * 48);
498                Ticker::Ref(tmp);
499                data->pairs[i][data->dim.j - 1].id = id;
500                data->pairs[i][data->dim.j - 1].piece = tmp;
501                list[i][data->dim.j - 1] = 0;
502            }
503        }
504
505        mash->nextmash = data->mashes;
506        data->mashes = mash;
507    }
508    while(ListMashes(list));
509
510    data->nmoves = ListMoves(list);
511
512    if (data->nmoves == 0)
513    {
514        Mash *mash = new Mash(data->emitter);
515        Ticker::Ref(mash);
516
517        for (int j = data->dim.j; j--;) for (int i = 0; i < data->dim.i; i++)
518            mash->AddPiece(data->pairs[i][j].piece);
519
520        mash->nextmash = data->mashes;
521        data->mashes = mash;
522
523        Piece *below[MAX_WIDTH];
524        for (int i = 0; i < data->dim.i; i++)
525            below[i] = data->pairs[i][data->dim.j - 1].piece;
526
527        Fill();
528
529        for (int i = 0; i < data->dim.i; i++)
530            data->pairs[i][0].piece->SetBelow(below[i]);
531    }
532}
533
534/* Fill an array with the list of pieces that should disappear due to
535 * 3-piece or more alignments. */
536int Board::ListMashes(int list[MAX_WIDTH][MAX_HEIGHT])
537{
538    int ret = 0;
539
540    for (int j = 0; j < data->dim.j; j++)
541        for (int i = 0; i < data->dim.i; i++)
542            list[i][j] = 0;
543
544    for (int j = 0; j < data->dim.j; j++)
545        for (int i = 0; i < data->dim.i; i++)
546        {
547            int id = data->pairs[i][j].id;
548
549            if (i + 2 < data->dim.i && data->pairs[i + 1][j].id == id
550                          && data->pairs[i + 2][j].id == id)
551            {
552                list[i][j]++;
553                list[i + 1][j] += 2;
554                list[i + 2][j]++;
555                ret = 1;
556            }
557
558            if (j + 2 < data->dim.j && data->pairs[i][j + 1].id == id
559                          && data->pairs[i][j + 2].id == id)
560            {
561                list[i][j]++;
562                list[i][j + 1] += 2;
563                list[i][j + 2]++;
564                ret = 1;
565            }
566        }
567
568    return ret;
569}
570
571/* Fill an array with the list of pieces that can be moved. A value of 1
572 * indicates the piece can be moved right. A value of 2 means it can be
573 * moved up, and a value of 3 means both moves are possible. The number
574 * of possible moves is returned. */
575int Board::ListMoves(int moves[MAX_WIDTH][MAX_HEIGHT])
576{
577    int ret = 0;
578
579    for (int j = 0; j < data->dim.j; j++)
580        for (int i = 0; i < data->dim.i; i++)
581            moves[i][j] = 0;
582
583    for (int j = 0; j < data->dim.j; j++)
584        for (int i = 0; i < data->dim.i; i++)
585        {
586            /* Copy neighbourhood to a local buffer */
587            int tmp[6][6];
588
589            for (int dj = -2; dj <= 3; dj++)
590                for (int di = -2; di <= 3; di++)
591                    if (j + dj >= 0 && j + dj < data->dim.j
592                         && i + di >= 0 && i + di < data->dim.i)
593                        tmp[2 + di][2 + dj] = data->pairs[i + di][j + dj].id;
594                    else
595                        tmp[2 + di][2 + dj] = 0;
596
597            /* +--+--+--+--+--+--+
598             * |  |  |25|  |  |  |
599             * +--+--+--+--+--+--+
600             * |  |  |24|34|  |  |
601             * +--+--+--+--+--+--+
602             * |03|13|c |33|43|  |
603             * +--+--+--+--+--+--+
604             * |02|12|a |b |42|52|
605             * +--+--+--+--+--+--+
606             * |  |11|21|31|  |  |
607             * +--+--+--+--+--+--+
608             * |  |  |20|30|  |  |
609             * +--+--+--+--+--+--+ */
610            int a = tmp[2][2];
611            int b = tmp[3][2] ? tmp[3][2] : -1;
612            int c = tmp[2][3] ? tmp[2][3] : -1;
613
614            /* Try moving right */
615            if ((a == tmp[3][0] && a == tmp[3][1]) ||
616                (a == tmp[3][1] && a == tmp[3][3]) ||
617                (a == tmp[3][3] && a == tmp[3][4]) ||
618                (a == tmp[4][2] && a == tmp[5][2]) ||
619                (b == tmp[2][0] && b == tmp[2][1]) ||
620                (b == tmp[2][1] && b == tmp[2][3]) ||
621                (b == tmp[2][3] && b == tmp[2][4]) ||
622                (b == tmp[0][2] && b == tmp[1][2]))
623            {
624                moves[i][j] |= 1;
625                ret++;
626            }
627
628            /* Try moving up */
629            if ((a == tmp[0][3] && a == tmp[1][3]) ||
630                (a == tmp[1][3] && a == tmp[3][3]) ||
631                (a == tmp[3][3] && a == tmp[4][3]) ||
632                (a == tmp[2][4] && a == tmp[2][5]) ||
633                (c == tmp[0][2] && c == tmp[1][2]) ||
634                (c == tmp[1][2] && c == tmp[3][2]) ||
635                (c == tmp[3][2] && c == tmp[4][2]) ||
636                (c == tmp[2][0] && c == tmp[2][1]))
637            {
638                moves[i][j] |= 2;
639                ret++;
640            }
641        }
642
643    return ret;
644}
645
646int Board::GetRandomId() const
647{
648    int max = data->npieces;
649
650    if (max > data->minnpieces)
651        max--;
652
653    return 1 + rand() % max;
654}
655
656void Board::Resolve()
657{
658    int list[MAX_PIECES][MAX_PIECES];
659    int count[MAX_PIECES * MAX_PIECES];
660
661    for (int j = 0; j < data->dim.j; j++)
662        for (int i = 0; i < data->dim.i; i++)
663            list[i][j] = -1;
664    memset(count, 0, sizeof(count));
665
666    int seq = 0, effect = 0;
667
668    /* Count connected tiles */
669    for (int j = 0; j < data->dim.j; j++) for (int i = 0; i < data->dim.i; i++)
670    {
671        if (!data->pairs[i][j].id)
672            continue;
673
674        if (data->pairs[i][j].id >= data->maxnpieces)
675            continue;
676
677        if (list[i][j] != -1)
678            continue;
679
680        list[i][j] = seq;
681        count[seq] = TagNeighbours(list, i, j);
682        if (count[seq] >= 3)
683            effect = 1;
684        seq++;
685    }
686
687    /* Only continue if there is an effect */
688    if (!effect)
689        return;
690
691    /* Add tiles to a mash; add mash to our list */
692    Mash *mash = new Mash(data->emitter);
693    Ticker::Ref(mash);
694
695    for (int j = 0; j < data->dim.j; j++) for (int i = 0; i < data->dim.i; i++)
696    {
697        if (list[i][j] == -1)
698            continue;
699        if (count[list[i][j]] < 3)
700            continue;
701
702        mash->AddPiece(data->pairs[i][j].piece);
703        data->pairs[i][j].piece = NULL;
704    }
705
706    mash->nextmash = data->mashes;
707    data->mashes = mash;
708
709    /* Create new pieces where necessary */
710    for (int j = 0; j < data->dim.j; j++) for (int i = 0; i < data->dim.i; i++)
711    {
712        if (list[i][j] == -1)
713            continue;
714        if (count[list[i][j]] < 3)
715        {
716            if (!data->pairs[i][j].piece)
717                data->pairs[i][j].id = 0;
718            continue;
719        }
720
721        data->pairs[i][j].id++;
722        if (data->pairs[i][j].id > data->npieces
723                && data->pairs[i][j].id <= data->maxnpieces)
724        {
725            data->npieces++;
726            data->thumbs->SetMax(data->npieces);
727        }
728        data->pairs[i][j].piece = new Piece(data->emitter, int2(i, j), 80 + 20 * data->pairs[i][j].id);
729        Ticker::Ref(data->pairs[i][j].piece);
730        data->pairs[i][j].piece->SetPos(int2(i, j) * 48);
731        data->thumbs->AddCount(data->pairs[i][j].id, 1);
732        count[list[i][j]] = 0;
733        list[i][j] = -1;
734    }
735
736    /* Move everything down */
737    for (int j = data->dim.j; j--;) for (int i = 0; i < data->dim.i; i++)
738    {
739        if (list[i][j] == -1 || data->pairs[i][j].piece)
740            continue;
741
742        for (int j2 = j + 1; j2 < data->dim.j; j2++)
743        {
744            data->pairs[i][j2 - 1] = data->pairs[i][j2];
745            if (data->pairs[i][j2 - 1].id)
746            {
747                data->pairs[i][j2 - 1].piece->SetCell(int2(i, j2 - 1));
748                data->pairs[i][j2 - 1].piece->Move(int2(i, j2 - 1) * 48);
749            }
750            list[i][j2 - 1] = list[i][j2];
751        }
752
753        data->pairs[i][data->dim.j - 1].id = 0;
754        list[i][data->dim.j - 1] = -1;
755    }
756
757    /* Start again (FIXME: make this a while() loop) */
758    Resolve();
759}
760
761int Board::TagNeighbours(int list[MAX_PIECES][MAX_PIECES], int i, int j)
762{
763    int2 const off[] = { int2(-1, 0), int2(1, 0), int2(0, -1), int2(0, 1) };
764
765    int count = 1;
766
767    for (int n = 0; n < 4; n++)
768    {
769        int i2 = i + off[n].i;
770        int j2 = j + off[n].j;
771
772        if (i2 >= 0 && i2 < data->dim.i && j2 >= 0 && j2 < data->dim.j
773             && data->pairs[i2][j2].id == data->pairs[i][j].id
774             && list[i2][j2] == -1)
775        {
776            list[i2][j2] = list[i][j];
777            count += TagNeighbours(list, i2, j2);
778        }
779    }
780    return count;
781}
782
783Board::~Board()
784{
785    Input::UntrackMouse(this);
786
787    switch (data->game)
788    {
789    case GAME_HUNT:
790        for (int j = 0; j < data->dim.j; j++)
791            for (int i = 0; i < data->dim.i; i++)
792            {
793                data->pairs[i][j].piece->SetBelow(NULL);
794                Ticker::Unref(data->pairs[i][j].piece);
795            }
796        break;
797    case GAME_FUSION:
798        for (int j = 0; j < data->dim.j; j++)
799            for (int i = 0; i < data->dim.i; i++)
800                if (data->pairs[i][j].id)
801                    Ticker::Unref(data->pairs[i][j].piece);
802        Ticker::Unref(data->current[0].piece);
803        Ticker::Unref(data->current[1].piece);
804        break;
805    }
806    Ticker::Unref(data->thumbs);
807    Ticker::Unref(data->scoretext);
808    while (data->mashes)
809    {
810        Ticker::Unref(data->mashes);
811        data->mashes = data->mashes->nextmash;
812    }
813    /* FIXME: the emitter may be destroyed after the Tiler is removed,
814     * because the last Tiler tick may be done just after the emitter
815     * scheduled its sprites! */
816    Ticker::Unref(data->emitter);
817    Tiler::Deregister(data->board);
818    Tiler::Deregister(data->tiles);
819    Tiler::Deregister(data->icons);
820    Sampler::Deregister(data->click);
821    Sampler::Deregister(data->whip);
822    delete data;
823}
824
Note: See TracBrowser for help on using the repository browser.