source: trunk/monsterz/piece.cpp @ 297

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

Use monster eyes as particles for the exploding effect.

File size: 7.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    Emitter *emitter;
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(Emitter *emitter, int2 cell, int id)
56  : data(new PieceData())
57{
58    data->emitter = emitter;
59    Ticker::Ref(emitter);
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 = DELAY_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 = DELAY_DUH + DELAY_POP;
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        {
279            float3 pos(data->pos.x + 24, data->pos.y + 177, 5);
280            int start = data->id + 10;
281            int stop = data->id + 13;
282            for (int id = start; id < stop; id++)
283            {
284                float3 vel(RandF(-0.3f, 0.3f), RandF(0.2f, 0.3f), 0.0f);
285                data->emitter->AddParticle(id, pos, vel);
286            }
287
288            data->state = PieceData::DEAD;
289        }
290        break;
291    case PieceData::DEAD:
292        break;
293    }
294    Entity::TickGame(deltams);
295}
296
297void Piece::TickDraw(float deltams)
298{
299    Entity::TickDraw(deltams);
300
301    int id = data->id;
302    int x = data->pos.x + 24;
303    int y = data->pos.y + 177;
304    int z = 2;
305
306    /* Optional modifiers */
307    switch (data->state)
308    {
309    case PieceData::IDLE:
310        break;
311    case PieceData::BLINK:
312        id = data->id + 1;
313        break;
314    case PieceData::GRAB:
315        id = data->id + 1;
316        z = 4;
317        break;
318    case PieceData::UNGRAB:
319        if ((data->cell * 48 - data->src).sqlen() > 24 * 24)
320            id = data->id + 5;
321        z = 4;
322        break;
323    case PieceData::MOVE:
324        z = 3;
325        break;
326    case PieceData::POP:
327    {
328        int off = 4 - (data->timer * 5 / DELAY_POP);
329        if (off < 0) off = 0;
330        if (off > 4) off = 4;
331        id = data->id + 5 + off;
332        break;
333    }
334    case PieceData::DEAD:
335        break;
336    }
337
338    if (data->state != PieceData::DEAD)
339        Scene::GetDefault()->AddTile((data->tiler << 16) | id, x, y, z, 0);
340
341    if (data->state == PieceData::GRAB)
342        Scene::GetDefault()->AddTile((data->tiler << 16) | 0, x, y, 5, 0);
343}
344
345Piece::~Piece()
346{
347    if (data->above)
348        Ticker::Unref(data->above);
349    if (data->below)
350        Ticker::Unref(data->below);
351    Ticker::Unref(data->emitter);
352    Tiler::Deregister(data->tiler);
353    delete data;
354}
355
Note: See TracBrowser for help on using the repository browser.