source: trunk/monsterz/board.cpp @ 740

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

monsterz: create a Score class to display the score text and increment it
progressively.

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