source: trunk/monsterz/board.cpp @ 354

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

Remove Piece::Blink and implement it as a timer inside Piece.

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