source: trunk/monsterz/title.cpp @ 633

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

TileSets can now be initialised either using the tile size, or the
known number of tiles in a row and a column. Necessary for ticket #24.

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