1 // This file is part of Dust Racing 2D.
2 // Copyright (C) 2015 Jussi Lind <jussi.lind@iki.fi>
3 //
4 // Dust Racing 2D is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 // Dust Racing 2D is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Dust Racing 2D. If not, see <http://www.gnu.org/licenses/>.
15 
16 #include "statemachine.hpp"
17 #include "inputhandler.hpp"
18 
19 #include <MenuManager>
20 #include <cassert>
21 
22 StateMachine * StateMachine::m_instance = nullptr;
23 
StateMachine(InputHandler & inputHandler)24 StateMachine::StateMachine(InputHandler & inputHandler)
25   : m_state(State::Init)
26   , m_oldState(State::Init)
27   , m_raceFinished(false)
28   , m_inputHandler(inputHandler)
29 {
30     assert(!StateMachine::m_instance);
31     StateMachine::m_instance = this;
32 
33     m_stateToFunctionMap[State::Init] = std::bind(&StateMachine::stateInit, this);
34     m_stateToFunctionMap[State::DoIntro] = std::bind(&StateMachine::stateDoIntro, this);
35     m_stateToFunctionMap[State::Menu] = std::bind(&StateMachine::stateMenu, this);
36     m_stateToFunctionMap[State::MenuTransitionIn] = std::bind(&StateMachine::stateMenuTransitionIn, this);
37     m_stateToFunctionMap[State::MenuTransitionOut] = std::bind(&StateMachine::stateMenuTransitionOut, this);
38     m_stateToFunctionMap[State::GameTransitionIn] = std::bind(&StateMachine::stateGameTransitionIn, this);
39     m_stateToFunctionMap[State::GameTransitionOut] = std::bind(&StateMachine::stateGameTransitionOut, this);
40     m_stateToFunctionMap[State::DoStartlights] = std::bind(&StateMachine::stateDoStartlights, this);
41     m_stateToFunctionMap[State::Play] = std::bind(&StateMachine::statePlay, this);
42 }
43 
~StateMachine()44 StateMachine::~StateMachine()
45 {
46     StateMachine::m_instance = nullptr;
47 }
48 
instance()49 StateMachine & StateMachine::instance()
50 {
51     assert(StateMachine::m_instance);
52     return *StateMachine::m_instance;
53 }
54 
quit()55 void StateMachine::quit()
56 {
57     if (m_state == StateMachine::State::Play)
58     {
59         m_state = State::GameTransitionOut;
60     }
61     else if (m_state == StateMachine::State::Menu)
62     {
63         emit exitGameRequested();
64     }
65 }
66 
update()67 bool StateMachine::update()
68 {
69     // Run the state function on transition
70     if (m_state == State::Init || m_oldState != m_state)
71     {
72         m_oldState = m_state;
73         m_stateToFunctionMap[m_state]();
74     }
75 
76     // Transition logic that needs to be constantly updated
77     if (m_state == State::Menu)
78     {
79         if (MTFH::MenuManager::instance().isDone())
80         {
81             m_state = State::MenuTransitionOut;
82         }
83     }
84 
85     return true;
86 }
87 
endFadeIn()88 void StateMachine::endFadeIn()
89 {
90     switch (m_state)
91     {
92     case State::GameTransitionIn:
93         m_state = State::DoStartlights;
94         break;
95     case State::MenuTransitionIn:
96         m_state = State::Menu;
97         break;
98     default:
99         break;
100     }
101 }
102 
endFadeOut()103 void StateMachine::endFadeOut()
104 {
105     switch (m_state)
106     {
107     case State::MenuTransitionOut:
108         m_state = State::GameTransitionIn;
109         break;
110     case State::GameTransitionOut:
111         m_state = State::MenuTransitionIn;
112         break;
113     default:
114         break;
115     }
116 }
117 
endStartlightAnimation()118 void StateMachine::endStartlightAnimation()
119 {
120     m_state = State::Play;
121 }
122 
stateInit()123 void StateMachine::stateInit()
124 {
125     m_state = State::DoIntro;
126 }
127 
stateDoIntro()128 void StateMachine::stateDoIntro()
129 {
130     m_timer.singleShot(3000, [&]() {
131         if (m_state == State::DoIntro)
132         {
133             m_state = State::Menu;
134         }
135     });
136 
137     emit renderingEnabled(true);
138 }
139 
stateMenu()140 void StateMachine::stateMenu()
141 {
142     // Re-init the current menu
143     MTFH::MenuManager::instance().enterCurrentMenu();
144 }
145 
stateMenuTransitionIn()146 void StateMachine::stateMenuTransitionIn()
147 {
148     emit fadeInRequested(0, 2000, 0);
149     emit soundsStopped();
150 }
151 
stateMenuTransitionOut()152 void StateMachine::stateMenuTransitionOut()
153 {
154     emit fadeOutFlashRequested(0, 2000, 0);
155 }
156 
stateGameTransitionIn()157 void StateMachine::stateGameTransitionIn()
158 {
159     emit fadeInRequested(0, 2000, 0);
160 
161     m_inputHandler.reset();
162 }
163 
stateGameTransitionOut()164 void StateMachine::stateGameTransitionOut()
165 {
166     if (m_raceFinished)
167     {
168         emit fadeOutRequested(10000, 10000, 0);
169     }
170     else
171     {
172         emit fadeOutRequested(0, 2000, 0);
173     }
174 }
175 
stateDoStartlights()176 void StateMachine::stateDoStartlights()
177 {
178     emit startlightAnimationRequested();
179 }
180 
statePlay()181 void StateMachine::statePlay()
182 {
183     m_raceFinished = false;
184 }
185 
finishRace()186 void StateMachine::finishRace()
187 {
188     m_state = State::GameTransitionOut;
189     m_raceFinished = true;
190 }
191 
state() const192 StateMachine::State StateMachine::state() const
193 {
194     return m_state;
195 }
196 
reset()197 void StateMachine::reset()
198 {
199     m_state = State::Init;
200 }
201