source: trunk/monsterz/board.cpp @ 664

Last change on this file since 664 was 664, checked in by sam, 9 years ago

Get rid of float3, float4, int3 etc. in favour of GLSL types.

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