source: trunk/monsterz/board.cpp @ 260

Last change on this file since 260 was 260, checked in by sam, 11 years ago

Quick initial random board.

  • Property svn:keywords set to Id
File size: 7.5 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
20#include "core.h"
21#include "board.h"
22#include "piece.h"
23#include "monsterz.h"
24
25/*
26 * Board implementation class
27 */
28
29class BoardData
30{
31    friend class Board;
32
33private:
34    Game *game;
35    int screen, board, tiles;
36    int click;
37    Piece *pieces[8][8];
38    Piece *grabbed;
39    Int2 src_cell, dst_cell;
40
41    Int2 mouse;
42    Int3 buttons;
43    float nextblink;
44
45    enum
46    {
47        IDLE,
48        BADCLICK,
49        GRAB,
50    }
51    state;
52};
53
54/*
55 * Public Board class
56 */
57
58Board::Board(Game *game)
59  : data(new BoardData())
60{
61    data->game = game;
62    Ticker::Ref(game);
63    data->screen = Tiler::Register(PNG_BACKGROUND, 640, 480, 1.0f);
64    data->board = Tiler::Register(PNG_BOARD, 384, 384, 1.0f);
65    data->tiles = Tiler::Register(PNG_TILES, 48, 48, 1.0f);
66    data->click = Sampler::Register(WAV_CLICK);
67
68    srand(rand() ^ time(NULL));
69
70restart:
71    for (int j = 0; j < 8; j++)
72        for (int i = 0; i < 8; i++)
73        {
74            int id = rand() % 7;
75            data->pieces[i][j] = new Piece(game, Int2(i, j), 25 + 5 * id);
76            Ticker::Ref(data->pieces[i][j]);
77        }
78
79    int list[8][8];
80    if (ListMashes(list))
81    {
82        for (int j = 0; j < 8; j++)
83            for (int i = 0; i < 8; i++)
84                Ticker::Unref(data->pieces[i][j]);
85        goto restart;
86    }
87
88    data->nextblink = 0.0f;
89    data->state = BoardData::IDLE;
90}
91
92void Board::TickGame(float deltams)
93{
94    Entity::TickGame(deltams);
95
96    Int2 mouse = Input::GetMousePos();
97    Int3 buttons = Input::GetMouseButtons();
98
99    /* If possible, make a random monster blink */
100    if ((data->nextblink -= deltams) < 0.0f)
101    {
102        data->pieces[rand() % 8][rand() % 8]->Blink();
103        data->nextblink = (float)(200 + rand() % 500);
104    }
105
106    /* Should we start dragging something? */
107    switch (data->state)
108    {
109    case BoardData::IDLE:
110        if (buttons[0] && !data->buttons[0])
111        {
112            int x = mouse.x - 24;
113            int y = mouse.y - 72;
114            if (x >= 0 && x < 8 * 48 && y >= 0 && y < 8 * 48)
115            {
116                if (data->pieces[x / 48][y / 48]->Grab(Int2(0, 0)))
117                {
118                    Sampler::PlaySample(data->click);
119                    data->grabbed = data->pieces[x / 48][y / 48];
120                    data->src_cell = Int2(x / 48, y / 48);
121                    data->dst_cell = Int2(-1);
122                    data->state = BoardData::GRAB;
123                }
124                else
125                    data->state = BoardData::BADCLICK;
126            }
127            else
128                data->state = BoardData::BADCLICK;
129        }
130        break;
131    case BoardData::GRAB:
132        if (mouse.x >= 0 && mouse.y >= 0)
133        {
134            data->grabbed->Grab(mouse - data->mouse);
135            Int2 cur_pos = data->grabbed->GetPos();
136            Int2 cur_cell = (cur_pos + 24) / 48;
137            if (cur_cell.i < 0 || cur_cell.i >= 8
138                 || cur_cell.j < 0 || cur_cell.j >= 8
139                 || (cur_pos - cur_cell * 48).sqlen() > 24 * 24
140                 || (cur_cell - data->src_cell).sqlen() != 1)
141                cur_cell = Int2(-1);
142            /* If potential target changed, update our cache. */
143            if (cur_cell != data->dst_cell)
144            {
145                if (data->dst_cell != Int2(-1))
146                    data->pieces[data->dst_cell.i]
147                                [data->dst_cell.j]->Goto(data->dst_cell * 48);
148                if (cur_cell != Int2(-1))
149                    data->pieces[cur_cell.i]
150                                [cur_cell.j]->Goto(data->src_cell * 48);
151                data->dst_cell = cur_cell;
152            }
153        }
154        if (!buttons[0] || mouse.x < 0 || mouse.y < 0
155             || (data->src_cell * 48
156                  - data->grabbed->GetPos()).sqlen() > 100 * 100)
157        {
158            data->grabbed->Ungrab();
159            if (data->dst_cell != Int2(-1))
160                Switch(data->src_cell, data->dst_cell);
161            data->state = BoardData::IDLE;
162        }
163        break;
164    case BoardData::BADCLICK:
165        if (!buttons[0])
166            data->state = BoardData::IDLE;
167        break;
168    }
169
170    data->mouse = mouse;
171    data->buttons = buttons;
172}
173
174void Board::TickDraw(float deltams)
175{
176    Entity::TickDraw(deltams);
177
178    data->game->GetScene()->AddTile((data->screen << 16) | 0, 0, 1050, 0, 0);
179    data->game->GetScene()->AddTile((data->board << 16) | 0, 24, 912, 1, 0);
180
181    if (data->mouse.x >= 0 && data->mouse.y >= 0)
182    {
183        int x = data->mouse.x - 2;
184        int y = data->mouse.y + 59;
185        data->game->GetScene()->AddTile((data->tiles << 16) | 7, x, y, 10, 0);
186    }
187}
188
189void Board::Switch(Int2 cell_a, Int2 cell_b)
190{
191    Piece *a = data->pieces[cell_a.i][cell_a.j];
192    Piece *b = data->pieces[cell_b.i][cell_b.j];
193    data->pieces[cell_a.i][cell_a.j] = b;
194    data->pieces[cell_b.i][cell_b.j] = a;
195
196    /* Check whether this is a valid move by testing all patterns.
197     * If the move is invalid, cancel the swap and bail out */
198    int list[8][8];
199
200    if (!ListMashes(list))
201    {
202        data->pieces[cell_a.i][cell_a.j] = a;
203        data->pieces[cell_b.i][cell_b.j] = b;
204        a->Goto(cell_a * 48);
205        b->Goto(cell_b * 48);
206        return;
207    }
208
209    /* Perform the swap */
210    a->SetCell(cell_b);
211    a->Goto(cell_b * 48);
212    b->SetCell(cell_a);
213    b->Goto(cell_a * 48);
214
215    /* Remove matching tiles */
216    do for (int j = 8; j--;) for (int i = 0; i < 8; i++)
217    {
218        if (list[i][j])
219        {
220            Ticker::Unref(data->pieces[i][j]);
221            for (int j2 = j + 1; j2 < 8; j2++)
222            {
223                data->pieces[i][j2 - 1] = data->pieces[i][j2];
224                data->pieces[i][j2 - 1]->SetCell(Int2(i, j2 - 1));
225                data->pieces[i][j2 - 1]->Goto(Int2(i, j2 - 1) * 48);
226                list[i][j2 - 1] = list[i][j2];
227            }
228            data->pieces[i][7] = new Piece(data->game, Int2(i, 7), 25 + 5 * (rand() % 7));
229            Ticker::Ref(data->pieces[i][7]);
230            list[i][7] = 0;
231        }
232    }
233    while(ListMashes(list));
234}
235
236int Board::ListMashes(int list[8][8])
237{
238    int ret = 0;
239
240    for (int j = 0; j < 8; j++)
241        for (int i = 0; i < 8; i++)
242            list[i][j] = 0;
243
244    for (int j = 0; j < 8; j++)
245        for (int i = 0; i < 8; i++)
246        {
247            int id = data->pieces[i][j]->GetId();
248
249            if (i + 2 < 8 && data->pieces[i + 1][j]->GetId() == id
250                          && data->pieces[i + 2][j]->GetId() == id)
251            {
252                list[i][j] = list[i + 1][j] = list[i + 2][j] = 1;
253                ret = 1;
254            }
255
256            if (j + 2 < 8 && data->pieces[i][j + 1]->GetId() == id
257                          && data->pieces[i][j + 2]->GetId() == id)
258            {
259                list[i][j] = list[i][j + 1] = list[i][j + 2] = 1;
260                ret = 1;
261            }
262        }
263
264    return ret;
265}
266
267Board::~Board()
268{
269    Ticker::Unref(data->game);
270    for (int j = 0; j < 8; j++)
271        for (int i = 0; i < 8; i++)
272            Ticker::Unref(data->pieces[i][j]);
273    Tiler::Deregister(data->board);
274    Tiler::Deregister(data->screen);
275    Tiler::Deregister(data->tiles);
276    Sampler::Deregister(data->click);
277    delete data;
278}
279
Note: See TracBrowser for help on using the repository browser.