source: trunk/monsterz/title.cpp @ 754

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

monsterz: start rearranging the title screen.

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