stk-code_catmod/src/modes/overworld.cpp
Alayan-stk-2 6a25384ed9 SuperTux in Story Mode (and other improvements) (#3207)
* Add SuperTux difficulty & update number of karts

Also make the expert challenge slightly easier to match more the difficulty of other challenges.

* Add SuperTux difficulty & update number of karts & points required

Also give some more time margin in easier difficulties, as it is a hard challenge compared to most.

* Add SuperTux difficulty & update number of karts & points required

Also change the lap count to 4 as it is a very short track (sub 30s)

* Add SuperTux difficulty

Also tweak the expert challenge to have a more appropriate difficulty

* Add SuperTux difficulty & update number of karts

* Add SuperTux difficulty & update number of karts & points required

* Add SuperTux difficulty & update number of karts & points required

Also correct the requirement position, since this is not a FTL race anymore.

* Add SuperTux difficulty & update number of karts & points required

Also slight balancing improvements for the usual difficulties.

* Add SuperTux difficulty & update number of karts & points required

Also adds a position requirement in expert

* Add SuperTux difficulty & update number of karts & points required

* Add SuperTux difficulty & update number of karts & points required

* Add SuperTux difficulty & update number of karts & points required

Also change the number of laps to 5, as this is a very short track. The time requirements for easier difficulties have been kept proportionally similar to before.

* Add SuperTux difficulty & update number of karts & points required

Also change the number of laps to 4.

* Add SuperTux difficulty & update number of karts & points required

Also add a position requirement to expert and intermediate.

* Add SuperTux difficulty & update number of karts & points required

Also change the number of laps to 4, as a lap often is 30s or less in expert/supertux

* Add SuperTux difficulty & update number of karts & points required

* Add SuperTux difficulty & update number of karts & points required

* Rename islandtrack.challenge to gran_paradiso.challenge

* Rename challenge file

* Add SuperTux difficulty & update number of karts & points required

Also makes the time limit in expert less easy and tweak position requirement.

* Add SuperTux difficulty & update number of karts

* Add SuperTux difficulty & update number of karts & points required

* Add SuperTux difficulty & update number of karts & points required

* Add SuperTux difficulty & update number of karts & points required

* Add SuperTux difficulty & update number of karts & points required 

Doesn't unlock the SuperTux difficulty anymore - it's managed elsewhere.

* Add SuperTux difficulty & update number of karts & points required

* Add SuperTux difficulty & update number of karts & points required

* Add new unlock challenges, for difficulty and karts

* Add a lap to oliver's math class

* Replace Northern Resort by Volcano Island

* Replace Volcano Island by Candela City

Candela City was in no (official) GP before this.

Also sets Green Valley to 3 laps.

* Add Northern Resort and remove Fort Magma

In 0.9.3, this GP has only 4 races in Story Mode (5 for the other GPs) because Fort Magma is locked.

Of all the tracks outside this GP before, Northern Resort is one of the hardest, the AI being rather good there.

* Temporary cup for SuperTux challenges

Recolored version of the gold cup

* Update challenge selection UI for the SuperTux challenges

* GUI used before SuperTux difficulty unlocking

This is the old select_challenge.stkgui

* Swap the two sara

* Replace Kiki by another kart to unlock on Benau's demand

* Update for improved Story Mode

* Update for improved Story Mode

* Add support for SuperTux challenges

* Add support for SuperTux challenges

* Add support for SuperTux challenges

* Add support for SuperTux challenges

* Update for SuperTux ; also adds the ability to unlock a challenge by points

* Update for unlocking by points

* Add support for SuperTux challenges

* Add support for SuperTux challenges

* Add support for SuperTux challenges

* Minor changes to function calls

* Update for SuperTux challenges

* Add support for SuperTux challenges

* Update for Story Mode GP changes

* Allows to display the correct number of points for GP challenges

* Set the unlock of the 1st bonus kart to correct non-test value

* Add support for SuperTux challenges

Including a bigger challenge selection diaolg

* Add default value

* Icon to indicate that there is an unlockable

The number of points needed to unlock it are displayed next to it.

* Changed format : the point requirements is now specified in the file

* Changed format : the point requirements is now specified in the file

* Changed format : the point requirements is now specified in the file

* Function for unlock by points UI

* Add default for unlock list node and use requirements node for all

* Make unlockByPoints simpler and more flexible

Now the code will iterate in StoryModeStatus and send the unlock_list challenges for treatment here. The question of getting the right challenge statuses beings solved, it allows for a great simplification and much more flexibility

* Update unlockByPoints declaration

* Adds support for next unlockable UI

* Improve call of unlockByPoints

Also calculations for displaying in the UI how many point the next unlockable by points requires.

* Add icon for next unlockable

* Displays icon/number to make the player aware of the next unlockable

Also displays the number below the icon rather than on the side, for more clarity.

* Changes to display karts in the unlock scene

* Update unlock functions declarations

* New function to clarify code and more logical recently unlocked list management

In the previous version, everything was added to the recently unlocked list at some point, necessitating a clearing at the end of computeActive, which also removed from the list the non-race challenges. Checking if the feature is newly unlocked to add it to the list remove the need of that clearing.

* Declaration for unlockFeatureByList

* Display newly unlocked karts

* Display newly unlocked karts

* Clear the list of recently unlocked features at the end

* Update testing code

* Update unlocks finding function call

* Improve UI scaling

* Fixes indentation

* Update the number of points before checking for unlock by points

* Add const to declarations

* Remove const_cast

* Remove a const_cast

There are other const_cast in the menu debug items (but they are unrelated to this PR)

* Fix menu being bolder
2018-04-29 18:27:03 -04:00

304 lines
10 KiB
C++

// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2004-2015 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "modes/overworld.hpp"
#include "audio/music_manager.hpp"
#include "challenges/unlock_manager.hpp"
#include "config/player_manager.hpp"
#include "config/user_config.hpp"
#include "graphics/irr_driver.hpp"
#include "input/device_manager.hpp"
#include "input/input.hpp"
#include "input/input_manager.hpp"
#include "input/keyboard_device.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp"
#include "karts/rescue_animation.hpp"
#include "physics/btKart.hpp"
#include "physics/physics.hpp"
#include "states_screens/dialogs/select_challenge.hpp"
#include "states_screens/offline_kart_selection.hpp"
#include "states_screens/race_gui_overworld.hpp"
#include "tracks/track.hpp"
#include "tracks/track_object_manager.hpp"
//-----------------------------------------------------------------------------
OverWorld::OverWorld() : World()
{
m_return_to_garage = false;
m_stop_music_when_dialog_open = false;
m_play_track_intro_sound = false;
} // Overworld
//-----------------------------------------------------------------------------
OverWorld::~OverWorld()
{
Vec3 kart_xyz = getKart(0)->getXYZ();
race_manager->setKartLastPositionOnOverworld(kart_xyz);
} // ~OverWorld
//-----------------------------------------------------------------------------
/** Function to simplify the start process */
void OverWorld::enterOverWorld()
{
// update point count and the list of locked/unlocked stuff
PlayerManager::getCurrentPlayer()->computeActive();
race_manager->setNumPlayers(1);
race_manager->setMajorMode (RaceManager::MAJOR_MODE_SINGLE);
race_manager->setMinorMode (RaceManager::MINOR_MODE_OVERWORLD);
race_manager->setNumKarts( 1 );
race_manager->setTrack( "overworld" );
if (PlayerManager::getCurrentPlayer()->isLocked("difficulty_best"))
{
race_manager->setDifficulty(RaceManager::DIFFICULTY_HARD);
}
else
{
race_manager->setDifficulty(RaceManager::DIFFICULTY_BEST);
}
// Use keyboard 0 by default (FIXME: let player choose?)
InputDevice* device = input_manager->getDeviceManager()->getKeyboard(0);
// Create player and associate player with keyboard
StateManager::get()->createActivePlayer(PlayerManager::getCurrentPlayer(),
device);
if (!kart_properties_manager->getKart(UserConfigParams::m_default_kart))
{
Log::warn("[overworld]", "cannot find kart '%s', "
"will revert to default",
UserConfigParams::m_default_kart.c_str());
UserConfigParams::m_default_kart.revertToDefaults();
}
race_manager->setPlayerKart(0, UserConfigParams::m_default_kart);
// ASSIGN should make sure that only input from assigned devices
// is read.
input_manager->getDeviceManager()->setAssignMode(ASSIGN);
input_manager->getDeviceManager()
->setSinglePlayer( StateManager::get()->getActivePlayer(0) );
StateManager::get()->enterGameState();
race_manager->setupPlayerKartInfo();
race_manager->startNew(false);
if(race_manager->haveKartLastPositionOnOverworld()){
OverWorld *ow = (OverWorld*)World::getWorld();
ow->getKart(0)->setXYZ(race_manager->getKartLastPositionOnOverworld());
ow->moveKartAfterRescue(ow->getKart(0));
}
irr_driver->showPointer(); // User should be able to click on the minimap
} // enterOverWorld
//-----------------------------------------------------------------------------
/** General update function called once per frame.
* \param ticks Number of physics time steps - should be 1.
*/
void OverWorld::update(int ticks)
{
// Skip annoying waiting without a purpose
// Make sure to do all things that would normally happen in the
// update() method of the base classes.
if (getPhase() < GO_PHASE)
{
setPhase(RACE_PHASE);
// Normally done in WorldStatus::update(), during phase SET_PHASE,
// so we have to start music 'manually', since we skip all phases.
Track::getCurrentTrack()->startMusic();
if (UserConfigParams::m_music)
music_manager->startMusic();
m_karts[0]->startEngineSFX();
}
World::update(ticks);
World::updateTrack(ticks);
const unsigned int kart_amount = (unsigned int)m_karts.size();
// isn't it cool, on the overworld nitro is free!
for(unsigned int n=0; n<kart_amount; n++)
{
m_karts[n]->setEnergy(100.0f);
}
/*
TrackObjectManager* tom = getTrack()->getTrackObjectManager();
PtrVector<TrackObject>& objects = tom->getObjects();
for(unsigned int i=0; i<objects.size(); i++)
{
TrackObject* obj = objects.get(i);
if(!obj->isGarage())
continue;
float m_distance = obj->getDistance();
Vec3 m_garage_pos = obj->getPosition();
Vec3 m_kart_pos = getKart(0)->getXYZ();
if ((m_garage_pos-m_kart_pos).length_2d() > m_distance)
{
obj->reset();
}
}
*/
if (m_return_to_garage)
{
m_return_to_garage = false;
race_manager->exitRace();
KartSelectionScreen* s = OfflineKartSelectionScreen::getInstance();
s->setMultiplayer(false);
s->setFromOverworld(true);
StateManager::get()->resetAndGoToScreen(s);
throw AbortWorldUpdateException();
}
} // update
// ----------------------------------------------------------------------------
/** Finds the starting position which is closest to the kart.
* \param kart The kart for which a rescue position needs to be determined.
*/
unsigned int OverWorld::getRescuePositionIndex(AbstractKart *kart)
{
// find closest point to drop kart on
const int start_spots_amount = getNumberOfRescuePositions();
assert(start_spots_amount > 0);
int closest_id = -1;
float closest_distance = 999999999.0f;
for (int n=0; n<start_spots_amount; n++)
{
const btTransform &s = getStartTransform(n);
const Vec3 &v = s.getOrigin();
float abs_distance = (v - kart->getXYZ()).length();
if (abs_distance < closest_distance)
{
closest_distance = abs_distance;
closest_id = n;
}
}
assert(closest_id != -1);
return closest_id;
} // getRescuePositionIndex
//-----------------------------------------------------------------------------
/** This function is not used in the overworld race gui.
*/
void OverWorld::getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info)
{
assert(false);
} // getKartsDisplayInfo
//-----------------------------------------------------------------------------
void OverWorld::createRaceGUI()
{
m_race_gui = new RaceGUIOverworld();
} // createRaceGUI
//-----------------------------------------------------------------------------
void OverWorld::onFirePressed(Controller* who)
{
const std::vector<OverworldChallenge>& challenges =
Track::getCurrentTrack()->getChallengeList();
AbstractKart* k = getKart(0);
Vec3 kart_xyz = k->getXYZ();
if (dynamic_cast<RescueAnimation*>(k->getKartAnimation()) != NULL)
{
// you can't start a race while being rescued
return;
}
for (unsigned int n=0; n<challenges.size(); n++)
{
if ( (kart_xyz - Vec3(challenges[n].m_position)).length2_2d()
< CHALLENGE_DISTANCE_SQUARED)
{
if (challenges[n].m_challenge_id == "tutorial")
{
scheduleTutorial();
return;
}
else
{
const ChallengeData* challenge = unlock_manager->getChallengeData(challenges[n].m_challenge_id);
if (challenge == NULL)
{
Log::error("track", "Cannot find challenge named '%s'\n",
challenges[n].m_challenge_id.c_str());
continue;
}
const unsigned int val = challenge->getNumTrophies();
bool unlocked = (PlayerManager::getCurrentPlayer()->getPoints() >= val);
if (UserConfigParams::m_everything_unlocked)
unlocked = true;
if (unlocked)
{
race_manager->setKartLastPositionOnOverworld(kart_xyz);
new SelectChallengeDialog(0.9f, 0.9f,
challenges[n].m_challenge_id);
}
}
} // end if
} // end for
} // onFirePressed
//-----------------------------------------------------------------------------
/** Called when a mouse click happens. If the click happened while the mouse
* was hovering on top of a challenge, the kart will be teleported to
* the challenge.
* \param x,y Mouse coordinates.
*/
void OverWorld::onMouseClick(int x, int y)
{
const OverworldChallenge *challenge =
((RaceGUIOverworld*)getRaceGUI())->getCurrentChallenge();
if(challenge)
{
// Use the 'get closest start point' rescue function
// from World by setting the kart's position to
// be the location of the challenge bubble.
AbstractKart* kart = getKart(0);
kart->setXYZ(challenge->m_position);
kart->getVehicle()->setMaxSpeed(0);
unsigned int index = getRescuePositionIndex(kart);
btTransform s = getRescueTransform(index);
const btVector3 &xyz = s.getOrigin();
float angle = atan2(challenge->m_position.X - xyz[0],
challenge->m_position.Z - xyz[2]);
s.setRotation( btQuaternion(btVector3(0.0f, 1.0f, 0.0f), angle) );
moveKartTo(kart, s);
return;
}
} // onMouseClick