~ubuntu-branches/ubuntu/trusty/enigma/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/system-zipios-and-no-s3m/src/MusicManager.cc

  • Committer: Package Import Robot
  • Author(s): Erich Schubert
  • Date: 2013-04-06 14:54:02 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20130406145402-jgjrtk7hac8gtvza
Tags: 1.20-dfsg.1-1
* New upstream release (Closes: #704595)
  (Repacked: dropped zipios++ source and main menu music)
* Update watch file, sf.net again.
* Fix documentation links (Closes: #653508)
* Conflict with enigma-level-previews to encourage deinstallation
  (Pregenerated level previews were only used with version 1.01)
* Use dh7 for building instead of CDBS
* Update to policy 3.9.4.0 (no changes)
* Register documentation with doc-base

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2002,2003,2004 Daniel Heck
 
3
 * Copyright (C) 2007,2008,2009 Andreas Lochmann
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License along
 
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
18
 *
 
19
 */
 
20
#include "errors.hh"
 
21
#include "options.hh"
 
22
#include "MusicManager.hh"
 
23
#include "SoundEngine.hh"
 
24
#include "main.hh"
 
25
#include "lev/RatingManager.hh"
 
26
#include "lev/Index.hh"
 
27
 
 
28
#include "SDL.h"
 
29
#include "SDL_mixer.h"
 
30
 
 
31
#include <string>
 
32
#include <cassert>
 
33
 
 
34
using namespace enigma;
 
35
using namespace sound;
 
36
 
 
37
/* -------------------- Interface Functions -------------------- */
 
38
 
 
39
void sound::StartMenuMusic()
 
40
{
 
41
    MusicManager::instance()->setMusicContext(MUSIC_MENU);
 
42
}
 
43
 
 
44
void sound::StartLevelLoadMusic()
 
45
{
 
46
    MusicManager::instance()->setMusicContext(MUSIC_LEVEL_LOADING);
 
47
}
 
48
 
 
49
void sound::StartLevelMusic()
 
50
{
 
51
    MusicManager::instance()->setMusicContext(MUSIC_GAME);
 
52
}
 
53
 
 
54
void sound::SetInGameMusicActive(bool active)
 
55
{
 
56
    MusicManager::instance()->setInGameMusicActive(active);
 
57
}
 
58
 
 
59
void sound::MusicTick(double dtime)
 
60
{
 
61
    if(!sound::IsMusicMute())
 
62
        MusicManager::instance()->tick(dtime);
 
63
}
 
64
 
 
65
void sound::InitMusic()
 
66
{
 
67
    MusicManager::instance()->init();
 
68
}
 
69
 
 
70
void sound::DefineMusicSingle(std::string title, std::string filename,
 
71
        float affinity_intelligence, float affinity_dexterity, float affinity_patience,
 
72
        float affinity_knowledge, float affinity_speed)
 
73
{
 
74
    if(filename == "") {
 
75
        Log << "Warning: Tried to define music single '" << title
 
76
            << "' without file name. Skipped.\n";
 
77
        return;
 
78
    }
 
79
    MusicManager::instance()->defineMusicSingle(title, filename,
 
80
        affinity_intelligence, affinity_dexterity, affinity_patience,
 
81
        affinity_knowledge, affinity_speed);
 
82
}
 
83
 
 
84
/* -------------------- Sound option helpers -------------------- */
 
85
 
 
86
/*! These functions are used in OptionsMenu.cc for the MenuMusicButton. */
 
87
 
 
88
int sound::GetOptionMenuMusicCount()
 
89
{        
 
90
    return MusicManager::instance()->getMenuMusicQueueCount();
 
91
}
 
92
 
 
93
int sound::GetOptionMenuMusic()
 
94
{
 
95
    std::string music_queue = app.state->getString("MenuMusicQueue");
 
96
    int pos = MusicManager::instance()->getMusicQueueButtonPosition(music_queue);
 
97
    assert(pos >= 0);
 
98
    return pos;
 
99
}
 
100
 
 
101
void sound::SetOptionMenuMusic(int value)
 
102
{
 
103
    std::string music_queue = MusicManager::instance()->getMusicQueueByPosition(value);
 
104
    app.state->setProperty("MenuMusicQueue", music_queue);
 
105
    MusicManager::instance()->setMenuMusicQueue(music_queue);
 
106
}
 
107
 
 
108
std::string sound::GetOptionMenuMusicText(int value)
 
109
{
 
110
    return MusicManager::instance()->getMusicQueueByPosition(value);
 
111
}
 
112
 
 
113
/* -------------------- MusicManager -------------------- */
 
114
 
 
115
MusicManager *MusicManager::theSingleton = 0;
 
116
    
 
117
MusicManager* MusicManager::instance() {
 
118
    if (theSingleton == 0) {
 
119
        theSingleton = new MusicManager();
 
120
    }
 
121
    return theSingleton;
 
122
}
 
123
 
 
124
MusicManager::MusicManager()
 
125
: music_singles(), music_queues(), active_music_queue_title(""),
 
126
  ingame_music_queue_title(""), menu_music_queue_title(""),
 
127
  wait_length(-1), music_context(MUSIC_NONE), is_waiting(false),
 
128
  ingame_music_active(false)
 
129
{}
 
130
 
 
131
void MusicManager::tick(double dtime)
 
132
{
 
133
    static double cumulated_dtime = 0;
 
134
    if(!sound::IsMusicPlaying()) {
 
135
        if(is_waiting && (dtime > 0.0)) {
 
136
            // No music is playing, but we are actively counting seconds:
 
137
            // This is a silent phase of determined length ("waiting").
 
138
            cumulated_dtime += dtime;
 
139
            if(cumulated_dtime > wait_length) {
 
140
                cumulated_dtime = 0;
 
141
                stopWaiting();
 
142
                music_queues[active_music_queue_title].onWaitEnded();
 
143
            }        
 
144
        } else {
 
145
            // Music has really ended or not even begun.
 
146
            switch(getMusicContext()) {
 
147
                case MUSIC_NONE:
 
148
                    break;
 
149
                case MUSIC_GAME:
 
150
                    if(ingame_music_active)
 
151
                        music_queues[active_music_queue_title].onMusicEnded(false);
 
152
                    break;
 
153
                case MUSIC_MENU:
 
154
                    if(active_music_queue_title != "")
 
155
                        music_queues[active_music_queue_title].onMusicEnded(false);
 
156
                    break;
 
157
                case MUSIC_LEVEL_LOADING:
 
158
                    // Fadeout ended while level is still loading.
 
159
                    // Just wait until load is complete.
 
160
                    break;
 
161
                default:
 
162
                    Log << "Error: getMusicContext() returns an invalid type. Will ignore this.\n";
 
163
            }
 
164
        }
 
165
    }
 
166
}
 
167
 
 
168
void MusicManager::setMusicContext(MusicContext new_context)
 
169
{
 
170
    if(new_context == music_context)
 
171
        return;  // Nothing to do.
 
172
 
 
173
    switch(new_context) {
 
174
        case MUSIC_MENU:
 
175
            //sound::FadeoutMusic();
 
176
            //stopWaiting();
 
177
            //if(active_music_queue_title != "") {
 
178
            //    // onMusicEnded(true) means: force music, no waiting!
 
179
            //    music_queues[active_music_queue_title].onMusicEnded(true);
 
180
            //}
 
181
            Log << "Switching to menu music.\n";
 
182
            music_context = new_context;
 
183
            setActiveMusicQueue(getMenuMusicQueueTitle());
 
184
            break;
 
185
        case MUSIC_LEVEL_LOADING:
 
186
            Log << "Switching to level load music.\n";
 
187
            if(music_context == MUSIC_GAME) {
 
188
                // Switching from one level to another.
 
189
                music_context = new_context;
 
190
            } else {
 
191
                // Switching from menu to level, stop menu music.
 
192
                music_queues[active_music_queue_title].calculate_level_points();
 
193
                music_context = new_context;                
 
194
                setActiveMusicQueue(getInGameMusicQueueTitle());
 
195
            }
 
196
            break;
 
197
        case MUSIC_GAME:
 
198
            Log << "Switching to level music.\n";
 
199
            // TODO: Stop music if current music is not suitable.
 
200
            music_queues[active_music_queue_title].calculate_level_points();
 
201
            music_context = new_context;
 
202
            //sound::FadeoutMusic();
 
203
            setActiveMusicQueue(getInGameMusicQueueTitle());
 
204
            // We do not force music here, but leave it to "tick" to handle.
 
205
            break;
 
206
        case MUSIC_NONE:
 
207
            Log << "Switching to no music.\n";
 
208
            sound::FadeoutMusic(false);
 
209
            break;
 
210
    }    
 
211
}
 
212
 
 
213
void MusicManager::init()
 
214
{
 
215
    // TODO: This is only temporary. Information will come 
 
216
    // from an xml file later.
 
217
    
 
218
    // Menu Music
 
219
    music_singles["Esprit"] =
 
220
        MusicSingle("Esprit", "music/menu/esprit.ogg");
 
221
    music_singles["Pentagonal Dreams"] =
 
222
        MusicSingle("Pentagonal Dreams", "music/menu/pentagonal_dreams.s3m");
 
223
    
 
224
    // Level Music
 
225
    music_singles["Across The Ice"] =
 
226
        MusicSingle("Across The Ice", "music/game/across_the_ice.ogg", 0, 0.5, 0, 0, 0.5);
 
227
    music_singles["In Space"] =
 
228
        MusicSingle("In Space", "music/game/in_space.ogg", 0.3, 0, 0.4, 0, -0.3);
 
229
    music_singles["Meditation"] =
 
230
        MusicSingle("Meditation", "music/game/meditation.ogg", 0.4, 0.2, 0.4, 0, 0);
 
231
    music_singles["On The Water"] =
 
232
        MusicSingle("On The Water", "music/game/on_the_water.ogg", 0.2, 0.2, 0.2, 0.2, 0.4);
 
233
    music_singles["Puzzle"] =
 
234
        MusicSingle("Puzzle", "music/game/puzzle.ogg", 0.4, 0, 0.3, 0, 0.3);
 
235
    music_singles["Skull Stones"] =
 
236
        MusicSingle("Skull Stones", "music/game/skull_stones.ogg", 0, 0.5, -0.5, 0, 0);
 
237
    music_singles["Swamp"] =
 
238
        MusicSingle("Swamp", "music/game/swamp.ogg", 0.4, 0.1, -0.3, 0, 0.2);
 
239
 
 
240
    // Menu and Level Music
 
241
    music_singles["Enigma Rag"] =
 
242
        MusicSingle("Enigma Rag", "music/menu/enigma_rag.ogg", 0.4, -0.2, 0, 0, 0.4);
 
243
 
 
244
    // Menu Music Queues
 
245
    music_queues["Default"] = MusicQueue("Default", MUSICQUEUE_NEXT, 0);
 
246
    music_queues["Default"].appendSingle("Esprit", false);
 
247
    music_queues["Default"].appendSingle("Esprit", false);
 
248
    music_queues["Default"].appendSingleThenWait("Esprit", true, 8.0);
 
249
    music_queues["Default"].appendSingleThenWait("Enigma Rag", true, 8.0);
 
250
    music_queues["Default"].appendSingleThenWait("Pentagonal Dreams", true, 8.0);
 
251
 
 
252
    music_queues["Esprit"] = MusicQueue("Esprit", MUSICQUEUE_NEXT, 1);
 
253
    music_queues["Esprit"].appendSingle("Esprit", false);
 
254
 
 
255
    music_queues["Enigma Rag"] = MusicQueue("Enigma Rag", MUSICQUEUE_NEXT, 2);
 
256
    music_queues["Enigma Rag"].appendSingleThenWait("Enigma Rag", false, 8.0);
 
257
 
 
258
    music_queues["Pentagonal Dreams"] = MusicQueue("Pentagonal Dreams", MUSICQUEUE_NEXT, 3);
 
259
    music_queues["Pentagonal Dreams"].appendSingle("Pentagonal Dreams", true);
 
260
 
 
261
    active_music_queue_title = app.state->getString("MenuMusicQueue");
 
262
    // Set the default menu music queue, if saved queue doesn't exist.
 
263
    if(music_queues.find(active_music_queue_title) == music_queues.end())
 
264
    {
 
265
        Log << "Warning: Did not find specified menu music queue '"
 
266
            << active_music_queue_title << "', will switch to default.\n";
 
267
        active_music_queue_title = "Default";
 
268
        app.state->setProperty("MenuMusicQueue", active_music_queue_title);
 
269
    }
 
270
 
 
271
    // Level Music Queue
 
272
    music_queues["In Game"] = MusicQueue("In Game", MUSICQUEUE_LEVEL, 4);
 
273
    music_queues["In Game"].appendSingleThenWait("Across The Ice", true, 3.0);
 
274
    music_queues["In Game"].appendSingleThenWait("In Space", true, 3.0);
 
275
    music_queues["In Game"].appendSingleThenWait("Meditation", true, 3.0);
 
276
    music_queues["In Game"].appendSingleThenWait("On The Water", true, 3.0);
 
277
    music_queues["In Game"].appendSingleThenWait("Puzzle", true, 3.0);
 
278
    music_queues["In Game"].appendSingleThenWait("Skull Stones", true, 3.0);
 
279
    music_queues["In Game"].appendSingleThenWait("Swamp", true, 3.0);
 
280
    music_queues["In Game"].appendSingleThenWait("Enigma Rag", true, 3.0);
 
281
    
 
282
    menu_music_queue_title = app.state->getString("MenuMusicQueue");
 
283
    // Set the default menu music queue, if saved queue doesn't exist.
 
284
    if(music_queues.find(menu_music_queue_title) == music_queues.end())
 
285
    {
 
286
        Log << "Warning: Did not find specified menu music queue '"
 
287
            << menu_music_queue_title << "', will switch to default.\n";
 
288
        menu_music_queue_title = "Default";
 
289
        app.state->setProperty("MenuMusicQueue", menu_music_queue_title);
 
290
    }
 
291
    ingame_music_active = app.prefs->getBool("InGameMusic");
 
292
    ingame_music_queue_title = "In Game";   
 
293
    
 
294
    // setMusicContext will set active_music_queue_title as well;
 
295
    // after this, tick will start the music.
 
296
    setMusicContext(MUSIC_MENU);
 
297
    tick(-1);
 
298
}
 
299
 
 
300
bool MusicManager::defineMusicSingle(std::string title, std::string filename,
 
301
            float affinity_intelligence, float affinity_dexterity, float affinity_patience,
 
302
            float affinity_knowledge, float affinity_speed)
 
303
{
 
304
    music_singles[title] = MusicSingle(title, filename, affinity_intelligence,
 
305
        affinity_dexterity, affinity_patience, affinity_knowledge, affinity_speed);
 
306
    Log << "Added music single '" << title << "'.\n";
 
307
    return true;
 
308
}
 
309
 
 
310
bool MusicManager::playMusicSingle(std::string title)
 
311
{
 
312
    if(music_singles.find(title) == music_singles.end()) {
 
313
        // Single doesn't exist! Returning "false" will make the queue
 
314
        // mark its entry as "no_music", so this single will be ignored.
 
315
        return false;
 
316
    }
 
317
    return music_singles[title].start();
 
318
}
 
319
 
 
320
void MusicManager::setWaiting(float seconds)
 
321
{
 
322
    is_waiting = true;
 
323
    wait_length = seconds;
 
324
}
 
325
 
 
326
void MusicManager::stopWaiting()
 
327
{
 
328
    is_waiting = false;
 
329
    wait_length = -1;
 
330
}
 
331
 
 
332
bool MusicManager::setActiveMusicQueue(std::string music_queue_title)
 
333
{
 
334
    if (music_queue_title == "") {
 
335
        Log << "Warning: Tried to choose empty music queue title as active music queue.\n";
 
336
        return false;
 
337
    }
 
338
    if (music_queue_title == getActiveMusicQueueTitle()) {
 
339
        // Current queue is aready running.
 
340
        return true;
 
341
    }
 
342
    // Stop current music and leave this queue.
 
343
    sound::FadeoutMusic();
 
344
    if (active_music_queue_title != "")
 
345
        music_queues[active_music_queue_title].leave();
 
346
    // Switch to new queue if possible.
 
347
    stopWaiting();
 
348
    active_music_queue_title = music_queue_title;
 
349
    Log << "Switched to music queue '" << music_queue_title << "'.\n";
 
350
    return true;
 
351
    // We leave it to tick to start the new queue.
 
352
}
 
353
 
 
354
bool MusicManager::setMenuMusicQueue(std::string music_queue_title)
 
355
{
 
356
    if (music_queue_title == "") {
 
357
        Log << "Warning: Tried to choose empty music queue title as menu music queue.\n";
 
358
        return false;
 
359
    }
 
360
    if (menu_music_queue_title == music_queue_title)
 
361
        return true;
 
362
    menu_music_queue_title = music_queue_title;
 
363
    if(getMusicContext() == MUSIC_MENU)
 
364
        return setActiveMusicQueue(music_queue_title);
 
365
    return true;
 
366
}
 
367
 
 
368
bool MusicManager::setInGameMusicQueue(std::string music_queue_title)
 
369
{
 
370
    if (music_queue_title == "") {
 
371
        Log << "Warning: Tried to choose empty music queue title as in-game music queue.\n";
 
372
        return false;
 
373
    }
 
374
    if (ingame_music_queue_title == music_queue_title)
 
375
        return true;
 
376
    ingame_music_queue_title = music_queue_title;
 
377
    if(getMusicContext() == MUSIC_GAME)
 
378
        return setActiveMusicQueue(music_queue_title);
 
379
    return true;
 
380
}
 
381
 
 
382
std::string MusicManager::getMusicQueueByPosition(int button_position)
 
383
{
 
384
    for (MusicQueueRepository::iterator i = music_queues.begin();
 
385
             i != music_queues.end(); ++i)
 
386
        if((*i).second.getButtonPosition() == button_position)
 
387
            return (*i).first;
 
388
    return "";
 
389
}
 
390
 
 
391
int MusicManager::getMenuMusicQueueCount()
 
392
{
 
393
    int count = 0;
 
394
    for (MusicQueueRepository::iterator i = music_queues.begin();
 
395
             i != music_queues.end(); ++i)
 
396
        if((*i).second.getButtonPosition() != -1)
 
397
            count++;
 
398
    return count;
 
399
}
 
400
 
 
401
std::string MusicManager::getCurrentMusicTitle() {
 
402
    if(sound::IsMusicPlaying() && (active_music_queue_title != ""))
 
403
        return music_queues[active_music_queue_title].getCurrentMusicTitle();
 
404
    else
 
405
        return "";
 
406
}
 
407
 
 
408
void MusicManager::setInGameMusicActive(bool active)
 
409
{
 
410
    ingame_music_active = active;
 
411
    if ((getMusicContext() == MUSIC_GAME) && (!ingame_music_active))
 
412
    {
 
413
        sound::FadeoutMusic();
 
414
        if (active_music_queue_title != "")
 
415
            music_queues[active_music_queue_title].leave();
 
416
    }
 
417
}
 
418
 
 
419
MusicSingle MusicManager::getMusicSingle(std::string title)
 
420
{
 
421
    if(music_singles.find(title) != music_singles.end())
 
422
        return music_singles[title];
 
423
    else
 
424
    {
 
425
        Log << "Warning: Did not find music single " << title << ".\n";
 
426
        return MusicSingle();
 
427
    }
 
428
}
 
429
 
 
430
/* -------------------- Music Single -------------------- */
 
431
 
 
432
bool MusicSingle::start()
 
433
{
 
434
    if(title == MusicManager::instance()->getCurrentMusicTitle())
 
435
        return true;
 
436
    if(sound::PlayMusic(filename))
 
437
        return true;
 
438
    return false;
 
439
}
 
440
 
 
441
float MusicSingle::affinity(float lev_int, float lev_dex, float lev_pat,
 
442
                            float lev_kno, float lev_spe)
 
443
{
 
444
    return   (affinity_intelligence * lev_int)
 
445
           + (affinity_dexterity * lev_dex)
 
446
           + (affinity_patience * lev_pat)
 
447
           + (affinity_knowledge * lev_kno)
 
448
           + (affinity_speed * lev_spe);
 
449
}
 
450
 
 
451
 
 
452
/* -------------------- Music Queue -------------------- */
 
453
 
 
454
std::string MusicQueue::getCurrentMusicTitle()
 
455
{
 
456
    if(current_position_in_queue == -1)
 
457
        return "";
 
458
    else
 
459
        return queue_entry[current_position_in_queue].title;
 
460
}
 
461
 
 
462
void MusicQueue::appendSingle(std::string title, bool fadeout_on_end)
 
463
{
 
464
    MusicQueueEntry new_entry;
 
465
    new_entry.type = MUSICQUEUE_SINGLE;
 
466
    new_entry.title = title;
 
467
    new_entry.fadeout_on_end = fadeout_on_end;
 
468
    // TODO: fadeout_on_end currently doesn't work, as the music
 
469
    //       ends before it is noticed that the next entry of the
 
470
    //       queue should be read.
 
471
    new_entry.wait_length = -1;
 
472
    new_entry.no_music = false;
 
473
    new_entry.points_transient = 0;
 
474
    new_entry.points_level = 0;
 
475
    new_entry.points_total = 0;
 
476
    queue_entry.push_back(new_entry);
 
477
}
 
478
 
 
479
void MusicQueue::appendSingleThenWait(std::string title, bool fadeout_on_end, float seconds)
 
480
{
 
481
    appendSingle(title, fadeout_on_end);
 
482
    (queue_entry.back()).wait_length = seconds;
 
483
}
 
484
 
 
485
void MusicQueue::appendWait(float seconds)
 
486
{
 
487
    MusicQueueEntry new_entry;
 
488
    new_entry.type = MUSICQUEUE_WAIT;
 
489
    new_entry.title = "";
 
490
    new_entry.fadeout_on_end = false;
 
491
    new_entry.wait_length = seconds;
 
492
    new_entry.no_music = true;
 
493
    new_entry.points_transient = 0;
 
494
    new_entry.points_level = 0;
 
495
    new_entry.points_total = 0;
 
496
    queue_entry.push_back(new_entry);
 
497
}
 
498
 
 
499
bool MusicQueue::start()
 
500
{
 
501
    current_position_in_queue = -1;
 
502
    return next();
 
503
    // We explicitly allow the queue to start silent.
 
504
    // Otherwise use next(true), i.e. force_music.
 
505
    // "next()" will also take care of empty queues.
 
506
}
 
507
 
 
508
void MusicQueue::calculate_level_points()
 
509
{
 
510
    lev::RatingManager *theRatingMgr = lev::RatingManager::instance();
 
511
    lev::Proxy *currentLevel = (lev::Index::getCurrentIndex())->getCurrent();
 
512
    MusicManager *theMusicMgr = MusicManager::instance();
 
513
    float currentInt = theRatingMgr->getIntelligence(currentLevel);
 
514
    float currentDex = theRatingMgr->getDexterity(currentLevel);
 
515
    float currentPat = theRatingMgr->getPatience(currentLevel);
 
516
    float currentKno = theRatingMgr->getKnowledge(currentLevel);
 
517
    float currentSpe = theRatingMgr->getSpeed(currentLevel);
 
518
    // If the requested level does not exist, theRatingMgr will
 
519
    // return 0 instead. We shift ratings such that 2.8 is seen as 0.
 
520
    // Special handling for knowledge == 6 (set to 0).
 
521
    //Log << currentInt << "/" << currentDex << "/" << currentPat << "/" <<
 
522
    // currentKno << "/" << currentSpe << "\n";
 
523
    currentInt = (currentInt == 0) ? 0 : (currentInt - 2.8);
 
524
    currentDex = (currentDex == 0) ? 0 : (currentDex - 2.8);
 
525
    currentPat = (currentPat == 0) ? 0 : (currentPat - 2.8);
 
526
    currentKno = ((currentKno == 0) || (currentKno == 6)) ? 0 : (currentKno - 2.8);
 
527
    currentSpe = (currentSpe == 0) ? 0 : (currentSpe - 2.8);
 
528
    //Log << currentInt << "/" << currentDex << "/" << currentPat << "/" <<
 
529
    // currentKno << "/" << currentSpe << "\n";
 
530
    for(int j = 0; j < queue_entry.size(); j++)
 
531
        if(queue_entry[j].type == MUSICQUEUE_SINGLE)
 
532
        {
 
533
            std::string title = queue_entry[j].title;
 
534
            queue_entry[j].points_level =
 
535
                (theMusicMgr->getMusicSingle(title)).affinity(
 
536
                currentInt, currentDex, currentPat, currentKno, currentSpe);
 
537
            //Log << title << ": " << queue_entry[j].points_level << "\n";
 
538
        }
 
539
}
 
540
 
 
541
bool MusicQueue::next(bool force_music)
 
542
{
 
543
    if(defunc)
 
544
        return false;
 
545
 
 
546
    if(queue_entry.size() <= 0) {
 
547
        Log << "Music queue is empty. No music will be played.\n";
 
548
        return false;
 
549
    }
 
550
 
 
551
    if(current_position_in_queue != -1) {
 
552
        // Another queue entry ended before this. Maybe we have to fade out.
 
553
        MusicQueueEntry old_entry = queue_entry[current_position_in_queue];
 
554
        if(old_entry.fadeout_on_end && sound::IsMusicPlaying())
 
555
            sound::FadeoutMusic();
 
556
    }
 
557
 
 
558
    int new_position = (current_position_in_queue >= 0) ? current_position_in_queue : 0;
 
559
    switch(shuffle_type) {
 
560
        case MUSICQUEUE_NEXT:
 
561
            // Jump to next position in queue.
 
562
            new_position = (current_position_in_queue + 1) % queue_entry.size();
 
563
            break;
 
564
        case MUSICQUEUE_RANDOM:
 
565
            // Jump to a random position in queue other than the current.
 
566
            if(queue_entry.size() < 2)
 
567
                break; // Don't change current_position.
 
568
            while (new_position == current_position_in_queue)
 
569
                new_position = IntegerRand(0, queue_entry.size() - 1, false);
 
570
            break;
 
571
        case MUSICQUEUE_LEVEL:
 
572
            // Calculate the optimal single (or maybe silence phase).
 
573
            if(current_position_in_queue >= 0)
 
574
                queue_entry[current_position_in_queue].points_transient += -10;
 
575
            for(int j = 0; j < queue_entry.size(); j++)
 
576
            {
 
577
                queue_entry[j].points_transient = queue_entry[j].points_transient / 2.0;
 
578
                queue_entry[j].points_total = queue_entry[j].points_transient
 
579
                    + queue_entry[j].points_level + IntegerRand(0, 300, false) / 1000.0;
 
580
                Log << j << ": " << queue_entry[j].title << ": " << queue_entry[j].points_level
 
581
                    << " + " << queue_entry[j].points_transient << " -> " <<
 
582
                    queue_entry[j].points_total << "\n";
 
583
            }
 
584
            float best_value = queue_entry[new_position].points_total;
 
585
            for(int j = 0; j < queue_entry.size(); j++)
 
586
                if (queue_entry[j].points_total >= best_value)
 
587
                {
 
588
                    best_value = queue_entry[j].points_total;
 
589
                    new_position = j;
 
590
                }
 
591
            Log << "Chose " << queue_entry[new_position].title << "\n";
 
592
            break;
 
593
    }
 
594
    current_position_in_queue = new_position;
 
595
        
 
596
    MusicQueueEntry current_entry = queue_entry[current_position_in_queue];
 
597
    bool success = false;
 
598
    switch(current_entry.type) {
 
599
        case MUSICQUEUE_SINGLE:
 
600
            Log << "Play next in queue " << title << ": " << current_entry.title << ".\n";
 
601
            success = MusicManager::instance()->playMusicSingle(current_entry.title);
 
602
            queue_entry[current_position_in_queue].no_music = !success;
 
603
            if(!success)
 
604
                assureQueueHasMusic();
 
605
            return success;
 
606
            break;
 
607
        case MUSICQUEUE_WAIT:
 
608
            if(force_music)
 
609
                return false;  // this will cause "tick" to call "next" again.
 
610
            Log << "Music queue starts waiting (" << current_entry.wait_length << "s).\n";
 
611
            MusicManager::instance()->setWaiting(current_entry.wait_length);
 
612
            return true;
 
613
            break;
 
614
        default:
 
615
            Log << "Error: Current music queue entry is of invalid type. Will ignore this.\n";
 
616
            return false;
 
617
    }
 
618
}
 
619
 
 
620
bool MusicQueue::onMusicEnded(bool force_music)
 
621
{
 
622
    if((current_position_in_queue >= 0) && (current_position_in_queue < queue_entry.size())) {
 
623
        MusicQueueEntry current_entry = queue_entry[current_position_in_queue];
 
624
        if((current_entry.wait_length > 0) && (!current_entry.no_music) && (!force_music))
 
625
        {
 
626
            Log << "Music queue starts conditional waiting (" << current_entry.wait_length << "s).\n";
 
627
            MusicManager::instance()->setWaiting(current_entry.wait_length);
 
628
            return true;
 
629
        } else
 
630
            return next(force_music);
 
631
    }
 
632
    return start();
 
633
}
 
634
 
 
635
bool MusicQueue::onWaitEnded()
 
636
{
 
637
    return next();
 
638
}
 
639
 
 
640
void MusicQueue::leave()
 
641
{
 
642
    /*! We have the following choices to determine where to start the queue
 
643
      next time. Remember that "next" will be called and auto-increase
 
644
      current_position_in_queue.
 
645
      Complete reset: current_position_in_queue = -1;
 
646
      Start with n-th song: current_position_in_queue = n - 2;
 
647
      Restart the current: decrease current_position_in_queue by one.
 
648
      Start the next position in queue: don't change anything.
 
649
      However, what we want is: Jump to the next real music, skip all kinds of
 
650
      silent breaks. Cycle through until the end of the queue; if nothing is
 
651
      found, always start the queue from the beginning. */
 
652
    int total = queue_entry.size();
 
653
    while(   (queue_entry[(current_position_in_queue + 1) % total].type != MUSICQUEUE_SINGLE)
 
654
          && (current_position_in_queue < total)) {
 
655
        current_position_in_queue++;
 
656
    }
 
657
    if(current_position_in_queue >= total)
 
658
        current_position_in_queue = -1;
 
659
}
 
660
 
 
661
void MusicQueue::assureQueueHasMusic()
 
662
{
 
663
    /*! This is called when a queue might have no music at all,
 
664
      e.g. because all of its referenced files don't exist. Each time a
 
665
      file is missing, its entry is changed to "no_music = true". Pure
 
666
      waiting phases have "no_music = true" just as well. If all entries
 
667
      are "no_music = true", then the queue is set to "defunc = true". */
 
668
    bool queue_has_no_music = true;
 
669
    for(std::vector<MusicQueueEntry>::const_iterator iter = queue_entry.begin();
 
670
            iter != queue_entry.end(); ++iter)
 
671
        queue_has_no_music = queue_has_no_music && (*iter).no_music;
 
672
    if(queue_has_no_music) {
 
673
        defunc = true;
 
674
        Log << "Warning: Queue " << title << " has no playable music! (Files missing?) Deactivated it.\n";
 
675
    }
 
676
}
 
677