Merge soccer mode back into trunk - but still WIP, can be disabled via a #define in race_setup_screen.cpp

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@12475 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
funto66
2013-02-11 22:30:50 +00:00
37 changed files with 1248 additions and 70 deletions

BIN
data/gui/mode_soccer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -0,0 +1,35 @@
<stkgui>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
<div x="5%" y="5%" width="90%" height="90%" layout="vertical-row" >
<header width="80%" text="Race Setup" align="center" text_align="center" />
<spacer height="25" width="25"/>
<div layout="horizontal-row" width="100%" height="50" align="center">
<bright proportion="1" height="100%"
I18N="In soccer setup menu" text="Number of goals to win" text_align="right" />
<spacer width="50" height="25"/>
<spinner id="goalamount" proportion="1" height="100%" min_value="1" max_value="30" wrap_around="true"/>
</div>
<spacer height="25" width="25"/>
<bright height="15" width="25" I18N="In soccer setup menu" text="Use left/right to choose your team" text_align="center" align="center" />
<spacer height="25" width="25"/>
<div id="central_div" layout="horizontal-row" width="100%" proportion="1" align="center">
<roundedbox x="2%" y="5%" proportion="1" layout="horizontal-row" height="100%">
<!-- Content is added programmatically -->
</roundedbox>
<header id="vs" text="VS"/> <!-- Layout is done programmatically -->
</div>
<button id="continue" I18N="In soccer setup screen" text="Continue" align="center" width="60%"/>
</div>
</stkgui>

View File

@@ -127,6 +127,7 @@ src/modes/game_tutorial.cpp
src/modes/linear_world.cpp
src/modes/overworld.cpp
src/modes/profile_world.cpp
src/modes/soccer_world.cpp
src/modes/standard_race.cpp
src/modes/three_strikes_battle.cpp
src/modes/tutorial_world.cpp
@@ -197,6 +198,7 @@ src/states_screens/race_gui.cpp
src/states_screens/race_gui_overworld.cpp
src/states_screens/race_result_gui.cpp
src/states_screens/race_setup_screen.cpp
src/states_screens/soccer_setup_screen.cpp
src/states_screens/state_manager.cpp
src/states_screens/story_mode_lobby.cpp
src/states_screens/tracks_screen.cpp
@@ -212,6 +214,7 @@ src/tinygettext/tinygettext.cpp
src/tracks/ambient_light_sphere.cpp
src/tracks/bezier_curve.cpp
src/tracks/check_cannon.cpp
src/tracks/check_goal.cpp
src/tracks/check_lap.cpp
src/tracks/check_line.cpp
src/tracks/check_manager.cpp

View File

@@ -133,11 +133,11 @@ void ModelViewWidget::update(float delta)
if (distance_with_positive_rotation < distance_with_negative_rotation)
{
angle += delta*(3.0f + std::min(distance_with_positive_rotation, distance_with_negative_rotation)*2.0f);
angle += m_rotation_speed * delta*(3.0f + std::min(distance_with_positive_rotation, distance_with_negative_rotation)*2.0f);
}
else
{
angle -= delta*(3.0f + std::min(distance_with_positive_rotation, distance_with_negative_rotation)*2.0f);
angle -= m_rotation_speed * delta*(3.0f + std::min(distance_with_positive_rotation, distance_with_negative_rotation)*2.0f);
}
if (angle > 360) angle -= 360;
if (angle < 0) angle += 360;

View File

@@ -63,7 +63,7 @@ namespace GUIEngine
LEAK_CHECK()
ModelViewWidget();
~ModelViewWidget();
virtual ~ModelViewWidget();
void add();
void clearModels();

View File

@@ -842,10 +842,9 @@ int handleCmdLine(int argc, char **argv)
argv[i+1]);
}
else if (t->isArena())
{
race_manager->setMinorMode(
RaceManager::MINOR_MODE_3_STRIKES);
}
race_manager->setMinorMode(RaceManager::MINOR_MODE_3_STRIKES);
else if(t->isSoccer())
race_manager->setMinorMode(RaceManager::MINOR_MODE_SOCCER);
}
/*
else

View File

@@ -116,7 +116,7 @@ bool DemoWorld::updateIdleTimeAndStartDemo(float dt)
// Remove arena tracks and internal tracks like the overworld
// (outside the if statement above in case that
// a user requests one of those ;) )
while((!track || track->isArena() || track->isInternal())
while((!track || track->isArena() || track->isSoccer() || track->isInternal())
&& m_demo_tracks.size() > 0)
{
if(!track)

View File

@@ -57,6 +57,7 @@ void LinearWorld::init()
WorldWithRank::init();
assert(!m_track->isArena());
assert(!m_track->isSoccer());
m_last_lap_sfx_played = false;
m_last_lap_sfx_playing = false;

331
src/modes/soccer_world.cpp Normal file
View File

@@ -0,0 +1,331 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2006 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/soccer_world.hpp"
#include <string>
#include <IMeshSceneNode.h>
#include "audio/music_manager.hpp"
#include "graphics/irr_driver.hpp"
#include "io/file_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/kart_model.hpp"
#include "karts/kart_properties.hpp"
#include "karts/rescue_animation.hpp"
#include "physics/physics.hpp"
#include "states_screens/race_gui_base.hpp"
#include "tracks/track.hpp"
#include "tracks/track_object_manager.hpp"
#include "utils/constants.hpp"
//-----------------------------------------------------------------------------
/** Constructor. Sets up the clock mode etc.
*/
SoccerWorld::SoccerWorld() : WorldWithRank()
{
WorldStatus::setClockMode(CLOCK_CHRONO);
m_use_highscores = false;
} // SoccerWorld
//-----------------------------------------------------------------------------
/** Initializes the soccer world. It sets up the data structure
* to keep track of points etc. for each kart.
*/
void SoccerWorld::init()
{
WorldWithRank::init();
m_display_rank = false;
m_can_score_points = true;
memset(m_team_goals, 0, sizeof(m_team_goals));
// check for possible problems if AI karts were incorrectly added
if(getNumKarts() > race_manager->getNumPlayers())
{
fprintf(stderr, "No AI exists for this game mode\n");
exit(1);
}
initKartList();
} // SoccerWorld
//-----------------------------------------------------------------------------
/** Returns the internal identifier for this race.
*/
const std::string& SoccerWorld::getIdent() const
{
return IDENT_SOCCER;
} // getIdent
//-----------------------------------------------------------------------------
/** Update the world and the track.
* \param dt Time step size.
*/
void SoccerWorld::update(float dt)
{
WorldWithRank::update(dt);
WorldWithRank::updateTrack(dt);
// TODO
} // update
void SoccerWorld::onCheckGoalTriggered(bool first_goal)
{
// TODO
if(m_can_score_points)
printf("*** GOOOOOOOOOAAAAAAALLLLLL!!!! (team: %d) ***\n", first_goal ? 0 : 1);
//m_check_goals_enabled = false; // TODO: remove?
// Reset original positions for the soccer balls
TrackObjectManager* tom = getTrack()->getTrackObjectManager();
assert(tom);
PtrVector<TrackObject>& objects = tom->getObjects();
for(int i=0; i<objects.size(); i++)
{
TrackObject* obj = objects.get(i);
if(!obj->isSoccerBall())
continue;
obj->reset();
}
//for(int i=0 ; i < getNumKarts() ; i++
/*if(World::getWorld()->getTrack()->isAutoRescueEnabled() &&
!getKartAnimation() && fabs(getRoll())>60*DEGREE_TO_RAD &&
fabs(getSpeed())<3.0f )
{
new RescueAnimation(this, true);
}*/
// TODO: rescue the karts
// TODO: score a point
}
//-----------------------------------------------------------------------------
/** The battle is over if only one kart is left, or no player kart.
*/
bool SoccerWorld::isRaceOver()
{
// for tests : never over when we have a single player there :)
if (race_manager->getNumPlayers() < 2)
{
return false;
}
// TODO
return getCurrentNumKarts()==1 || getCurrentNumPlayers()==0;
} // isRaceOver
//-----------------------------------------------------------------------------
/** Called when the race finishes, i.e. after playing (if necessary) an
* end of race animation. It updates the time for all karts still racing,
* and then updates the ranks.
*/
void SoccerWorld::terminateRace()
{
m_can_score_points = false;
WorldWithRank::terminateRace();
} // terminateRace
//-----------------------------------------------------------------------------
/** Called then a battle is restarted.
*/
void SoccerWorld::restartRace()
{
WorldWithRank::restartRace();
m_can_score_points = true;
memset(m_team_goals, 0, sizeof(m_team_goals));
initKartList();
} // restartRace
//-----------------------------------------------------------------------------
/** Returns the data to display in the race gui.
*/
void SoccerWorld::getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info)
{
// TODO!!
/*
const unsigned int kart_amount = getNumKarts();
for(unsigned int i = 0; i < kart_amount ; i++)
{
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
// reset color
rank_info.lap = -1;
AbstractKart* kart = getKart(i);
switch(kart->getSoccerTeam())
{
case SOCCER_TEAM_BLUE:
rank_info.r = 0.0f;
rank_info.g = 0.0f;
rank_info.b = 0.7f;
break;
case SOCCER_TEAM_RED:
rank_info.r = 0.9f;
rank_info.g = 0.0f;
rank_info.b = 0.0f;
break;
default:
assert(false && "Soccer team not set to blue or red");
rank_info.r = 0.0f;
rank_info.g = 0.0f;
rank_info.b = 0.0f;
}
}
*/
} // getKartsDisplayInfo
//-----------------------------------------------------------------------------
/** Moves a kart to its rescue position.
* \param kart The kart that was rescued.
*/
void SoccerWorld::moveKartAfterRescue(AbstractKart* kart)
{
// find closest point to drop kart on
World *world = World::getWorld();
const int start_spots_amount = world->getTrack()->getNumberOfStartPositions();
assert(start_spots_amount > 0);
float largest_accumulated_distance_found = -1;
int furthest_id_found = -1;
const float kart_x = kart->getXYZ().getX();
const float kart_z = kart->getXYZ().getZ();
for(int n=0; n<start_spots_amount; n++)
{
// no need for the overhead to compute exact distance with sqrt(),
// so using the 'manhattan' heuristic which will do fine enough.
const btTransform &s = world->getTrack()->getStartTransform(n);
const Vec3 &v=s.getOrigin();
float accumulatedDistance = .0f;
bool spawnPointClear = true;
for(unsigned int k=0; k<getCurrentNumKarts(); k++)
{
const AbstractKart *currentKart = World::getWorld()->getKart(k);
const float currentKart_x = currentKart->getXYZ().getX();
const float currentKartk_z = currentKart->getXYZ().getZ();
if(kart_x!=currentKart_x && kart_z !=currentKartk_z)
{
float absDistance = fabs(currentKart_x - v.getX()) +
fabs(currentKartk_z - v.getZ());
if(absDistance < CLEAR_SPAWN_RANGE)
{
spawnPointClear = false;
break;
}
accumulatedDistance += absDistance;
}
}
if(largest_accumulated_distance_found < accumulatedDistance && spawnPointClear)
{
furthest_id_found = n;
largest_accumulated_distance_found = accumulatedDistance;
}
}
assert(furthest_id_found != -1);
const btTransform &s = world->getTrack()->getStartTransform(furthest_id_found);
const Vec3 &xyz = s.getOrigin();
kart->setXYZ(xyz);
kart->setRotation(s.getRotation());
//position kart from same height as in World::resetAllKarts
btTransform pos;
pos.setOrigin(kart->getXYZ()+btVector3(0, 0.5f*kart->getKartHeight(), 0.0f));
pos.setRotation( btQuaternion(btVector3(0.0f, 1.0f, 0.0f), 0 /* angle */) );
kart->getBody()->setCenterOfMassTransform(pos);
//project kart to surface of track
bool kart_over_ground = m_physics->projectKartDownwards(kart);
if (kart_over_ground)
{
//add vertical offset so that the kart starts off above the track
float vertical_offset = kart->getKartProperties()->getVertRescueOffset() *
kart->getKartHeight();
kart->getBody()->translate(btVector3(0, vertical_offset, 0));
}
else
{
fprintf(stderr, "WARNING: invalid position after rescue for kart %s on track %s.\n",
(kart->getIdent().c_str()), m_track->getIdent().c_str());
}
} // moveKartAfterRescue
/** Set position and team for the karts */
void SoccerWorld::initKartList()
{
const unsigned int kart_amount = m_karts.size();
// Set kart positions, ordering them by team
for(unsigned int n=0; n<kart_amount; n++)
{
m_karts[n]->setPosition(-1);
}
// TODO: remove
/*
const unsigned int kart_amount = m_karts.size();
int team_karts_amount[NB_SOCCER_TEAMS];
memset(team_karts_amount, 0, sizeof(team_karts_amount));
{
// Set the kart teams if they haven't been already set by the setup screen
// (happens when the setup screen is skipped, with 1 player)
SoccerTeam round_robin_team = SOCCER_TEAM_RED;
for(unsigned int n=0; n<kart_amount; n++)
{
if(m_karts[n]->getSoccerTeam() == SOCCER_TEAM_NONE)
m_karts[n]->setSoccerTeam(round_robin_team);
team_karts_amount[m_karts[n]->getSoccerTeam()]++;
round_robin_team = (round_robin_team==SOCCER_TEAM_RED ?
SOCCER_TEAM_BLUE : SOCCER_TEAM_RED);
}// next kart
}
// Compute start positions for each team
int team_cur_position[NB_SOCCER_TEAMS];
team_cur_position[0] = 1;
for(int i=1 ; i < (int)NB_SOCCER_TEAMS ; i++)
team_cur_position[i] = team_karts_amount[i-1] + team_cur_position[i-1];
// Set kart positions, ordering them by team
for(unsigned int n=0; n<kart_amount; n++)
{
SoccerTeam team = m_karts[n]->getSoccerTeam();
m_karts[n]->setPosition(team_cur_position[team]);
team_cur_position[team]++;
}// next kart
*/
}

View File

@@ -0,0 +1,80 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2004 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.
#ifndef SOCCER_WORLD_HPP
#define SOCCER_WORLD_HPP
#include "modes/world_with_rank.hpp"
#include "states_screens/race_gui_base.hpp"
#include "karts/abstract_kart.hpp"
#include <IMesh.h>
#include <string>
#define CLEAR_SPAWN_RANGE 5
class PhysicalObject;
/**
* \brief An implementation of World, to provide the soccer game mode
* \ingroup modes
*/
class SoccerWorld : public WorldWithRank
{
private:
/** Number of goals each team scored
*/
int m_team_goals[NB_SOCCER_TEAMS];
/** Whether or not goals can be scored (they are disabled when a point is scored
and re-enabled when the next game can be played)*/
bool m_can_score_points;
public:
SoccerWorld();
virtual ~SoccerWorld() {}
virtual void init();
// clock events
virtual bool isRaceOver();
virtual void terminateRace();
// overriding World methods
virtual void restartRace();
virtual bool useFastMusicNearEnd() const { return false; }
virtual void getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info);
virtual bool raceHasLaps(){ return false; }
virtual void moveKartAfterRescue(AbstractKart* kart);
virtual const std::string& getIdent() const;
virtual void update(float dt);
void onCheckGoalTriggered(bool first_goal);
private:
void initKartList();
}; // SoccerWorld
#endif

View File

@@ -22,6 +22,14 @@
#include <string>
#include <irrString.h>
enum SoccerTeam
{
SOCCER_TEAM_NONE=-1,
SOCCER_TEAM_RED=0,
SOCCER_TEAM_BLUE=1,
NB_SOCCER_TEAMS
};
class RemoteKartInfo
{
std::string m_kart_name;
@@ -29,12 +37,13 @@ class RemoteKartInfo
int m_local_player_id;
int m_global_player_id;
int m_host_id;
SoccerTeam m_soccer_team;
public:
RemoteKartInfo(int player_id, const std::string& kart_name,
const irr::core::stringw& user_name, int host_id)
: m_kart_name(kart_name), m_user_name(user_name),
m_local_player_id(player_id), m_host_id(host_id)
m_local_player_id(player_id), m_host_id(host_id), m_soccer_team(SOCCER_TEAM_NONE)
{};
RemoteKartInfo(const std::string& kart_name)
{m_kart_name=kart_name; m_user_name="";
@@ -46,11 +55,15 @@ public:
void setHostId(int id) { m_host_id = id; }
void setLocalPlayerId(int id) { m_local_player_id = id; }
void setGlobalPlayerId(int id) { m_global_player_id = id; }
void setSoccerTeam(SoccerTeam team) { m_soccer_team = team; }
int getHostId() const { return m_host_id; }
int getLocalPlayerId() const { return m_local_player_id; }
int getGlobalPlayerId() const { return m_global_player_id; }
const std::string& getKartName() const { return m_kart_name; }
const irr::core::stringw& getPlayerName() const { return m_user_name; }
const SoccerTeam getSoccerTeam() const {return m_soccer_team; }
bool operator<(const RemoteKartInfo& other) const
{
return ((m_host_id<other.m_host_id) ||

View File

@@ -40,6 +40,7 @@
#include "modes/tutorial_world.hpp"
#include "modes/world.hpp"
#include "modes/three_strikes_battle.hpp"
#include "modes/soccer_world.hpp"
#include "network/network_manager.hpp"
#include "states_screens/grand_prix_lose.hpp"
#include "states_screens/grand_prix_win.hpp"
@@ -144,6 +145,16 @@ void RaceManager::setLocalKartInfo(unsigned int player_id,
network_manager->getMyHostId());
} // setLocalKartInfo
//-----------------------------------------------------------------------------
/** Sets additional information for a player to indicate which soccer team it belong to
*/
void RaceManager::setLocalKartSoccerTeam(unsigned int player_id, SoccerTeam team)
{
assert(0<=player_id && player_id <m_local_player_karts.size());
m_local_player_karts[player_id].setSoccerTeam(team);
}
//-----------------------------------------------------------------------------
/** Returns a pointer to the kart which has a given GP rank.
* \param n The rank (1 to number of karts) to look for.
@@ -394,6 +405,8 @@ void RaceManager::startNextRace()
World::setWorld(new TutorialWorld());
else if(m_minor_mode==MINOR_MODE_3_STRIKES)
World::setWorld(new ThreeStrikesBattle());
else if(m_minor_mode==MINOR_MODE_SOCCER)
World::setWorld(new SoccerWorld());
else if(m_minor_mode==MINOR_MODE_OVERWORLD)
World::setWorld(new OverWorld());
else if(m_minor_mode==MINOR_MODE_CUTSCENE)

View File

@@ -43,6 +43,7 @@ static const std::string IDENT_TTRIAL ("STD_TIMETRIAL" );
static const std::string IDENT_FTL ("FOLLOW_LEADER" );
static const std::string IDENT_STRIKES ("BATTLE_3_STRIKES");
static const std::string IDENT_EASTER ("EASTER_EGG_HUNT");
static const std::string IDENT_SOCCER ("SOCCER" );
static const std::string IDENT_OVERWORLD("OVERWORLD" );
static const std::string IDENT_CUSTSCENE("CUTSCENE" );
@@ -111,8 +112,8 @@ public:
MINOR_MODE_TUTORIAL = LINEAR_RACE(4, false),
MINOR_MODE_3_STRIKES = BATTLE_ARENA(0),
MINOR_MODE_CUTSCENE = BATTLE_ARENA(1),
MINOR_MODE_SOCCER = BATTLE_ARENA(1),
MINOR_MODE_CUTSCENE = BATTLE_ARENA(2),
MINOR_MODE_EASTER_EGG = EASTER_EGG(0)
};
@@ -138,6 +139,7 @@ public:
case MINOR_MODE_FOLLOW_LEADER: return IDENT_FTL;
case MINOR_MODE_3_STRIKES: return IDENT_STRIKES;
case MINOR_MODE_EASTER_EGG: return IDENT_EASTER;
case MINOR_MODE_SOCCER: return IDENT_SOCCER;
default: assert(false);
return IDENT_STD; // stop compiler warning
}
@@ -156,6 +158,7 @@ public:
case MINOR_MODE_FOLLOW_LEADER: return "/gui/mode_ftl.png";
case MINOR_MODE_3_STRIKES: return "/gui/mode_3strikes.png";
case MINOR_MODE_EASTER_EGG: return "/gui/mode_easter.png";
case MINOR_MODE_SOCCER: return "/gui/mode_soccer.png";
default: assert(false); return NULL;
}
} // getIconOf
@@ -176,7 +179,10 @@ public:
case MINOR_MODE_FOLLOW_LEADER: return _("Follow the Leader");
//I18N: Game mode
case MINOR_MODE_3_STRIKES: return _("3 Strikes Battle");
//I18N: Game mode
case MINOR_MODE_EASTER_EGG: return _("Easter Egg Hunt");
//I18N: Game mode
case MINOR_MODE_SOCCER: return _("Soccer");
default: assert(false); return NULL;
}
}
@@ -191,6 +197,7 @@ public:
case MINOR_MODE_FOLLOW_LEADER: return true;
case MINOR_MODE_3_STRIKES: return false;
case MINOR_MODE_EASTER_EGG: return false;
case MINOR_MODE_SOCCER: return false;
default: assert(false); return NULL;
}
}
@@ -209,6 +216,7 @@ public:
else if (name==IDENT_FTL ) return MINOR_MODE_FOLLOW_LEADER;
else if (name==IDENT_STRIKES) return MINOR_MODE_3_STRIKES;
else if (name==IDENT_EASTER ) return MINOR_MODE_EASTER_EGG;
else if (name==IDENT_SOCCER) return MINOR_MODE_SOCCER;
assert(0);
return MINOR_MODE_NONE;
@@ -353,6 +361,10 @@ public:
*/
void setLocalKartInfo(unsigned int player_id, const std::string& kart);
/** Sets additional information for a player to indicate which soccer team it belong to
*/
void setLocalKartSoccerTeam(unsigned int player_id, SoccerTeam team);
/** Sets the number of local players playing on this computer (including
* split screen).
* \param n Number of local players.

View File

@@ -63,7 +63,8 @@ void ArenasScreen::beforeAddingWidget()
tabs->clearAllChildren();
const std::vector<std::string>& groups = track_manager->getAllArenaGroups();
bool soccer_mode = race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER;
const std::vector<std::string>& groups = track_manager->getAllArenaGroups(soccer_mode);
const int group_amount = groups.size();
if (group_amount > 1)
@@ -90,8 +91,15 @@ void ArenasScreen::beforeAddingWidget()
for (unsigned int n=0; n<track_manager->getNumberOfTracks(); n++) //iterate through tracks to find how many are arenas
{
Track* temp = track_manager->getTrack(n);
if (temp->isArena()){
num_of_arenas++;
if (soccer_mode)
{
if(temp->isSoccer())
num_of_arenas++;
}
else
{
if(temp->isArena())
num_of_arenas++;
}
}
@@ -130,6 +138,8 @@ void ArenasScreen::eventCallback(Widget* widget, const std::string& name, const
{
RibbonWidget* tabs = this->getWidget<RibbonWidget>("trackgroups");
assert( tabs != NULL );
bool soccer_mode = race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER;
std::vector<int> curr_group;
if (tabs->getSelectionIDString(PLAYER_ID_GAME_MASTER) == ALL_ARENA_GROUPS_ID)
@@ -137,7 +147,7 @@ void ArenasScreen::eventCallback(Widget* widget, const std::string& name, const
const std::vector<std::string>& groups = track_manager->getAllArenaGroups();
for (unsigned int i = 0; i < groups.size(); i++)
{
const std::vector<int>& tmp_group = track_manager->getArenasInGroup(groups[i]);
const std::vector<int>& tmp_group = track_manager->getArenasInGroup(groups[i], soccer_mode);
// Append to our main vector
curr_group.insert(curr_group.end(), tmp_group.begin(), tmp_group.end());
}
@@ -145,7 +155,7 @@ void ArenasScreen::eventCallback(Widget* widget, const std::string& name, const
else
{
curr_group = track_manager->getArenasInGroup(
tabs->getSelectionIDString(PLAYER_ID_GAME_MASTER) );
tabs->getSelectionIDString(PLAYER_ID_GAME_MASTER), soccer_mode );
}
RandomGenerator random;
@@ -206,6 +216,8 @@ void ArenasScreen::buildTrackList()
assert( tabs != NULL );
const std::string curr_group_name = tabs->getSelectionIDString(0);
bool soccer_mode = race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER;
if (curr_group_name == ALL_ARENA_GROUPS_ID)
{
const int trackAmount = track_manager->getNumberOfTracks();
@@ -213,7 +225,14 @@ void ArenasScreen::buildTrackList()
for (int n=0; n<trackAmount; n++)
{
Track* curr = track_manager->getTrack(n);
if (!curr->isArena()) continue;
if (soccer_mode)
{
if(!curr->isSoccer()) continue;
}
else
{
if(!curr->isArena()) continue;
}
if (unlock_manager->getCurrentSlot()->isLocked(curr->getIdent()))
{
@@ -230,13 +249,20 @@ void ArenasScreen::buildTrackList()
}
else
{
const std::vector<int>& currArenas = track_manager->getArenasInGroup(curr_group_name);
const std::vector<int>& currArenas = track_manager->getArenasInGroup(curr_group_name, soccer_mode);
const int trackAmount = currArenas.size();
for (int n=0; n<trackAmount; n++)
{
Track* curr = track_manager->getTrack(currArenas[n]);
if (!curr->isArena()) continue;
if (soccer_mode)
{
if(!curr->isSoccer()) continue;
}
else
{
if(!curr->isArena()) continue;
}
if (unlock_manager->getCurrentSlot()->isLocked(curr->getIdent()))
{

View File

@@ -605,7 +605,7 @@ public:
sfx_manager->quickSound( "wee" );
m_model_view->setRotateTo(30.0f, 150.0f);
m_model_view->setRotateTo(30.0f, 1.0f);
player_id_w *= 2;
player_name_w = 0;

View File

@@ -259,7 +259,7 @@ void MinimalRaceGUI::drawGlobalMiniMap()
{
World *world = World::getWorld();
// arenas currently don't have a map.
if(world->getTrack()->isArena()) return;
if(world->getTrack()->isArena() || world->getTrack()->isSoccer()) return;
const video::ITexture *mini_map = world->getTrack()->getMiniMap();

View File

@@ -269,7 +269,7 @@ void RaceGUI::drawGlobalMiniMap()
{
World *world = World::getWorld();
// arenas currently don't have a map.
if(world->getTrack()->isArena()) return;
if(world->getTrack()->isArena() || world->getTrack()->isSoccer()) return;
const video::ITexture *mini_map = world->getTrack()->getMiniMap();

View File

@@ -720,6 +720,11 @@ void RaceGUIBase::drawGlobalReadySetGo()
*/
void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
{
// For now, don't draw player icons when in soccer mode
const RaceManager::MinorRaceModeType minor_mode = race_manager->getMinorMode();
if(minor_mode == RaceManager::MINOR_MODE_SOCCER)
return;
int x_base = 10;
int y_base = 20;
unsigned int y_space = UserConfigParams::m_height - bottom_margin - y_base;
@@ -806,9 +811,9 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
//x,y is the target position
int lap = info.lap;
// In battle mode there is no distance along track etc.
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES ||
race_manager->getMinorMode()==RaceManager::MINOR_MODE_EASTER_EGG)
// In battle mode mode there is no distance along track etc.
if( minor_mode==RaceManager::MINOR_MODE_3_STRIKES ||
minor_mode==RaceManager::MINOR_MODE_EASTER_EGG)
{
x = x_base;
y = previous_y+ICON_PLAYER_WIDTH+2;

View File

@@ -295,7 +295,7 @@ void RaceGUIOverworld::drawGlobalMiniMap()
{
World *world = World::getWorld();
// arenas currently don't have a map.
if(world->getTrack()->isArena()) return;
if(world->getTrack()->isArena() || world->getTrack()->isSoccer()) return;
Track* track = world->getTrack();
const std::vector<OverworldChallenge>& challenges =

View File

@@ -22,18 +22,21 @@
#include "io/file_manager.hpp"
#include "race/race_manager.hpp"
#include "states_screens/arenas_screen.hpp"
#include "states_screens/soccer_setup_screen.hpp"
#include "states_screens/state_manager.hpp"
#include "states_screens/tracks_screen.hpp"
#include "utils/translation.hpp"
#include "states_screens/race_setup_screen.hpp"
#define ENABLE_SOCCER_MODE
const int CONFIG_CODE_NORMAL = 0;
const int CONFIG_CODE_TIMETRIAL = 1;
const int CONFIG_CODE_FTL = 2;
const int CONFIG_CODE_3STRIKES = 3;
const int CONFIG_CODE_EASTER = 4;
const int CONFIG_CODE_SOCCER = 5;
using namespace GUIEngine;
DEFINE_SCREEN_SINGLETON( RaceSetupScreen );
@@ -135,6 +138,17 @@ void RaceSetupScreen::eventCallback(Widget* widget, const std::string& name, con
race_manager->setNumKarts( race_manager->getNumLocalPlayers() ); // no AI karts;
StateManager::get()->pushScreen( TracksScreen::getInstance() );
}
else if (selectedMode == IDENT_SOCCER)
{
race_manager->setMinorMode(RaceManager::MINOR_MODE_SOCCER);
UserConfigParams::m_game_mode = CONFIG_CODE_SOCCER;
race_manager->setNumKarts( race_manager->getNumLocalPlayers() ); // no AI karts;
// 1 player -> no need to choose a team or determine when the match ends
if(race_manager->getNumLocalPlayers() <= 1)
StateManager::get()->pushScreen( ArenasScreen::getInstance() );
else
StateManager::get()->pushScreen( SoccerSetupScreen::getInstance() );
}
else if (selectedMode == "locked")
{
unlock_manager->playLockSound();
@@ -236,6 +250,16 @@ void RaceSetupScreen::init()
name4 += _("Hit others with weapons until they lose all their lives. (Only in multiplayer games)");
w2->addItem( name4, IDENT_STRIKES, RaceManager::getIconOf(RaceManager::MINOR_MODE_3_STRIKES));
}
#ifdef ENABLE_SOCCER_MODE
{
irr::core::stringw name5 = irr::core::stringw(
RaceManager::getNameOf(RaceManager::MINOR_MODE_SOCCER)) + L"\n";
name5 += _("Push the ball to the opposite cage to score goals. (Only in multiplayer games)");
w2->addItem( name5, IDENT_SOCCER, RaceManager::getIconOf(RaceManager::MINOR_MODE_SOCCER));
}
#endif
#ifdef ENABLE_EASTER_EGG_MODE
{
irr::core::stringw name1 = irr::core::stringw(
@@ -247,6 +271,7 @@ void RaceSetupScreen::init()
RaceManager::getIconOf(RaceManager::MINOR_MODE_EASTER_EGG));
}
#endif
w2->updateItemDisplay();
// restore saved game mode
@@ -267,6 +292,9 @@ void RaceSetupScreen::init()
case CONFIG_CODE_EASTER :
w2->setSelection(IDENT_EASTER, PLAYER_ID_GAME_MASTER, true);
break;
case CONFIG_CODE_SOCCER :
w2->setSelection(IDENT_SOCCER, PLAYER_ID_GAME_MASTER, true);
break;
}
m_mode_listener = new GameModeRibbonListener(this);

View File

@@ -0,0 +1,325 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Lionel Fuentes
//
// 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 "states_screens/soccer_setup_screen.hpp"
#include "input/device_manager.hpp"
#include "input/input_manager.hpp"
#include "states_screens/state_manager.hpp"
#include "states_screens/arenas_screen.hpp"
#include "guiengine/widgets/button_widget.hpp"
#include "guiengine/widgets/spinner_widget.hpp"
#include "guiengine/widgets/label_widget.hpp"
#include "guiengine/widgets/model_view_widget.hpp"
#include "guiengine/scalable_font.hpp"
#include "io/file_manager.hpp"
#include "karts/kart_properties_manager.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_model.hpp"
using namespace GUIEngine;
DEFINE_SCREEN_SINGLETON( SoccerSetupScreen );
#define KART_CONTINUOUS_ROTATION_SPEED 35.f
#define KART_CONFIRMATION_ROTATION_SPEED 4.f
#define KART_CONFIRMATION_TARGET_ANGLE 10.f
// -----------------------------------------------------------------------------
SoccerSetupScreen::SoccerSetupScreen() : Screen("soccer_setup.stkgui")
{
}
// -----------------------------------------------------------------------------
void SoccerSetupScreen::loadedFromFile()
{
}
// -----------------------------------------------------------------------------
void SoccerSetupScreen::eventCallback(Widget* widget, const std::string& name, const int playerID)
{
if(name == "continue")
{
StateManager::get()->pushScreen( ArenasScreen::getInstance() );
}
else if (name == "back")
{
StateManager::get()->escapePressed();
}
}
// -----------------------------------------------------------------------------
void SoccerSetupScreen::beforeAddingWidget()
{
Widget* central_div = getWidget<Widget>("central_div");
// Compute some dimensions
const core::dimension2d<u32> vs_size = GUIEngine::getTitleFont()->getDimension( L"VS" );
const int vs_width = (int)vs_size.Width;
const int vs_height = (int)vs_size.Height;
const int center_x = central_div->m_x + central_div->m_w/2;
const int center_y = central_div->m_y + central_div->m_h/2;
// Add "VS" label at the center of the rounded box
LabelWidget* label_vs = getWidget<LabelWidget>("vs");
label_vs->m_x = center_x - vs_width/2;
label_vs->m_y = center_y - vs_height/2;
label_vs->m_w = vs_width;
label_vs->m_h = vs_height;
// Add the 3D views for the karts
int nb_players = race_manager->getNumLocalPlayers();
for(int i=0 ; i < nb_players ; i++)
{
const RemoteKartInfo& kart_info = race_manager->getLocalKartInfo(i);
const std::string& kart_name = kart_info.getKartName();
const KartProperties* props = kart_properties_manager->getKart(kart_name);
const KartModel& kart_model = props->getMasterKartModel();
// Add the view
ModelViewWidget* kart_view = new ModelViewWidget();
kart_view->m_x = 0;
kart_view->m_y = 0;
kart_view->m_w = 200;
kart_view->m_h = 200; // these values will be overriden by updateKartViewsLayout() anyway
kart_view->clearModels();
// Add the kart model
kart_view->addModel( kart_model.getModel(), Vec3(0,0,0),
Vec3(35.0f, 35.0f, 35.0f),
kart_model.getBaseFrame() );
kart_view->addModel( kart_model.getWheelModel(0),
kart_model.getWheelGraphicsPosition(0) );
kart_view->addModel( kart_model.getWheelModel(1),
kart_model.getWheelGraphicsPosition(1) );
kart_view->addModel( kart_model.getWheelModel(2),
kart_model.getWheelGraphicsPosition(2) );
kart_view->addModel( kart_model.getWheelModel(3),
kart_model.getWheelGraphicsPosition(3) );
kart_view->setRotateContinuously( KART_CONTINUOUS_ROTATION_SPEED );
kart_view->update(0);
central_div->getChildren().push_back(kart_view);
// Record info about it for further update
KartViewInfo info;
info.view = kart_view;
info.confirmed = false;
info.local_player_id = i;
info.team = i&1 ? SOCCER_TEAM_BLUE : SOCCER_TEAM_RED;
m_kart_view_info.push_back(info);
}
// Update layout
updateKartViewsLayout();
}
// -----------------------------------------------------------------------------
void SoccerSetupScreen::init()
{
Screen::init();
// TODO: remember in config.xml the last number of goals
SpinnerWidget* goalamount = getWidget<SpinnerWidget>("goalamount");
goalamount->setValue(3);
// Set focus on "continue"
ButtonWidget* bt_continue = getWidget<ButtonWidget>("continue");
bt_continue->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
bt_continue->setDeactivated();
// We need players to be able to choose their teams
input_manager->getDeviceList()->setAssignMode(ASSIGN);
input_manager->setMasterPlayerOnly(false);
}
// -----------------------------------------------------------------------------
void SoccerSetupScreen::tearDown()
{
Widget* central_div = getWidget<Widget>("central_div");
// Remove all ModelViewWidgets we created manually
PtrVector<Widget>& children = central_div->getChildren();
for(int i = children.size()-1 ; i >= 0 ; i--)
{
if(children[i].getType() == WTYPE_MODEL_VIEW)
children.erase(i);
}
m_kart_view_info.clear();
Screen::tearDown();
}
// -----------------------------------------------------------------------------
GUIEngine::EventPropagation SoccerSetupScreen::filterActions( PlayerAction action,
int deviceID,
const unsigned int value,
Input::InputType type,
int playerId)
{
GUIEngine::EventPropagation result = EVENT_LET;
SoccerTeam team_switch = SOCCER_TEAM_NONE;
int nb_players = m_kart_view_info.size();
switch(action)
{
case PA_MENU_LEFT:
team_switch = SOCCER_TEAM_RED;
break;
case PA_MENU_RIGHT:
team_switch = SOCCER_TEAM_BLUE;
break;
case PA_MENU_SELECT:
{
// Confirm team selection
for(int i=0 ; i < nb_players ; i++)
{
if(m_kart_view_info[i].local_player_id == playerId)
{
m_kart_view_info[i].confirmed = true;
m_kart_view_info[i].view->setRotateTo( KART_CONFIRMATION_TARGET_ANGLE, KART_CONFIRMATION_ROTATION_SPEED );
result = EVENT_BLOCK;
break;
}
}
break;
}
case PA_MENU_CANCEL:
{
// Un-confirm team selection
// TODO: shouldn't trigger quitting the screen...
for(int i=0 ; i < nb_players ; i++)
{
if(m_kart_view_info[i].local_player_id == playerId)
{
m_kart_view_info[i].confirmed = false;
m_kart_view_info[i].view->setRotateContinuously( KART_CONTINUOUS_ROTATION_SPEED );
result = EVENT_BLOCK;
break;
}
}
break;
}
default:
break;
}
if(team_switch != SOCCER_TEAM_NONE) // A player wants to change its team?
{
// Find the corresponding kart view, update its team and update the layout
for(int i=0 ; i < nb_players ; i++)
{
if(m_kart_view_info[i].local_player_id == playerId)
{
// Player has already confirmed -> can't change
if(m_kart_view_info[i].confirmed)
break;
m_kart_view_info[i].team = team_switch;
updateKartViewsLayout();
result = EVENT_BLOCK;
break;
}
}
}
// Update "continue" button state
ButtonWidget* bt_continue = getWidget<ButtonWidget>("continue");
if(areAllKartsConfirmed())
{
bt_continue->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
bt_continue->setActivated();
for(int i=0 ; i < nb_players ; i++)
race_manager->setLocalKartSoccerTeam(m_kart_view_info[i].local_player_id,
m_kart_view_info[i].team);
}
else
bt_continue->setDeactivated();
return result;
}
bool SoccerSetupScreen::areAllKartsConfirmed() const
{
bool all_confirmed = true;
int nb_players = m_kart_view_info.size();
for(int i=0 ; i < nb_players ; i++)
{
if(!m_kart_view_info[i].confirmed)
{
all_confirmed = false;
break;
}
}
return all_confirmed;
}
void SoccerSetupScreen::updateKartViewsLayout()
{
Widget* central_div = getWidget<Widget>("central_div");
// Compute/get some dimensions
LabelWidget* label_vs = getWidget<LabelWidget>("vs");
const int vs_width = label_vs->m_w;
const int nb_columns = 2; // two karts maximum per column
const int kart_area_width = (central_div->m_w - vs_width) / 2; // size of one half of the screen
const int kart_view_size = kart_area_width/nb_columns; // Size (width and height) of a kart view
const int center_x = central_div->m_x + central_div->m_w/2;
const int center_y = central_div->m_y + central_div->m_h/2;
// Count the number of karts per team
int nb_players = m_kart_view_info.size();
int nb_karts_per_team[2] = {0,0};
for(int i=0 ; i < nb_players ; i++)
nb_karts_per_team[m_kart_view_info[i].team]++;
// - number of rows displayed for each team = ceil(nb_karts_per_team[i] / nb_columns)
const int nb_rows_per_team[2] = { (nb_karts_per_team[0] + nb_columns - 1) / nb_columns,
(nb_karts_per_team[1] + nb_columns - 1) / nb_columns};
// - where to start vertically
const int start_y[2] = {center_y - nb_rows_per_team[0] * kart_view_size / 2,
center_y - nb_rows_per_team[1] * kart_view_size / 2};
// - center of each half-screen
const int center_x_per_team[2] = { ( central_div->m_x + (center_x - vs_width) ) / 2,
( central_div->m_x+central_div->m_w + (center_x + vs_width) ) / 2,
};
// Update the layout of the 3D views for the karts
int cur_kart_per_team[2] = {0,0}; // counters
for(int i=0 ; i < nb_players ; i++)
{
const KartViewInfo& view_info = m_kart_view_info[i];
const SoccerTeam team = view_info.team;
// Compute the position
const int cur_row = cur_kart_per_team[team] / nb_columns;
const int pos_y = start_y[team] + cur_row*kart_view_size;
const int cur_col = cur_kart_per_team[team] % nb_columns;
int nb_karts_in_this_row = (nb_karts_per_team[team] - cur_row*nb_columns) % nb_columns;
if(nb_karts_in_this_row == 0)
nb_karts_in_this_row = nb_columns; // TODO: not sure of the computation here...
const int pos_x = center_x_per_team[team] + cur_col*kart_view_size - nb_karts_in_this_row*kart_view_size/2;
cur_kart_per_team[team]++;
// Move the view
view_info.view->move(pos_x, pos_y, kart_view_size, kart_view_size);
}
}

View File

@@ -0,0 +1,78 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Lionel Fuentes
//
// 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.
#ifndef HEADER_SOCCER_SETUP_SCREEN_HPP
#define HEADER_SOCCER_SETUP_SCREEN_HPP
#include "guiengine/screen.hpp"
#include "network/remote_kart_info.hpp"
namespace GUIEngine { class Widget; class LabelWidget; class ModelViewWidget; }
/**
* \brief Screen with soccer setup options
* \ingroup states_screens
*/
class SoccerSetupScreen : public GUIEngine::Screen, public GUIEngine::ScreenSingleton<SoccerSetupScreen>
{
friend class GUIEngine::ScreenSingleton<SoccerSetupScreen>;
SoccerSetupScreen();
struct KartViewInfo
{
GUIEngine::ModelViewWidget* view;
bool confirmed;
int local_player_id;
SoccerTeam team;
KartViewInfo() : view(NULL), confirmed(false), local_player_id(-1), team(SOCCER_TEAM_NONE) {}
};
AlignedArray<KartViewInfo> m_kart_view_info;
public:
/** \brief implement callback from parent class GUIEngine::Screen */
virtual void loadedFromFile() OVERRIDE;
/** \brief implement callback from parent class GUIEngine::Screen */
virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name,
const int playerID) OVERRIDE;
/** \brief implement callback from parent class GUIEngine::Screen */
virtual void beforeAddingWidget() OVERRIDE;
/** \brief implement callback from parent class GUIEngine::Screen */
virtual void init() OVERRIDE;
/** \brief implement callback from parent class GUIEngine::Screen */
virtual void tearDown() OVERRIDE;
/** \brief implement callback from parent class GUIEngine::Screen */
virtual GUIEngine::EventPropagation filterActions( PlayerAction action,
int deviceID,
const unsigned int value,
Input::InputType type,
int playerId) OVERRIDE;
private:
bool areAllKartsConfirmed() const;
void updateKartViewsLayout();
};
#endif // HEADER_SOCCER_SETUP_SCREEN_HPP

View File

@@ -289,7 +289,7 @@ void TracksScreen::buildTrackList()
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_EASTER_EGG
&& !curr->hasEasterEggs())
continue;
if (curr->isArena()) continue;
if (curr->isArena() || curr->isSoccer()) continue;
if (curr->isInternal()) continue;
if (unlock_manager->getCurrentSlot()->isLocked(curr->getIdent()))
@@ -320,6 +320,7 @@ void TracksScreen::buildTrackList()
&& !curr->hasEasterEggs())
continue;
if (curr->isArena()) continue;
if (curr->isSoccer()) continue;
if (curr->isInternal()) continue;
if (unlock_manager->getCurrentSlot()->isLocked(curr->getIdent()))

128
src/tracks/check_goal.cpp Normal file
View File

@@ -0,0 +1,128 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2012 Joerg Henrichs
//
// 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 "tracks/check_goal.hpp"
#include "io/xml_node.hpp"
#include "tracks/track.hpp"
#include "tracks/track_object_manager.hpp"
#include "modes/soccer_world.hpp"
#include <stdio.h>
/** Constructor for a check goal line.
* \param node XML node containing the parameters for this goal line.
* \param index Index of this check structure in the check manager.
*/
CheckGoal::CheckGoal(const XMLNode &node, unsigned int index)
: CheckStructure(node, index)
{
// Determine the team for this goal
m_first_goal = false;
node.get("first_goal", &m_first_goal);
Vec3 p1, p2;
node.get("p1", &p1);
node.get("p2", &p2);
m_line.setLine( core::vector2df(p1.getX(), p1.getZ()),
core::vector2df(p2.getX(), p2.getZ()) );
} // CheckGoal
// ----------------------------------------------------------------------------
/**
* Checks the soccer balls to see if they crossed the line and trigger the goal accordingly.
*/
void CheckGoal::update(float dt)
{
World *world = World::getWorld();
assert(world);
Track* track = world->getTrack();
assert(track);
TrackObjectManager* tom = track->getTrackObjectManager();
assert(tom);
PtrVector<TrackObject>& objects = tom->getObjects();
int ball_index = 0;
for(int i=0; i<objects.size(); i++)
{
TrackObject* obj = objects.get(i);
if(!obj->isSoccerBall())
continue;
const Vec3 &xyz = obj->getNode()->getPosition();
if(isTriggered(m_previous_position[ball_index], xyz, ball_index))
{
if(UserConfigParams::m_check_debug)
printf("CHECK: Goal check structure %d triggered for object %s.\n",
m_index, obj->getDebugName());
trigger(ball_index);
}
m_previous_position[ball_index] = xyz;
ball_index++;
}
}
// ----------------------------------------------------------------------------
/** Called when the check line is triggered. This function creates a cannon
* animation object and attaches it to the kart.
* \param kart_index The index of the kart that triggered the check line.
*/
void CheckGoal::trigger(unsigned int kart_index)
{
SoccerWorld* world = dynamic_cast<SoccerWorld*>(World::getWorld());
if(!world)
{
fprintf(stderr, "WARNING: no soccer world found, cannot count the points\n");
return;
}
world->onCheckGoalTriggered(m_first_goal);
} // CheckGoal
bool CheckGoal::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, int indx)
{
core::vector2df cross_point;
// Check if the finite line was actually crossed:
return m_line.intersectWith(core::line2df(old_pos.toIrrVector2d(),
new_pos.toIrrVector2d()),
cross_point);
} // isTriggered
void CheckGoal::reset(const Track &track)
{
const TrackObjectManager* tom = track.getTrackObjectManager();
assert(tom);
m_previous_position.clear();
const PtrVector<TrackObject>& objects = tom->getObjects();
for(int i=0; i<objects.size(); i++)
{
const TrackObject* obj = objects.get(i);
if(!obj->isSoccerBall())
continue;
const Vec3 &xyz = obj->getNode()->getPosition();
m_previous_position.push_back(xyz);
}
} // reset

55
src/tracks/check_goal.hpp Normal file
View File

@@ -0,0 +1,55 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2012 Joerg Henrichs
//
// 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.
#ifndef HEADER_CHECK_GOAL_HPP
#define HEADER_CHECK_GOAL_HPP
#include "tracks/check_structure.hpp"
#include "utils/cpp2011.h"
#include <line2d.h>
using namespace irr;
class CheckManager;
class XMLNode;
class Track;
/**
* \brief Implements a simple checkline that will score a point when the
* soccer ball crosses it.
*
* \ingroup tracks
*/
class CheckGoal : public CheckStructure
{
private:
/** Which team is this goal for? */
bool m_first_goal;
/** The line that is tested for being crossed. */
core::line2df m_line;
public:
CheckGoal(const XMLNode &node, unsigned int index);
virtual ~CheckGoal() {}
virtual void update(float dt) OVERRIDE;
virtual void trigger(unsigned int kart_index);
virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, int indx) OVERRIDE;
virtual void reset(const Track &track) OVERRIDE;
}; // CheckLine
#endif

View File

@@ -24,6 +24,7 @@
#include "io/xml_node.hpp"
#include "tracks/ambient_light_sphere.hpp"
#include "tracks/check_cannon.hpp"
#include "tracks/check_goal.hpp"
#include "tracks/check_lap.hpp"
#include "tracks/check_line.hpp"
#include "tracks/check_structure.hpp"
@@ -48,10 +49,14 @@ void CheckManager::load(const XMLNode &node)
{
m_all_checks.push_back(new CheckLap(*check_node, i));
}
else if(type=="cannon")
{
m_all_checks.push_back(new CheckCannon(*check_node, i));
}
else if(type=="cannon")
{
m_all_checks.push_back(new CheckCannon(*check_node, i));
}
else if(type=="goal")
{
m_all_checks.push_back(new CheckGoal(*check_node, i));
}
else if(type=="check-sphere")
{
AmbientLightSphere *cs = new AmbientLightSphere(*check_node,

View File

@@ -65,8 +65,8 @@ CheckStructure::CheckStructure(const XMLNode &node, unsigned int index)
== m_same_group.end())
m_same_group.push_back(m_index);
// As a default, only lap lines and cannons are activated
m_active_at_reset= m_check_type==CT_NEW_LAP || m_check_type==CT_CANNON;
// As a default, only lap lines, cannons and goals are activated
m_active_at_reset= m_check_type==CT_NEW_LAP || m_check_type==CT_CANNON || m_check_type==CT_GOAL;
node.get("active", &m_active_at_reset);
} // CheckStructure

View File

@@ -41,6 +41,7 @@ class CheckManager;
* CT_TOGGLE: Toggles the specified other check structures (active to
* inactive and vice versa.
* CT_CANNON: A check line that 'shoots' the kart to a specified location.
* CT_GOAL: A goal line in soccer mode.
* Each check structure can be active or inactive. Only lap counters are
* initialised to be active, all other check structures are inactive.
*
@@ -54,7 +55,8 @@ public:
* the state that check structure is in)
* TOGGLE: Switches (inverts) the state of another check structure.
* NEW_LAP: On crossing a new lap is counted.
* CANNON: Causes the kart to be shot to a specified point.
* CANNON: Causes the kart to be shot to a specified point.
* GOAL: Causes a point to be scored when a soccer ball crosses its line
* AMBIENT_SPHERE: Modifies the ambient color.
* A combination of an activate and new_lap line are used to
* avoid shortcuts: a new_lap line is deactivated after crossing it, and
@@ -62,7 +64,7 @@ public:
* enabling you to count the lap again.
*/
enum CheckType {CT_NEW_LAP, CT_ACTIVATE, CT_TOGGLE, CT_CANNON,
CT_AMBIENT_SPHERE};
CT_GOAL, CT_AMBIENT_SPHERE};
protected:
/** Stores the previous position of all karts. This is needed to detect
@@ -75,13 +77,13 @@ protected:
/** True if this check structure should be activated at a reset. */
bool m_active_at_reset;
private:
/** The type of this checkline. */
CheckType m_check_type;
/** Stores the index of this check structure. This is only used for
* debugging (use --check-debug option). */
unsigned int m_index;
private:
/** The type of this checkline. */
CheckType m_check_type;
/** Contains the indices of the corresponding check structures that
* get their state changed (activated or switched). */

View File

@@ -99,6 +99,7 @@ Track::Track(const std::string &filename)
m_reverse_available = false;
m_is_arena = false;
m_has_easter_eggs = false;
m_is_soccer = false;
m_is_cutscene = false;
m_camera_far = 1000.0f;
m_mini_map = NULL;
@@ -328,6 +329,7 @@ void Track::loadTrackInfo()
getMusicInformation(filenames, m_music);
root->get("screenshot", &m_screenshot);
root->get("gravity", &m_gravity);
root->get("soccer", &m_is_soccer);
root->get("arena", &m_is_arena);
root->get("cutscene", &m_is_cutscene);
root->get("groups", &m_groups);
@@ -335,13 +337,14 @@ void Track::loadTrackInfo()
root->get("reverse", &m_reverse_available);
root->get("push-back", &m_enable_push_back);
// Make the default for auto-rescue in battle mode to be false
if(m_is_arena)
// Make the default for auto-rescue in battle mode and soccer mode to be false
if(m_is_arena || m_is_soccer)
m_enable_auto_rescue = false;
root->get("auto-rescue", & m_enable_auto_rescue);
root->get("smooth-normals", &m_smooth_normals);
// Reverse is meaningless in arena
m_reverse_available = !m_is_arena && m_reverse_available;
if(m_is_arena || m_is_soccer)
m_reverse_available = false;
for(unsigned int i=0; i<root->getNumNodes(); i++)
@@ -1345,7 +1348,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
// the race gui was created. The race gui is needed since it stores
// the information about the size of the texture to render the mini
// map to.
if (!m_is_arena && !m_is_cutscene) loadQuadGraph(mode_id, reverse_track);
if (!m_is_arena && !m_is_soccer && !m_is_cutscene) loadQuadGraph(mode_id, reverse_track);
ItemManager::create();
@@ -1364,7 +1367,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
default_start->get("upwards-distance", &upwards_distance );
default_start->get("karts-per-row", &karts_per_row );
}
if(!m_is_arena && !m_is_cutscene)
if(!m_is_arena && !m_is_soccer && !m_is_cutscene)
{
m_start_transforms.resize(race_manager->getNumberOfKarts());
QuadGraph::get()->setDefaultStartPositions(&m_start_transforms,

View File

@@ -227,9 +227,10 @@ private:
Vec3 m_aabb_max;
/** True if this track is an arena. */
bool m_is_arena;
/** True if this track has easter eggs. */
bool m_has_easter_eggs;
/** True if this track is a soccer arena. */
bool m_is_soccer;
bool m_is_cutscene;
@@ -413,6 +414,11 @@ public:
// ------------------------------------------------------------------------
/** Returns true if this track has easter eggs. */
bool hasEasterEggs() const { return m_has_easter_eggs; }
bool isSoccer () const { return m_is_soccer; }
// ------------------------------------------------------------------------
void loadTrackModel (World* parent,
bool reverse_track = false,
unsigned int mode_id=0);
// ------------------------------------------------------------------------
void addMusic (MusicInformation* mi)
{m_music.push_back(mi); }
@@ -533,7 +539,7 @@ public:
/** Returns true if the normals of this track can be smoothed. */
bool smoothNormals() const { return m_smooth_normals; }
// ------------------------------------------------------------------------
TrackObjectManager* getTrackObjectManager() {return m_track_object_manager;}
TrackObjectManager* getTrackObjectManager() const {return m_track_object_manager;}
/** Get list of challenges placed on that world. Works only for overworld. */
const std::vector<OverworldChallenge>& getChallengeList() const

View File

@@ -128,7 +128,9 @@ void TrackManager::loadTrackList()
m_track_group_names.clear();
m_track_groups.clear();
m_arena_group_names.clear();
m_soccer_arena_group_names.clear();
m_arena_groups.clear();
m_soccer_arena_groups.clear();
m_track_avail.clear();
m_tracks.clear();
@@ -223,11 +225,16 @@ void TrackManager::removeTrack(const std::string &ident)
int index = it - m_tracks.begin();
// Remove the track from all groups it belongs to
Group2Indices &group_2_indices = track->isArena() ? m_arena_groups
: m_track_groups;
std::vector<std::string> &group_names = track->isArena()
? m_arena_group_names
: m_track_group_names;
Group2Indices &group_2_indices =
(track->isArena() ? m_arena_groups :
(track->isSoccer() ? m_soccer_arena_groups :
m_track_groups));
std::vector<std::string> &group_names =
(track->isArena() ? m_arena_group_names :
(track->isSoccer() ? m_soccer_arena_group_names :
m_track_group_names));
const std::vector<std::string>& groups=track->getGroups();
for(unsigned int i=0; i<groups.size(); i++)
{
@@ -253,9 +260,11 @@ void TrackManager::removeTrack(const std::string &ident)
// Adjust all indices of tracks with an index number higher than
// the removed track, since they have been moved down. This must
// be done for all tracks and all arenas
for(unsigned int i=0; i<2; i++) // i=0: arenas, i=1: tracks
for(unsigned int i=0; i<2; i++) // i=0: soccer arenas, i=0: arenas, i=1: tracks
{
Group2Indices &g2i = i==0 ? m_arena_groups : m_track_groups;
Group2Indices &g2i = (i==0 ? m_soccer_arena_groups :
(i==1 ? m_arena_groups :
m_track_groups));
Group2Indices::iterator j;
for(j=g2i.begin(); j!=g2i.end(); j++)
{
@@ -280,11 +289,15 @@ void TrackManager::updateGroups(const Track* track)
const std::vector<std::string>& new_groups = track->getGroups();
Group2Indices &group_2_indices = track->isArena() ? m_arena_groups
: m_track_groups;
std::vector<std::string> &group_names = track->isArena()
? m_arena_group_names
: m_track_group_names;
Group2Indices &group_2_indices =
(track->isArena() ? m_arena_groups :
(track->isSoccer() ? m_soccer_arena_groups :
m_track_groups));
std::vector<std::string> &group_names =
(track->isArena() ? m_arena_group_names :
(track->isSoccer() ? m_soccer_arena_group_names :
m_track_group_names));
const unsigned int groups_amount = new_groups.size();
for(unsigned int i=0; i<groups_amount; i++)

View File

@@ -50,6 +50,9 @@ private:
/** List of all arena groups. */
Group2Indices m_arena_groups;
/** List of all soccer arena groups. */
Group2Indices m_soccer_arena_groups;
/** List of all groups (for both normal tracks and arenas) */
//std::vector<std::string> m_all_group_names;
@@ -58,6 +61,9 @@ private:
/** List of the names of all groups containing arenas */
std::vector<std::string> m_arena_group_names;
/** List of the names of all groups containing soccer arenas */
std::vector<std::string> m_soccer_arena_group_names;
/** Flag if this track is available or not. Tracks are set unavailable
* if they are not available on all clients (applies only to network mode)
@@ -99,11 +105,12 @@ public:
} // getAllTrackGroups
// ------------------------------------------------------------------------
/** \brief Returns a list of the names of all used arena groups. */
const std::vector<std::string>& getAllArenaGroups() const
const std::vector<std::string>&
getAllArenaGroups(bool soccer_arena=false) const
{
return m_arena_group_names;
} // getAllArenaGRoups
// ------------------------------------------------------------------------
return soccer_arena ? m_soccer_arena_group_names : m_arena_group_names;
} // getAllArenaGroups
// ------------------------------------------------------------------------
/** Returns the number of tracks. */
size_t getNumberOfTracks() const { return m_tracks.size(); }
// ------------------------------------------------------------------------
@@ -124,11 +131,12 @@ public:
// ------------------------------------------------------------------------
/** Returns a list of all arenas in a given group.
* \param g Name of the group. */
const std::vector<int>& getArenasInGroup(const std::string& g)
const std::vector<int>&
getArenasInGroup(const std::string& g, bool soccer_arena=false)
{
return m_arena_groups[g];
// getArenasInGroup}
}
return soccer_arena ? m_soccer_arena_groups[g] : m_arena_groups[g];
} // getArenasInGroup
}; // TrackManager
extern TrackManager* track_manager;

View File

@@ -75,6 +75,9 @@ TrackObject::TrackObject(const XMLNode &xml_node)
xml_node.get("interaction", &m_interaction);
xml_node.get("lod_group", &m_lod_group);
m_soccer_ball = false;
xml_node.get("soccer_ball", &m_soccer_ball);
std::string type;
xml_node.get("type", &type );

View File

@@ -104,6 +104,8 @@ protected:
LODNode* m_lod_emitter_node;
bool m_soccer_ball;
public:
TrackObject(const XMLNode &xml_node);
TrackObject();
@@ -133,11 +135,12 @@ public:
}
m_node = node;
if (node->getType() == irr::scene::ESNT_LOD_NODE)
if (m_node->getType() == irr::scene::ESNT_LOD_NODE)
{
((LODNode*)node)->setNodesPosition(m_init_xyz);
((LODNode*)node)->setNodesRotation(m_init_hpr);
((LODNode*)node)->setNodesScale(m_init_scale);
((LODNode*)m_node)->setNodesPosition(m_init_xyz);
((LODNode*)m_node)->setNodesRotation(m_init_hpr);
((LODNode*)m_node)->setNodesScale(m_init_scale);
}
else
{
@@ -151,6 +154,8 @@ public:
const std::string& getType() const { return m_type; }
bool isSoccerBall() const { return m_soccer_ball; }
/** Currently used for sound effects only, in cutscenes only atm */
const std::string& getTriggerCondition() const { return m_trigger_condition; }