source: trunk/monsterz/title.cpp @ 790

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

tileset: replace the Tiler ID system with real TileSet objects. The only
thing that is still broken is the Layer <--> Map interface.

File size: 10.2 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#ifdef WIN32
16#   define _USE_MATH_DEFINES /* for M_PI */
17#   define WIN32_LEAN_AND_MEAN
18#   include <windows.h>
19#endif
20
21#include <cmath>
22#include <cstdlib>
23#include <ctime>
24
25#include "core.h"
26
27using namespace std;
28using namespace lol;
29
30#include "monsterz.h"
31#include "title.h"
32
33/*
34 * Title implementation class
35 */
36
37class TitleData
38{
39    friend class Title;
40
41private:
42    TileSet *title, *stars, *clouds, *eagle, *logo, *ground;
43    TileSet *anim[6];
44    TileSet *event[7];
45
46    enum
47    {
48        IDLE,
49        ANIM,
50        EVENT,
51    }
52    state;
53
54    enum
55    {
56        DAY,
57        NIGHT,
58        STEALTH,
59        RADIO,
60    }
61    period, nextperiod;
62
63    vec2 cloudpos[5];
64    vec2 cloudspeed[5];
65
66    vec2i ground_pos;
67
68    int eagley;
69
70    float timer, length, eagletimer;
71    int nframes, animid;
72};
73
74static vec2i const animsize[] =
75{
76    vec2i(384, 384),
77    vec2i(284, 81),
78    vec2i(38, 146),
79    vec2i(29, 137),
80    vec2i(284, 82),
81    vec2i(384, 384),
82};
83
84static vec2i const animpos[] =
85{
86    vec2i(0, 0),
87    vec2i(65, 255),
88    vec2i(239, 168),
89    vec2i(248, 168),
90    vec2i(63, 255),
91    vec2i(0, 0),
92};
93
94static vec2i const eventsize[] =
95{
96    vec2i(143, 16),
97    vec2i(68, 49),
98    vec2i(17, 29),
99    vec2i(50, 80),
100    vec2i(237, 238),
101    vec2i(59, 53),
102    vec2i(140, 15),
103};
104
105static vec2i const eventpos[] =
106{
107    vec2i(0, 322),
108    vec2i(316, 286),
109    vec2i(246, 245),
110    vec2i(279, 173),
111    vec2i(42, 101),
112    vec2i(231, 154),
113    vec2i(0, 322),
114};
115
116/*
117 * Public Title class
118 */
119
120Title::Title()
121  : data(new TitleData())
122{
123    srand(rand() ^ time(NULL));
124
125    data->logo = Tiler::Register(PNG_TITLE_LOGO, vec2i(380, 181), 0, 1.0f);
126    data->ground = Tiler::Register(PNG_TITLE_GROUND, vec2i(384, 80), 0, 1.0f);
127    data->ground_pos = vec2i(640 / 2 - 384 / 2, 480 / 4 - 80);
128
129    data->title = Tiler::Register(PNG_TITLE, 384, 0, 1.0f);
130    data->stars = Tiler::Register(PNG_STARS, vec2i(384, 144), 0, 1.0f);
131    data->clouds = Tiler::Register(PNG_CLOUDS, vec2i(160, 32), 0, 1.0f);
132    data->eagle = Tiler::Register(PNG_EAGLE, 16, 0, 1.0f);
133    for (int n = 0; n < 6; n++)
134        data->anim[n] = Tiler::Register(PNG_TITLEANIM[n],
135                                        animsize[n], 0, 1.0f);
136    for (int n = 0; n < 7; n++)
137        data->event[n] = Tiler::Register(PNG_TITLEEVENT[n],
138                                         eventsize[n], 0, 1.0f);
139    data->state = TitleData::IDLE;
140    data->period = TitleData::DAY;
141    data->nextperiod = TitleData::DAY;
142    data->timer = RandF(2000.0f, 3000.0f);
143    data->eagletimer = RandF(DURATION_EAGLE, 4 * DURATION_EAGLE);
144
145    for (int n = 0; n < 5; n++)
146    {
147        data->cloudpos[n] = vec2(RandF(384), RandF(130, 190));
148        data->cloudspeed[n] = RandF(-0.01f, 0.01f);
149    }
150
151    data->eagley = 140 + rand() % 40;
152
153    position = vec3i(24, 72, 1);
154    bbox[0] = position;
155    bbox[1] = bbox[0] + vec3i(384, 384, 0);
156
157    Input::TrackMouse(this);
158}
159
160void Title::TickGame(float deltams)
161{
162    Entity::TickGame(deltams);
163
164    data->timer -= deltams;
165    data->eagletimer -= deltams;
166
167    /* Probability of playing an animation given the current period */
168    static float const p1[] = { 0.6f, 0.3f, 0.0f, 0.2f };
169    /* Probability of a period change given the current period */
170    static float const p2[] = { 0.1f, 0.2f, 0.5f, 0.5f };
171    /* Number of frames in transition anims and events */
172    static int const t1[] = { 31, 26, 7, 7, 32, 6, 31 };
173    static int const t2[] = { 2, 4, 11, 4, 6, 2 };
174
175    for (int n = 0; n < 5; n++)
176    {
177        data->cloudpos[n].x += deltams * data->cloudspeed[n].x;
178        if (data->cloudpos[n].x > 384.0f)
179            data->cloudpos[n].x -= 384.0f;
180        else if (data->cloudpos[n].x < 0.0f)
181            data->cloudpos[n].x += 384.0f;
182    }
183
184    switch (data->state)
185    {
186    case TitleData::IDLE:
187        if (data->eagletimer < 0.0f)
188        {
189            data->eagletimer = RandF(DURATION_EAGLE, 4 * DURATION_EAGLE);
190            data->eagley = 140 + rand() % 40;
191        }
192        if (data->timer > 0.0f)
193            break;
194        if (RandF() < p1[data->period])
195        {
196            switch (data->period)
197            {
198            case TitleData::DAY:
199                data->animid = rand() % 4;
200                break;
201            case TitleData::NIGHT:
202                data->animid = (rand() % 2) ? 4 : 6;
203                break;
204            case TitleData::STEALTH:
205                /* XXX: we should not be here! */
206                break;
207            case TitleData::RADIO:
208                data->animid = 5;
209                break;
210            }
211            data->state = TitleData::EVENT;
212            data->nframes = t1[data->animid];
213            data->timer = data->length = data->nframes * 100.0f;
214        }
215        else if (RandF() < p2[data->period])
216        {
217            switch (data->period)
218            {
219            case TitleData::DAY:
220                data->nextperiod = TitleData::NIGHT;
221                data->animid = 0;
222                break;
223            case TitleData::NIGHT:
224                if (RandF() < 0.6f)
225                {
226                    data->nextperiod = TitleData::DAY;
227                    data->animid = 5;
228                }
229                else
230                {
231                    data->nextperiod = TitleData::STEALTH;
232                    data->animid = 1;
233                }
234                break;
235            case TitleData::STEALTH:
236                if (RandF() < 0.3f)
237                {
238                    data->nextperiod = TitleData::RADIO;
239                    data->animid = 2;
240                }
241                else
242                {
243                    data->nextperiod = TitleData::NIGHT;
244                    data->animid = 4;
245                }
246                break;
247            case TitleData::RADIO:
248                data->nextperiod = TitleData::STEALTH;
249                data->animid = 3;
250                break;
251            }
252            data->state = TitleData::ANIM;
253            data->nframes = t2[data->animid];
254            data->timer = data->length = data->nframes * 100.0f;
255        }
256        else
257        {
258            data->timer = RandF(500.0f, 1000.0f);
259        }
260        break;
261    case TitleData::ANIM:
262        if (data->timer < 0.0f)
263            data->period = data->nextperiod;
264            /* Fall through */
265    case TitleData::EVENT:
266        if (data->timer < 0.0f)
267        {
268            data->state = TitleData::IDLE;
269            data->timer = RandF(500.0f, 1000.0f);
270        }
271        break;
272    }
273}
274
275void Title::TickDraw(float deltams)
276{
277    Entity::TickDraw(deltams);
278
279    /* The background, always here. */
280    int backid = (int)data->period;
281    Scene::GetDefault()->AddTile(data->title, backid,
282                                 data->ground_pos.x, data->ground_pos.y, 1, 0);
283
284    /* The stars */
285    if (data->period != TitleData::DAY)
286    {
287        Scene::GetDefault()->AddTile(data->stars, 0,
288                                     24 + 0, 72 + 240, 2, 0);
289    }
290
291    /* The clouds. FIXME: tune color grading later */
292    int cloudoff = data->period == TitleData::DAY ? 0 : 3;
293
294    for (int n = 0; n < 5; n++)
295    {
296        int cloudid = n * 4 + cloudoff;
297        Scene::GetDefault()->AddTile(data->clouds, cloudid,
298                                     24 + data->cloudpos[n].x,
299                                     72 + data->cloudpos[n].y, 2, 0);
300        Scene::GetDefault()->AddTile(data->clouds, cloudid,
301                                     24 + data->cloudpos[n].x - 384.0f,
302                                     72 + data->cloudpos[n].y, 2, 0);
303    }
304
305    /* Maybe an eagle? */
306    if (data->eagletimer >= 0.0f)
307    {
308        int eagleid = (int)(data->eagletimer / 100) % 6;
309        if (data->period != TitleData::DAY)
310            eagleid += 6;
311        float phase = sinf(data->eagletimer * (2.0f * M_PI / 100 / 6));
312        int x = (DURATION_EAGLE - data->eagletimer) * 384 / DURATION_EAGLE;
313        int y = data->eagley + 5.0f * sinf(phase);
314        Scene::GetDefault()->AddTile(data->eagle, eagleid,
315                                     24 + x, 72 + y, 3, 0);
316    }
317
318    /* The ground. */
319    for (int x = (data->ground_pos.x - 1) % 384 - 384;
320         x < Video::GetSize().x; x += 384)
321    {
322        Scene::GetDefault()->AddTile(data->ground, 0,
323                                     x, data->ground_pos.y, 0, 0);
324    }
325
326    /* Maybe an animation? */
327    TileSet *tiler = NULL;
328    int id = 0;
329    vec2i pos = 0;
330
331    switch (data->state)
332    {
333    case TitleData::IDLE:
334        break;
335    case TitleData::ANIM:
336        tiler = data->anim[data->animid];
337        pos = animpos[data->animid];
338        pos.y = 384 - animsize[data->animid].y - pos.y; // Hack
339        id = (data->length - data->timer) * data->nframes / data->length;
340        if (id < 0) id = 0;
341        if (id > data->nframes - 1) id = data->nframes - 1;
342        break;
343    case TitleData::EVENT:
344        tiler = data->event[data->animid];
345        pos = eventpos[data->animid];
346        pos.y = 384 - eventsize[data->animid].y - pos.y; // Hack
347        id = (data->length - data->timer) * data->nframes / data->length;
348        if (id < 0) id = 0;
349        if (id > data->nframes - 1) id = data->nframes - 1;
350        break;
351    }
352    if (tiler)
353        Scene::GetDefault()->AddTile(tiler, id,
354                                     data->ground_pos.x + pos.x,
355                                     data->ground_pos.y + pos.y, 1, 0);
356
357    /* The logo, on top of the rest. */
358    Scene::GetDefault()->AddTile(data->logo, 0, 26, 250, 3, 0);
359}
360
361int Title::IsClicked() const
362{
363    return clicked[0];
364}
365
366Title::~Title()
367{
368    Input::UntrackMouse(this);
369    Tiler::Deregister(data->logo);
370    Tiler::Deregister(data->ground);
371    Tiler::Deregister(data->title);
372    Tiler::Deregister(data->stars);
373    Tiler::Deregister(data->clouds);
374    Tiler::Deregister(data->eagle);
375    for (int n = 0; n < 6; n++)
376        Tiler::Deregister(data->anim[n]);
377    for (int n = 0; n < 7; n++)
378        Tiler::Deregister(data->event[n]);
379    delete data;
380}
381
Note: See TracBrowser for help on using the repository browser.