source: trunk/monsterz/title.cpp @ 735

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

core: get rid of now useless <cstdio> includes.

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