source: trunk/monsterz/piece.cpp @ 419

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

Name tilers, samples and pieces for easier debugging.

File size: 8.8 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    Piece::piece_t piece;
32
33    int tiler;
34    Emitter *emitter;
35    Piece *above, *below;
36    int2 size, cell, pos, src, dst;
37    int id;
38    float speed, timer, blink, idle;
39
40    enum
41    {
42        IDLE,
43        BLINK,
44        GRAB,
45        UNGRAB,
46        MOVE,
47        POP,
48        DEAD,
49    }
50    state;
51
52    char namebuf[40];
53};
54
55/*
56 * Public Piece class
57 */
58
59Piece::Piece(piece_t piece, Emitter *emitter, int2 cell, int id)
60  : data(new PieceData())
61{
62    data->piece = piece;
63
64    data->emitter = emitter;
65    Ticker::Ref(emitter);
66    data->above = NULL;
67    data->below = NULL;
68    data->cell = cell;
69    data->state = PieceData::IDLE;
70    data->timer = RandF(DELAY_IDLE);
71    data->blink = RandF(DELAY_BLINK);
72    data->idle = RandF(DELAY_IDLE, 2 * DELAY_IDLE);
73
74    switch (data->piece)
75    {
76    case PIECE_HUNT:
77        data->size = 48;
78        data->tiler = Tiler::Register(PNG_TILES,
79                                      data->size.x, data->size.y, 1.0f);
80        data->id = 80 + 20 * id;
81        break;
82    case PIECE_FUSION:
83        data->size = 40;
84        data->tiler = Tiler::Register(PNG_ELEMENTS,
85                                      data->size.x, data->size.y, 1.0f);
86        data->id = id - 1;
87        break;
88    }
89
90    data->pos = data->cell * data->size;
91}
92
93char const *Piece::GetName()
94{
95    sprintf(data->namebuf, "<piece> %ix%i @ %i,%i",
96            data->size.x, data->size.y, data->cell.x, data->cell.y);
97    return data->namebuf;
98}
99
100void Piece::SetCell(int2 cell)
101{
102    data->cell = cell;
103}
104
105int2 Piece::GetCell() const
106{
107    return data->cell;
108}
109
110void Piece::SetPos(int2 pos)
111{
112    data->pos = pos;
113}
114
115int2 Piece::GetPos() const
116{
117    return data->pos;
118}
119
120int2 Piece::GetSize() const
121{
122    return data->size;
123}
124
125int2 Piece::GetShift() const
126{
127    return data->pos - data->cell * data->size;
128}
129
130void Piece::SetAbove(Piece *above)
131{
132    Piece *old = data->above;
133
134    if (above == old)
135        return;
136
137    if (old)
138        Ticker::Unref(old);
139    data->above = above;
140    if (above)
141        Ticker::Ref(above);
142
143    if (old)
144        old->SetBelow(NULL);
145    if (above)
146        above->SetBelow(this);
147}
148
149Piece *Piece::GetAbove() const
150{
151    return data->above;
152}
153
154void Piece::SetBelow(Piece *below)
155{
156    Piece *old = data->below;
157
158    if (below == old)
159        return;
160
161    if (old)
162        Ticker::Unref(old);
163    data->below = below;
164    if (below)
165        Ticker::Ref(below);
166
167    if (old)
168        old->SetAbove(NULL);
169    if (below)
170        below->SetAbove(this);
171}
172
173Piece *Piece::GetBelow() const
174{
175    return data->below;
176}
177
178int Piece::IsDead() const
179{
180    return data->state == PieceData::DEAD;
181}
182
183int Piece::Pop()
184{
185    switch (data->state)
186    {
187    case PieceData::IDLE:
188    case PieceData::BLINK:
189    case PieceData::GRAB:
190    case PieceData::UNGRAB:
191    case PieceData::MOVE:
192    case PieceData::POP:
193        data->state = PieceData::POP;
194        data->timer = DELAY_DUH + DELAY_POP;
195        return 1;
196    default:
197        return 0;
198    }
199}
200
201int Piece::Grab(int2 dir)
202{
203    switch (data->state)
204    {
205    case PieceData::UNGRAB:
206    case PieceData::MOVE:
207        /* Only allow swaps when piece is close enough to its target cell. */
208        if ((data->cell * data->size - data->pos).sqlen()
209              > data->size.sqlen() / 8)
210            return 0;
211        /* Fall through */
212    case PieceData::IDLE:
213    case PieceData::BLINK:
214    case PieceData::GRAB:
215        data->state = PieceData::GRAB;
216        data->pos = data->pos + dir;
217        return 1;
218    default:
219        return 0;
220    }
221}
222
223int Piece::Ungrab(int2 pos)
224{
225    switch (data->state)
226    {
227    case PieceData::IDLE:
228    case PieceData::BLINK:
229    case PieceData::GRAB:
230    case PieceData::UNGRAB:
231    case PieceData::MOVE:
232        data->state = PieceData::UNGRAB;
233        data->speed = 0.4f;
234        data->timer = 0.0f;
235        data->src = data->pos;
236        data->dst = pos;
237        return 1;
238    default:
239        return 0;
240    }
241}
242
243int Piece::Move(int2 pos)
244{
245    switch (data->state)
246    {
247    case PieceData::IDLE:
248    case PieceData::BLINK:
249    case PieceData::UNGRAB:
250    case PieceData::MOVE:
251        data->state = PieceData::MOVE;
252        data->speed = 0.3f;
253        data->timer = 0.0f;
254        data->src = data->pos;
255        data->dst = pos;
256        return 1;
257    case PieceData::GRAB:
258    default:
259        return 0;
260    }
261}
262
263void Piece::TickGame(float deltams)
264{
265    switch (data->state)
266    {
267    case PieceData::IDLE:
268        data->timer -= deltams;
269        if (data->timer < 0.0f)
270            data->timer = data->idle = RandF(DELAY_IDLE, 2 * DELAY_IDLE);
271        data->blink -= deltams;
272        if (data->blink < 0.0f)
273        {
274            data->state = PieceData::BLINK;
275            data->timer = DURATION_BLINK;
276        }
277        break;
278    case PieceData::BLINK:
279        data->timer -= deltams;
280        if (data->timer < 0.0f)
281        {
282            data->state = PieceData::IDLE;
283            data->timer = data->idle = RandF(DELAY_IDLE, 2 * DELAY_IDLE);
284            data->blink = RandF(DELAY_BLINK, 2 * DELAY_BLINK);
285        }
286        break;
287    case PieceData::GRAB:
288        break;
289    case PieceData::UNGRAB:
290    case PieceData::MOVE:
291    {
292        data->timer += deltams;
293        int2 trip = data->dst - data->src;
294        float moving_time = trip.len() / data->speed;
295        float t = moving_time ? data->timer / moving_time : 1.0f;
296        if (t >= 1.0f)
297            t = 1.0f;
298        data->pos = data->src + (t * trip + 0.5f);
299        /* If the piece below is blocking us, clamp our position and
300         * start falling again. */
301        if (data->state == PieceData::MOVE && data->below
302             && data->pos.y < data->below->data->pos.y + data->size.y)
303        {
304            data->pos.y = data->below->data->pos.y + data->size.y;
305            data->src = data->pos;
306            data->timer = 0.0f;
307        }
308        if (data->timer > moving_time + 200.0f)
309        {
310            data->state = PieceData::IDLE;
311            data->timer = data->idle = RandF(DELAY_IDLE, 2 * DELAY_IDLE);
312        }
313        break;
314    }
315    case PieceData::POP:
316        data->timer -= deltams;
317        if (data->timer < 0.0f)
318        {
319            float3 pos(data->pos.x + 24, data->pos.y + 72, 5);
320            int start = data->id + 12;
321            int stop = data->id + 15;
322            for (int id = start; id < stop; id++)
323            {
324                float angle = RandF(-1.2f, 1.2f);
325                float speed = RandF(0.3f, 0.5f);
326                float3 vel(speed * sinf(angle), speed * cosf(angle), 0.0f);
327                data->emitter->AddParticle(id, pos, vel);
328            }
329
330            data->state = PieceData::DEAD;
331        }
332        break;
333    case PieceData::DEAD:
334        break;
335    }
336    Entity::TickGame(deltams);
337}
338
339void Piece::TickDraw(float deltams)
340{
341    Entity::TickDraw(deltams);
342
343    int id = data->id, off = 0;
344    int x = data->pos.x + 24;
345    int y = data->pos.y + 72;
346    int z = 2;
347
348    /* Optional modifiers */
349    switch (data->state)
350    {
351    case PieceData::IDLE:
352    {
353        off = data->timer * 3 / data->idle;
354        if (off < 0) off = 0;
355        if (off > 2) off = 2;
356        break;
357    }
358    case PieceData::BLINK:
359        off = 3;
360        break;
361    case PieceData::GRAB:
362        off = 3;
363        z = 4;
364        break;
365    case PieceData::UNGRAB:
366        if ((data->cell * data->size - data->src).sqlen()
367              > data->size.sqlen() / 8)
368            off = 7;
369        z = 4;
370        break;
371    case PieceData::MOVE:
372        z = 3;
373        break;
374    case PieceData::POP:
375    {
376        off = 4 - (int)(data->timer * 5 / DELAY_POP);
377        if (off < 0) off = 0;
378        if (off > 4) off = 4;
379        off += 7;
380        break;
381    }
382    case PieceData::DEAD:
383        break;
384    }
385
386    /* Only change image if the required frame is available */
387    switch (data->piece)
388    {
389    case PIECE_HUNT:
390        id += off;
391        break;
392    case PIECE_FUSION:
393        break;
394    }
395
396    if (data->state != PieceData::DEAD)
397        Scene::GetDefault()->AddTile((data->tiler << 16) | id, x, y, z, 0);
398
399    if (data->state == PieceData::GRAB)
400        Scene::GetDefault()->AddTile((data->tiler << 16) | 0, x, y, 5, 0);
401}
402
403Piece::~Piece()
404{
405    if (data->above)
406        Ticker::Unref(data->above);
407    if (data->below)
408        Ticker::Unref(data->below);
409    Ticker::Unref(data->emitter);
410    Tiler::Deregister(data->tiler);
411    delete data;
412}
413
Note: See TracBrowser for help on using the repository browser.