1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2004-2015 SuperTuxKart-Team
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 #include "modes/overworld.hpp"
19
20 #include "audio/music_manager.hpp"
21 #include "challenges/unlock_manager.hpp"
22 #include "config/player_manager.hpp"
23 #include "config/user_config.hpp"
24 #include "graphics/irr_driver.hpp"
25 #include "input/device_manager.hpp"
26 #include "input/input.hpp"
27 #include "input/input_manager.hpp"
28 #include "input/keyboard_device.hpp"
29 #include "karts/abstract_kart.hpp"
30 #include "karts/kart_properties.hpp"
31 #include "karts/kart_properties_manager.hpp"
32 #include "karts/rescue_animation.hpp"
33 #include "physics/btKart.hpp"
34 #include "physics/physics.hpp"
35 #include "states_screens/dialogs/select_challenge.hpp"
36 #include "states_screens/offline_kart_selection.hpp"
37 #include "states_screens/race_gui_overworld.hpp"
38 #include "tracks/track.hpp"
39 #include "tracks/track_object_manager.hpp"
40
41 //-----------------------------------------------------------------------------
OverWorld()42 OverWorld::OverWorld() : World()
43 {
44 m_return_to_garage = false;
45 m_stop_music_when_dialog_open = false;
46 m_play_track_intro_sound = false;
47 } // Overworld
48
49 //-----------------------------------------------------------------------------
~OverWorld()50 OverWorld::~OverWorld()
51 {
52 Vec3 kart_xyz = getKart(0)->getXYZ();
53 RaceManager::get()->setKartLastPositionOnOverworld(kart_xyz);
54 } // ~OverWorld
55
56 //-----------------------------------------------------------------------------
57 /** Function to simplify the start process */
enterOverWorld()58 void OverWorld::enterOverWorld()
59 {
60 // update point count and the list of locked/unlocked stuff
61 PlayerManager::getCurrentPlayer()->computeActive();
62
63 RaceManager::get()->setNumPlayers(1);
64 RaceManager::get()->setMajorMode (RaceManager::MAJOR_MODE_SINGLE);
65 RaceManager::get()->setMinorMode (RaceManager::MINOR_MODE_OVERWORLD);
66 RaceManager::get()->setNumKarts( 1 );
67 RaceManager::get()->setTrack( "overworld" );
68
69 if (PlayerManager::getCurrentPlayer()->isLocked("difficulty_best"))
70 {
71 RaceManager::get()->setDifficulty(RaceManager::DIFFICULTY_HARD);
72 }
73 else
74 {
75 RaceManager::get()->setDifficulty(RaceManager::DIFFICULTY_BEST);
76 }
77
78 // Use keyboard 0 by default (FIXME: let player choose?)
79 InputDevice* device = input_manager->getDeviceManager()->getKeyboard(0);
80
81 // Create player and associate player with keyboard
82 StateManager::get()->createActivePlayer(PlayerManager::getCurrentPlayer(),
83 device);
84
85 if (!kart_properties_manager->getKart(UserConfigParams::m_default_kart))
86 {
87 Log::warn("[overworld]", "cannot find kart '%s', "
88 "will revert to default",
89 UserConfigParams::m_default_kart.c_str());
90
91 UserConfigParams::m_default_kart.revertToDefaults();
92 }
93 RaceManager::get()->setPlayerKart(0, UserConfigParams::m_default_kart);
94
95 // ASSIGN should make sure that only input from assigned devices
96 // is read.
97 input_manager->getDeviceManager()->setAssignMode(ASSIGN);
98 input_manager->getDeviceManager()
99 ->setSinglePlayer( StateManager::get()->getActivePlayer(0) );
100
101 StateManager::get()->enterGameState();
102 RaceManager::get()->setupPlayerKartInfo();
103 RaceManager::get()->startNew(false);
104 if(RaceManager::get()->haveKartLastPositionOnOverworld()){
105 OverWorld *ow = (OverWorld*)World::getWorld();
106 ow->getKart(0)->setXYZ(RaceManager::get()->getKartLastPositionOnOverworld());
107 ow->moveKartAfterRescue(ow->getKart(0));
108 }
109 irr_driver->showPointer(); // User should be able to click on the minimap
110
111 } // enterOverWorld
112
113 //-----------------------------------------------------------------------------
114 /** General update function called once per frame.
115 * \param ticks Number of physics time steps - should be 1.
116 */
update(int ticks)117 void OverWorld::update(int ticks)
118 {
119 // Skip annoying waiting without a purpose
120 // Make sure to do all things that would normally happen in the
121 // update() method of the base classes.
122 if (getPhase() < GO_PHASE)
123 {
124 setPhase(RACE_PHASE);
125 // Normally done in WorldStatus::update(), during phase SET_PHASE,
126 // so we have to start music 'manually', since we skip all phases.
127 Track::getCurrentTrack()->startMusic();
128
129 if (UserConfigParams::m_music)
130 music_manager->startMusic();
131 m_karts[0]->startEngineSFX();
132 }
133 World::update(ticks);
134 World::updateTrack(ticks);
135 const unsigned int kart_amount = (unsigned int)m_karts.size();
136
137 // isn't it cool, on the overworld nitro is free!
138 for(unsigned int n=0; n<kart_amount; n++)
139 {
140 m_karts[n]->setEnergy(100.0f);
141 }
142
143 /*
144 TrackObjectManager* tom = getTrack()->getTrackObjectManager();
145 PtrVector<TrackObject>& objects = tom->getObjects();
146 for(unsigned int i=0; i<objects.size(); i++)
147 {
148 TrackObject* obj = objects.get(i);
149 if(!obj->isGarage())
150 continue;
151
152 float m_distance = obj->getDistance();
153 Vec3 m_garage_pos = obj->getPosition();
154 Vec3 m_kart_pos = getKart(0)->getXYZ();
155
156 if ((m_garage_pos-m_kart_pos).length_2d() > m_distance)
157 {
158 obj->reset();
159 }
160 }
161 */
162
163 if (m_return_to_garage)
164 {
165 m_return_to_garage = false;
166 RaceManager::get()->exitRace();
167 KartSelectionScreen* s = OfflineKartSelectionScreen::getInstance();
168 s->setMultiplayer(false);
169 s->setFromOverworld(true);
170 StateManager::get()->resetAndGoToScreen(s);
171 throw AbortWorldUpdateException();
172 }
173 } // update
174
175 // ----------------------------------------------------------------------------
176 /** Finds the starting position which is closest to the kart.
177 * \param kart The kart for which a rescue position needs to be determined.
178 */
getRescuePositionIndex(AbstractKart * kart)179 unsigned int OverWorld::getRescuePositionIndex(AbstractKart *kart)
180 {
181 // find closest point to drop kart on
182 const int start_spots_amount = getNumberOfRescuePositions();
183 assert(start_spots_amount > 0);
184
185 int closest_id = -1;
186 float closest_distance = 999999999.0f;
187
188 for (int n=0; n<start_spots_amount; n++)
189 {
190 const btTransform &s = getStartTransform(n);
191 const Vec3 &v = s.getOrigin();
192
193 float abs_distance = (v - kart->getXYZ()).length();
194
195 if (abs_distance < closest_distance)
196 {
197 closest_distance = abs_distance;
198 closest_id = n;
199 }
200 }
201
202 assert(closest_id != -1);
203 return closest_id;
204 } // getRescuePositionIndex
205
206 //-----------------------------------------------------------------------------
207 /** This function is not used in the overworld race gui.
208 */
getKartsDisplayInfo(std::vector<RaceGUIBase::KartIconDisplayInfo> * info)209 void OverWorld::getKartsDisplayInfo(
210 std::vector<RaceGUIBase::KartIconDisplayInfo> *info)
211 {
212 assert(false);
213 } // getKartsDisplayInfo
214
215 //-----------------------------------------------------------------------------
216
createRaceGUI()217 void OverWorld::createRaceGUI()
218 {
219 m_race_gui = new RaceGUIOverworld();
220 } // createRaceGUI
221
222 //-----------------------------------------------------------------------------
223
onFirePressed(Controller * who)224 void OverWorld::onFirePressed(Controller* who)
225 {
226 const std::vector<OverworldChallenge>& challenges =
227 Track::getCurrentTrack()->getChallengeList();
228
229 AbstractKart* k = getKart(0);
230 Vec3 kart_xyz = k->getXYZ();
231 if (dynamic_cast<RescueAnimation*>(k->getKartAnimation()) != NULL)
232 {
233 // you can't start a race while being rescued
234 return;
235 }
236
237 for (unsigned int n=0; n<challenges.size(); n++)
238 {
239 if ( (kart_xyz - Vec3(challenges[n].m_position)).length2_2d()
240 < CHALLENGE_DISTANCE_SQUARED)
241 {
242 if (challenges[n].m_challenge_id == "tutorial")
243 {
244 scheduleTutorial();
245 return;
246 }
247 else
248 {
249 const ChallengeData* challenge = unlock_manager->getChallengeData(challenges[n].m_challenge_id);
250 if (challenge == NULL)
251 {
252 Log::error("track", "Cannot find challenge named '%s'\n",
253 challenges[n].m_challenge_id.c_str());
254 continue;
255 }
256
257 const unsigned int val = challenge->getNumTrophies();
258 // Mobile STK may have less challenges available than the main version
259 #ifdef MOBILE_STK
260 bool enough_challenges = true;
261 #else
262 const unsigned int val2 = challenge->getNumChallenges();
263 bool enough_challenges = (PlayerManager::getCurrentPlayer()->getNumCompletedChallenges() >= val2);
264 #endif
265 bool unlocked = enough_challenges && (PlayerManager::getCurrentPlayer()->getPoints() >= val);
266
267 if (UserConfigParams::m_unlock_everything > 0)
268 unlocked = true;
269
270 if (unlocked)
271 {
272 RaceManager::get()->setKartLastPositionOnOverworld(kart_xyz);
273 new SelectChallengeDialog(0.9f, 0.9f,
274 challenges[n].m_challenge_id);
275 }
276 }
277 } // end if
278 } // end for
279 } // onFirePressed
280
281 //-----------------------------------------------------------------------------
282 /** Called when a mouse click happens. If the click happened while the mouse
283 * was hovering on top of a challenge, the kart will be teleported to
284 * the challenge.
285 * \param x,y Mouse coordinates.
286 */
onMouseClick(int x,int y)287 void OverWorld::onMouseClick(int x, int y)
288 {
289 const OverworldChallenge *challenge =
290 ((RaceGUIOverworld*)getRaceGUI())->getCurrentChallenge();
291
292 if(challenge)
293 {
294 // Use the 'get closest start point' rescue function
295 // from World by setting the kart's position to
296 // be the location of the challenge bubble.
297 AbstractKart* kart = getKart(0);
298 kart->setXYZ(challenge->m_position);
299 kart->getVehicle()->setMaxSpeed(0);
300
301 unsigned int index = getRescuePositionIndex(kart);
302 btTransform s = getRescueTransform(index);
303 const btVector3 &xyz = s.getOrigin();
304 float angle = atan2(challenge->m_position.X - xyz[0],
305 challenge->m_position.Z - xyz[2]);
306 s.setRotation( btQuaternion(btVector3(0.0f, 1.0f, 0.0f), angle) );
307 moveKartTo(kart, s);
308 return;
309 }
310 } // onMouseClick
311