source: trunk/monsterz/title.cpp @ 686

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

Put everything in the "lol" namespace. Better late than never.

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