source: trunk/monsterz/piece.cpp @ 284

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

New exploding sprites by Luc. Added to the data but not yet to the code.

File size: 6.6 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
18#include "core.h"
19#include "piece.h"
20#include "monsterz.h"
21
22/*
23 * Piece implementation class
24 */
25
26class PieceData
27{
28    friend class Piece;
29
30private:
31    Game *game;
32    Piece *above, *below;
33    int tiler;
34    Int2 cell, pos, src, dst;
35    int id;
36    float speed, timer;
37
38    enum
39    {
40        IDLE,
41        BLINK,
42        GRAB,
43        UNGRAB,
44        MOVE,
45        POP,
46        DEAD,
47    }
48    state;
49};
50
51/*
52 * Public Piece class
53 */
54
55Piece::Piece(Game *game, Int2 cell, int id)
56  : data(new PieceData())
57{
58    data->game = game;
59    Ticker::Ref(game);
60    data->above = NULL;
61    data->below = NULL;
62    data->tiler = Tiler::Register(PNG_TILES, 48, 48, 1.0f);
63    data->cell = cell;
64    data->pos = cell * 48;
65    data->id = id;
66    data->state = PieceData::IDLE;
67}
68
69void Piece::SetCell(Int2 cell)
70{
71    data->cell = cell;
72}
73
74Int2 Piece::GetCell() const
75{
76    return data->cell;
77}
78
79void Piece::SetPos(Int2 pos)
80{
81    data->pos = pos;
82}
83
84Int2 Piece::GetPos() const
85{
86    return data->pos;
87}
88
89int Piece::GetId() const
90{
91    return data->id;
92}
93
94void Piece::SetAbove(Piece *above)
95{
96    Piece *old = data->above;
97
98    if (above == old)
99        return;
100
101    if (old)
102        Ticker::Unref(old);
103    data->above = above;
104    if (above)
105        Ticker::Ref(above);
106
107    if (old)
108        old->SetBelow(NULL);
109    if (above)
110        above->SetBelow(this);
111}
112
113Piece *Piece::GetAbove() const
114{
115    return data->above;
116}
117
118void Piece::SetBelow(Piece *below)
119{
120    Piece *old = data->below;
121
122    if (below == old)
123        return;
124
125    if (old)
126        Ticker::Unref(old);
127    data->below = below;
128    if (below)
129        Ticker::Ref(below);
130
131    if (old)
132        old->SetAbove(NULL);
133    if (below)
134        below->SetAbove(this);
135}
136
137Piece *Piece::GetBelow() const
138{
139    return data->below;
140}
141
142int Piece::IsDead() const
143{
144    return data->state == PieceData::DEAD;
145}
146
147int Piece::Blink()
148{
149    switch (data->state)
150    {
151    case PieceData::IDLE:
152        data->state = PieceData::BLINK;
153        data->timer = 400.0f; /* Duration of a blink */
154        return 1;
155    default:
156        return 0;
157    }
158}
159
160int Piece::Pop()
161{
162    switch (data->state)
163    {
164    case PieceData::IDLE:
165    case PieceData::BLINK:
166    case PieceData::GRAB:
167    case PieceData::UNGRAB:
168    case PieceData::MOVE:
169    case PieceData::POP:
170        data->state = PieceData::POP;
171        data->timer = 400.0f;
172        return 1;
173    default:
174        return 0;
175    }
176}
177
178int Piece::Grab(Int2 dir)
179{
180    switch (data->state)
181    {
182    case PieceData::UNGRAB:
183    case PieceData::MOVE:
184        /* Only allow swaps when piece is close enough to its target cell. */
185        if ((data->cell * 48 - data->pos).sqlen() > 24 * 24)
186            return 0;
187        /* Fall through */
188    case PieceData::IDLE:
189    case PieceData::BLINK:
190    case PieceData::GRAB:
191        data->state = PieceData::GRAB;
192        data->pos = data->pos + dir;
193        return 1;
194    default:
195        return 0;
196    }
197}
198
199int Piece::Ungrab(Int2 pos)
200{
201    switch (data->state)
202    {
203    case PieceData::IDLE:
204    case PieceData::BLINK:
205    case PieceData::GRAB:
206    case PieceData::UNGRAB:
207    case PieceData::MOVE:
208        data->state = PieceData::UNGRAB;
209        data->speed = 0.4f;
210        data->timer = 0.0f;
211        data->src = data->pos;
212        data->dst = pos;
213        return 1;
214    default:
215        return 0;
216    }
217}
218
219int Piece::Move(Int2 pos)
220{
221    switch (data->state)
222    {
223    case PieceData::IDLE:
224    case PieceData::BLINK:
225    case PieceData::UNGRAB:
226    case PieceData::MOVE:
227        data->state = PieceData::MOVE;
228        data->speed = 0.3f;
229        data->timer = 0.0f;
230        data->src = data->pos;
231        data->dst = pos;
232        return 1;
233    case PieceData::GRAB:
234    default:
235        return 0;
236    }
237}
238
239void Piece::TickGame(float deltams)
240{
241    switch (data->state)
242    {
243    case PieceData::IDLE:
244        break;
245    case PieceData::BLINK:
246        data->timer -= deltams;
247        if (data->timer < 0.0f)
248            data->state = PieceData::IDLE;
249        break;
250    case PieceData::GRAB:
251        break;
252    case PieceData::UNGRAB:
253    case PieceData::MOVE:
254    {
255        data->timer += deltams;
256        Int2 trip = data->dst - data->src;
257        float moving_time = trip.len() / data->speed;
258        float t = moving_time ? data->timer / moving_time : 1.0f;
259        if (t >= 1.0f)
260            t = 1.0f;
261        data->pos = data->src + (t * trip + 0.5f);
262        /* If the piece below is blocking us, clamp our position and
263         * start falling again. */
264        if (data->state == PieceData::MOVE && data->below
265             && data->pos.y < data->below->data->pos.y + 48)
266        {
267            data->pos.y = data->below->data->pos.y + 48;
268            data->src = data->pos;
269            data->timer = 0.0f;
270        }
271        if (data->timer > moving_time + 200.0f)
272            data->state = PieceData::IDLE;
273        break;
274    }
275    case PieceData::POP:
276        data->timer -= deltams;
277        if (data->timer < 0.0f)
278            data->state = PieceData::DEAD;
279        break;
280    case PieceData::DEAD:
281        break;
282    }
283    Entity::TickGame(deltams);
284}
285
286void Piece::TickDraw(float deltams)
287{
288    Entity::TickDraw(deltams);
289
290    int id = data->id;
291    int x = data->pos.x + 24;
292    int y = data->pos.y + 177;
293    int z = 2;
294
295    /* Optional modifiers */
296    switch (data->state)
297    {
298    case PieceData::IDLE:
299        break;
300    case PieceData::BLINK:
301        id = data->id + 1;
302        break;
303    case PieceData::GRAB:
304        id = data->id + 1;
305        z = 4;
306        break;
307    case PieceData::UNGRAB:
308        if ((data->cell * 48 - data->src).sqlen() > 24 * 24)
309            id = data->id + 5;
310        z = 4;
311        break;
312    case PieceData::MOVE:
313        z = 3;
314        break;
315    case PieceData::POP:
316        id = data->id + 7;
317        break;
318    case PieceData::DEAD:
319        break;
320    }
321
322    if (data->state != PieceData::DEAD)
323        data->game->GetScene()->AddTile((data->tiler << 16) | id, x, y, z, 0);
324
325    if (data->state == PieceData::GRAB)
326        data->game->GetScene()->AddTile((data->tiler << 16) | 0, x, y, 5, 0);
327}
328
329Piece::~Piece()
330{
331    if (data->above)
332        Ticker::Unref(data->above);
333    if (data->below)
334        Ticker::Unref(data->below);
335    Ticker::Unref(data->game);
336    Tiler::Deregister(data->tiler);
337    delete data;
338}
339
Note: See TracBrowser for help on using the repository browser.