source: trunk/monsterz/piece.cpp @ 303

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

Heavily optimise the crappy initial board generation.

File size: 7.0 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
89void Piece::SetAbove(Piece *above)
90{
91    Piece *old = data->above;
92
93    if (above == old)
94        return;
95
96    if (old)
97        Ticker::Unref(old);
98    data->above = above;
99    if (above)
100        Ticker::Ref(above);
101
102    if (old)
103        old->SetBelow(NULL);
104    if (above)
105        above->SetBelow(this);
106}
107
108Piece *Piece::GetAbove() const
109{
110    return data->above;
111}
112
113void Piece::SetBelow(Piece *below)
114{
115    Piece *old = data->below;
116
117    if (below == old)
118        return;
119
120    if (old)
121        Ticker::Unref(old);
122    data->below = below;
123    if (below)
124        Ticker::Ref(below);
125
126    if (old)
127        old->SetAbove(NULL);
128    if (below)
129        below->SetAbove(this);
130}
131
132Piece *Piece::GetBelow() const
133{
134    return data->below;
135}
136
137int Piece::IsDead() const
138{
139    return data->state == PieceData::DEAD;
140}
141
142int Piece::Blink()
143{
144    switch (data->state)
145    {
146    case PieceData::IDLE:
147        data->state = PieceData::BLINK;
148        data->timer = DELAY_BLINK;
149        return 1;
150    default:
151        return 0;
152    }
153}
154
155int Piece::Pop()
156{
157    switch (data->state)
158    {
159    case PieceData::IDLE:
160    case PieceData::BLINK:
161    case PieceData::GRAB:
162    case PieceData::UNGRAB:
163    case PieceData::MOVE:
164    case PieceData::POP:
165        data->state = PieceData::POP;
166        data->timer = DELAY_DUH + DELAY_POP;
167        return 1;
168    default:
169        return 0;
170    }
171}
172
173int Piece::Grab(int2 dir)
174{
175    switch (data->state)
176    {
177    case PieceData::UNGRAB:
178    case PieceData::MOVE:
179        /* Only allow swaps when piece is close enough to its target cell. */
180        if ((data->cell * 48 - data->pos).sqlen() > 24 * 24)
181            return 0;
182        /* Fall through */
183    case PieceData::IDLE:
184    case PieceData::BLINK:
185    case PieceData::GRAB:
186        data->state = PieceData::GRAB;
187        data->pos = data->pos + dir;
188        return 1;
189    default:
190        return 0;
191    }
192}
193
194int Piece::Ungrab(int2 pos)
195{
196    switch (data->state)
197    {
198    case PieceData::IDLE:
199    case PieceData::BLINK:
200    case PieceData::GRAB:
201    case PieceData::UNGRAB:
202    case PieceData::MOVE:
203        data->state = PieceData::UNGRAB;
204        data->speed = 0.4f;
205        data->timer = 0.0f;
206        data->src = data->pos;
207        data->dst = pos;
208        return 1;
209    default:
210        return 0;
211    }
212}
213
214int Piece::Move(int2 pos)
215{
216    switch (data->state)
217    {
218    case PieceData::IDLE:
219    case PieceData::BLINK:
220    case PieceData::UNGRAB:
221    case PieceData::MOVE:
222        data->state = PieceData::MOVE;
223        data->speed = 0.3f;
224        data->timer = 0.0f;
225        data->src = data->pos;
226        data->dst = pos;
227        return 1;
228    case PieceData::GRAB:
229    default:
230        return 0;
231    }
232}
233
234void Piece::TickGame(float deltams)
235{
236    switch (data->state)
237    {
238    case PieceData::IDLE:
239        break;
240    case PieceData::BLINK:
241        data->timer -= deltams;
242        if (data->timer < 0.0f)
243            data->state = PieceData::IDLE;
244        break;
245    case PieceData::GRAB:
246        break;
247    case PieceData::UNGRAB:
248    case PieceData::MOVE:
249    {
250        data->timer += deltams;
251        int2 trip = data->dst - data->src;
252        float moving_time = trip.len() / data->speed;
253        float t = moving_time ? data->timer / moving_time : 1.0f;
254        if (t >= 1.0f)
255            t = 1.0f;
256        data->pos = data->src + (t * trip + 0.5f);
257        /* If the piece below is blocking us, clamp our position and
258         * start falling again. */
259        if (data->state == PieceData::MOVE && data->below
260             && data->pos.y < data->below->data->pos.y + 48)
261        {
262            data->pos.y = data->below->data->pos.y + 48;
263            data->src = data->pos;
264            data->timer = 0.0f;
265        }
266        if (data->timer > moving_time + 200.0f)
267            data->state = PieceData::IDLE;
268        break;
269    }
270    case PieceData::POP:
271        data->timer -= deltams;
272        if (data->timer < 0.0f)
273        {
274            float3 pos(data->pos.x + 24, data->pos.y + 177, 5);
275            int start = data->id + 10;
276            int stop = data->id + 13;
277            for (int id = start; id < stop; id++)
278            {
279                float3 vel(RandF(-0.3f, 0.3f), RandF(0.2f, 0.3f), 0.0f);
280                data->emitter->AddParticle(id, pos, vel);
281            }
282
283            data->state = PieceData::DEAD;
284        }
285        break;
286    case PieceData::DEAD:
287        break;
288    }
289    Entity::TickGame(deltams);
290}
291
292void Piece::TickDraw(float deltams)
293{
294    Entity::TickDraw(deltams);
295
296    int id = data->id;
297    int x = data->pos.x + 24;
298    int y = data->pos.y + 177;
299    int z = 2;
300
301    /* Optional modifiers */
302    switch (data->state)
303    {
304    case PieceData::IDLE:
305        break;
306    case PieceData::BLINK:
307        id = data->id + 1;
308        break;
309    case PieceData::GRAB:
310        id = data->id + 1;
311        z = 4;
312        break;
313    case PieceData::UNGRAB:
314        if ((data->cell * 48 - data->src).sqlen() > 24 * 24)
315            id = data->id + 5;
316        z = 4;
317        break;
318    case PieceData::MOVE:
319        z = 3;
320        break;
321    case PieceData::POP:
322    {
323        int off = 4 - (data->timer * 5 / DELAY_POP);
324        if (off < 0) off = 0;
325        if (off > 4) off = 4;
326        id = data->id + 5 + off;
327        break;
328    }
329    case PieceData::DEAD:
330        break;
331    }
332
333    if (data->state != PieceData::DEAD)
334        Scene::GetDefault()->AddTile((data->tiler << 16) | id, x, y, z, 0);
335
336    if (data->state == PieceData::GRAB)
337        Scene::GetDefault()->AddTile((data->tiler << 16) | 0, x, y, 5, 0);
338}
339
340Piece::~Piece()
341{
342    if (data->above)
343        Ticker::Unref(data->above);
344    if (data->below)
345        Ticker::Unref(data->below);
346    Ticker::Unref(data->emitter);
347    Tiler::Deregister(data->tiler);
348    delete data;
349}
350
Note: See TracBrowser for help on using the repository browser.