source: trunk/monsterz/piece.cpp @ 274

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

Implement above/below pieces.

File size: 6.1 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()
200{
201    switch (data->state)
202    {
203    case PieceData::GRAB:
204        data->state = PieceData::UNGRAB;
205        data->speed = 0.3f;
206        data->timer = 0.0f;
207        data->src = data->pos;
208        data->dst = data->cell * 48;
209        return 1;
210    default:
211        return 0;
212    }
213}
214
215int Piece::Goto(Int2 pos, float speed)
216{
217    switch (data->state)
218    {
219    case PieceData::IDLE:
220    case PieceData::BLINK:
221    case PieceData::UNGRAB:
222    case PieceData::MOVE:
223        data->state = PieceData::MOVE;
224        data->timer = 0.0f;
225        data->src = data->pos;
226        data->dst = pos;
227        data->speed = speed;
228        return 1;
229    case PieceData::GRAB:
230    default:
231        return 0;
232    }
233}
234
235void Piece::TickGame(float deltams)
236{
237    switch (data->state)
238    {
239    case PieceData::IDLE:
240        break;
241    case PieceData::BLINK:
242        data->timer -= deltams;
243        if (data->timer < 0.0f)
244            data->state = PieceData::IDLE;
245        break;
246    case PieceData::GRAB:
247        break;
248    case PieceData::UNGRAB:
249    case PieceData::MOVE:
250    {
251        data->timer += deltams;
252        Int2 trip = data->dst - data->src;
253        float moving_time = trip.len() / data->speed;
254        float t = moving_time ? data->timer / moving_time : 1.0f;
255        if (t >= 1.0f)
256            t = 1.0f;
257        if (data->timer > moving_time + 200.0f)
258            data->state = PieceData::IDLE;
259        data->pos = data->src + (t * trip + 0.5f);
260        break;
261    }
262    case PieceData::POP:
263        data->timer -= deltams;
264        if (data->timer < 0.0f)
265            data->state = PieceData::DEAD;
266        break;
267    case PieceData::DEAD:
268        break;
269    }
270    Entity::TickGame(deltams);
271}
272
273void Piece::TickDraw(float deltams)
274{
275    Entity::TickDraw(deltams);
276
277    int id = data->id;
278    int x = data->pos.x + 24;
279    int y = data->pos.y + 177;
280    int z = 2;
281
282    /* Optional modifiers */
283    switch (data->state)
284    {
285    case PieceData::IDLE:
286        break;
287    case PieceData::BLINK:
288        id = data->id + 1;
289        break;
290    case PieceData::GRAB:
291        id = data->id + 1;
292        z = 4;
293        break;
294    case PieceData::UNGRAB:
295        if ((data->cell * 48 - data->src).sqlen() > 24 * 24)
296            id = data->id + 2;
297        z = 4;
298        break;
299    case PieceData::MOVE:
300        z = 3;
301        break;
302    case PieceData::POP:
303        id = data->id + 4;
304        break;
305    case PieceData::DEAD:
306        break;
307    }
308
309    if (data->state != PieceData::DEAD)
310        data->game->GetScene()->AddTile((data->tiler << 16) | id, x, y, z, 0);
311
312    if (data->state == PieceData::GRAB)
313        data->game->GetScene()->AddTile((data->tiler << 16) | 0, x, y, 5, 0);
314}
315
316Piece::~Piece()
317{
318    if (data->above)
319        Ticker::Unref(data->above);
320    if (data->below)
321        Ticker::Unref(data->below);
322    Ticker::Unref(data->game);
323    Tiler::Deregister(data->tiler);
324    delete data;
325}
326
Note: See TracBrowser for help on using the repository browser.