source: trunk/monsterz/piece.cpp @ 664

Last change on this file since 664 was 664, checked in by sam, 9 years ago

Get rid of float3, float4, int3 etc. in favour of GLSL types.

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