source: trunk/monsterz/title.cpp @ 664

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

Get rid of float3, float4, int3 etc. in favour of GLSL types.

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    vec2 cloudpos[5];
61    vec2 cloudspeed[5];
62
63    int eagley;
64
65    float timer, length, eagletimer;
66    int nframes, animid;
67};
68
69static vec2i const animsize[] =
70{
71    vec2i(384, 384),
72    vec2i(284, 81),
73    vec2i(38, 146),
74    vec2i(29, 137),
75    vec2i(284, 82),
76    vec2i(384, 384),
77};
78
79static vec2i const animpos[] =
80{
81    vec2i(0, 0),
82    vec2i(65, 255),
83    vec2i(239, 168),
84    vec2i(248, 168),
85    vec2i(63, 255),
86    vec2i(0, 0),
87};
88
89static vec2i const eventsize[] =
90{
91    vec2i(143, 16),
92    vec2i(68, 49),
93    vec2i(17, 29),
94    vec2i(50, 80),
95    vec2i(237, 238),
96    vec2i(59, 53),
97    vec2i(140, 15),
98};
99
100static vec2i const eventpos[] =
101{
102    vec2i(0, 322),
103    vec2i(316, 286),
104    vec2i(246, 245),
105    vec2i(279, 173),
106    vec2i(42, 101),
107    vec2i(231, 154),
108    vec2i(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, vec2i(380, 181), 0, 1.0f);
121    data->title = Tiler::Register(PNG_TITLE, 384, 0, 1.0f);
122    data->stars = Tiler::Register(PNG_STARS, vec2i(384, 144), 0, 1.0f);
123    data->clouds = Tiler::Register(PNG_CLOUDS, vec2i(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] = vec2(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 = vec3i(24, 72, 1);
146    bbox[0] = position;
147    bbox[1] = bbox[0] + vec3i(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    vec2i 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.