Initial work on FFA in network

This commit is contained in:
Benau 2018-08-13 00:59:20 +08:00
parent c8c0e599db
commit 64595a7b18
25 changed files with 531 additions and 34 deletions

View File

@ -1,6 +1,8 @@
## SuperTuxKart 0.9.4
* Networking game for normal race, time trial, free for all, capture the flag and soccer
* Better random item distribution for various numbers of karts
* Improved powerup handling in AI
* New tracks Las Dunas Soccer by samuncle
## SuperTuxKart 0.9.3
* Reduced RAM and VRAM usage, reducing load times by Auria and Benau

View File

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

View File

@ -574,7 +574,8 @@ void Flyable::explode(AbstractKart *kart_hit, PhysicalObject *object,
ExplosionAnimation::create(kart, getXYZ(), kart==kart_hit);
if(kart==kart_hit && Track::getCurrentTrack()->isArena())
{
world->kartHit(kart->getWorldKartId());
world->kartHit(kart->getWorldKartId(),
m_owner->getWorldKartId());
}
}
}

View File

@ -377,7 +377,8 @@ void Swatter::squashThingsAround()
if (m_closest_kart->isSquashed())
{
// The kart may not be squashed if it was protected by a bubblegum shield
World::getWorld()->kartHit(m_closest_kart->getWorldKartId());
World::getWorld()->kartHit(m_closest_kart->getWorldKartId(),
m_kart->getWorldKartId());
}
// TODO: squash items

View File

@ -61,13 +61,10 @@
#include "karts/rescue_animation.hpp"
#include "karts/skidding.hpp"
#include "main_loop.hpp"
#include "modes/overworld.hpp"
#include "modes/soccer_world.hpp"
#include "modes/world.hpp"
#include "modes/capture_the_flag.hpp"
#include "modes/linear_world.hpp"
#include "modes/overworld.hpp"
#include "modes/soccer_world.hpp"
#include "modes/world.hpp"
#include "network/network_config.hpp"
#include "network/race_event_manager.hpp"
#include "network/rewind_manager.hpp"
@ -1026,11 +1023,17 @@ void Kart::setRaceResult()
}
}
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER ||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_BATTLE)
race_manager->getMajorMode() == RaceManager::MAJOR_MODE_3_STRIKES)
{
// the kart wins if it isn't eliminated
m_race_result = !this->isEliminated();
}
else if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_FREE_FOR_ALL)
{
// the top kart wins
FreeForAll* ffa = dynamic_cast<FreeForAll*>(World::getWorld());
m_race_result = ffa->getKartAtPosition(1) == this;
}
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
{
SoccerWorld* sw = dynamic_cast<SoccerWorld*>(World::getWorld());

View File

@ -0,0 +1,34 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2018 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/capture_the_flag.hpp"
#include "network/network_config.hpp"
#include <algorithm>
//-----------------------------------------------------------------------------
/** Constructor. Sets up the clock mode etc.
*/
CaptureTheFlag::CaptureTheFlag() : FreeForAll()
{
} // CaptureTheFlag
//-----------------------------------------------------------------------------
CaptureTheFlag::~CaptureTheFlag()
{
} // ~CaptureTheFlag

View File

@ -0,0 +1,36 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2018 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 CAPTURE_THE_FLAG_HPP
#define CAPTURE_THE_FLAG_HPP
#include "modes/free_for_all.hpp"
#include <vector>
#include <string>
class CaptureTheFlag : public FreeForAll
{
private:
public:
// ------------------------------------------------------------------------
CaptureTheFlag();
// ------------------------------------------------------------------------
virtual ~CaptureTheFlag();
}; // CaptureTheFlag
#endif

189
src/modes/free_for_all.cpp Normal file
View File

@ -0,0 +1,189 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2018 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/free_for_all.hpp"
#include "karts/kart.hpp"
#include "karts/controller/controller.hpp"
#include "network/network_config.hpp"
#include "network/network_string.hpp"
#include "network/protocols/game_events_protocol.hpp"
#include "network/stk_host.hpp"
#include <algorithm>
#include <utility>
//-----------------------------------------------------------------------------
/** Constructor. Sets up the clock mode etc.
*/
FreeForAll::FreeForAll() : WorldWithRank()
{
if (race_manager->hasTimeTarget())
{
WorldStatus::setClockMode(WorldStatus::CLOCK_COUNTDOWN,
race_manager->getTimeTarget());
}
else
{
WorldStatus::setClockMode(CLOCK_CHRONO);
}
} // FreeForAll
//-----------------------------------------------------------------------------
FreeForAll::~FreeForAll()
{
} // ~FreeForAll
//-----------------------------------------------------------------------------
void FreeForAll::init()
{
WorldWithRank::init();
m_display_rank = false;
m_count_down_reached_zero = false;
} // init
//-----------------------------------------------------------------------------
/** Called when a battle is restarted.
*/
void FreeForAll::reset()
{
WorldWithRank::reset();
if (race_manager->hasTimeTarget())
{
WorldStatus::setClockMode(WorldStatus::CLOCK_COUNTDOWN,
race_manager->getTimeTarget());
}
else
{
WorldStatus::setClockMode(CLOCK_CHRONO);
}
m_scores.clear();
m_scores.resize(m_karts.size(), 0);
} // reset
//-----------------------------------------------------------------------------
/** Called when the match time ends.
*/
void FreeForAll::countdownReachedZero()
{
// Prevent negative time in network soccer when finishing
m_time_ticks = 0;
m_time = 0.0f;
m_count_down_reached_zero = true;
} // countdownReachedZero
//-----------------------------------------------------------------------------
/** Called when a kart is hit.
* \param kart_id The world kart id of the kart that was hit.
* \param hitter The world kart id of the kart who hit(-1 if none).
*/
void FreeForAll::kartHit(int kart_id, int hitter)
{
if (NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isClient())
return;
if (isRaceOver()) return;
NetworkString p(PROTOCOL_GAME_EVENTS);
p.setSynchronous(true);
p.addUInt8(GameEventsProtocol::GE_BATTLE_KART_SCORE);
if (kart_id == hitter || hitter == -1)
p.addUInt8((uint8_t)kart_id).addUInt32(--m_scores[kart_id]);
else
p.addUInt8((uint8_t)hitter).addUInt32(++m_scores[hitter]);
STKHost::get()->sendPacketToAllPeers(&p, true);
} // kartHit
//-----------------------------------------------------------------------------
void FreeForAll::setKartScoreFromServer(NetworkString& ns)
{
int kart_id = ns.getUInt8();
int score = ns.getUInt32();
m_scores.at(kart_id) = score;
} // setKartScoreFromServer
//-----------------------------------------------------------------------------
/** Returns the internal identifier for this race.
*/
const std::string& FreeForAll::getIdent() const
{
return IDENT_STRIKES;
} // getIdent
// ------------------------------------------------------------------------
void FreeForAll::update(int ticks)
{
WorldWithRank::update(ticks);
WorldWithRank::updateTrack(ticks);
std::vector<std::pair<int, int> > ranks;
for (unsigned i = 0; i < m_scores.size(); i++)
ranks.emplace_back(i, m_scores[i]);
std::sort(ranks.begin(), ranks.end(),
[](const std::pair<int, int>& a, const std::pair<int, int>& b)
{
return a.second > b.second;
});
beginSetKartPositions();
for (unsigned i = 0; i < ranks.size(); i++)
setKartPosition(ranks[i].first, i + 1);
endSetKartPositions();
} // update
//-----------------------------------------------------------------------------
/** The battle is over if only one kart is left, or no player kart.
*/
bool FreeForAll::isRaceOver()
{
if (NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isClient())
return false;
if (!getKartAtPosition(1))
return false;
int top_id = getKartAtPosition(1)->getWorldKartId();
return (m_count_down_reached_zero && race_manager->hasTimeTarget()) ||
m_scores[top_id] >= race_manager->getHitCaptureLimit();
} // isRaceOver
//-----------------------------------------------------------------------------
/** Returns the data to display in the race gui.
*/
void FreeForAll::getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info)
{
const unsigned int kart_amount = getNumKarts();
for (unsigned int i = 0; i < kart_amount ; i++)
{
RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
rank_info.lap = -1;
rank_info.m_outlined_font = true;
rank_info.m_text = m_karts[i]->getController()->getName() + L" (" +
StringUtils::toWString(m_scores[i]) + L")";
}
} // getKartsDisplayInfo
//-----------------------------------------------------------------------------
void FreeForAll::terminateRace()
{
const unsigned int kart_amount = getNumKarts();
for (unsigned int i = 0; i < kart_amount ; i++)
{
m_karts[i]->finishedRace(0.0f, true/*from_server*/);
} // i<kart_amount
WorldWithRank::terminateRace();
} // terminateRace

View File

@ -0,0 +1,68 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2018 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 FREE_FOR_ALL_HPP
#define FREE_FOR_ALL_HPP
#include "modes/world_with_rank.hpp"
#include "states_screens/race_gui_base.hpp"
#include <vector>
class NetworkString;
class FreeForAll : public WorldWithRank
{
private:
bool m_count_down_reached_zero;
std::vector<int> m_scores;
public:
// ------------------------------------------------------------------------
FreeForAll();
// ------------------------------------------------------------------------
virtual ~FreeForAll();
// ------------------------------------------------------------------------
virtual void init() OVERRIDE;
// ------------------------------------------------------------------------
virtual bool isRaceOver() OVERRIDE;
// ------------------------------------------------------------------------
virtual void reset() OVERRIDE;
// ------------------------------------------------------------------------
virtual void getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
// ------------------------------------------------------------------------
virtual bool raceHasLaps() OVERRIDE { return false; }
// ------------------------------------------------------------------------
virtual const std::string& getIdent() const OVERRIDE;
// ------------------------------------------------------------------------
virtual void kartHit(int kart_id, int hitter = -1) OVERRIDE;
// ------------------------------------------------------------------------
virtual void update(int ticks) OVERRIDE;
// ------------------------------------------------------------------------
virtual void countdownReachedZero() OVERRIDE;
// ------------------------------------------------------------------------
virtual void terminateRace() OVERRIDE;
// ------------------------------------------------------------------------
void setKartScoreFromServer(NetworkString& ns);
// ------------------------------------------------------------------------
int getKartScore(int kart_id) const { return m_scores.at(kart_id); }
}; // FreeForAll
#endif

View File

@ -207,8 +207,9 @@ void ThreeStrikesBattle::kartAdded(AbstractKart* kart, scene::ISceneNode* node)
//-----------------------------------------------------------------------------
/** Called when a kart is hit.
* \param kart_id The world kart id of the kart that was hit.
* \param hitter The world kart id of the kart who hit(-1 if none).
*/
void ThreeStrikesBattle::kartHit(const unsigned int kart_id)
void ThreeStrikesBattle::kartHit(int kart_id, int hitter)
{
if (isRaceOver()) return;
@ -221,7 +222,7 @@ void ThreeStrikesBattle::kartHit(const unsigned int kart_id)
return;
}
assert(kart_id < m_karts.size());
assert(kart_id < (int)m_karts.size());
// make kart lose a life, ignore if in profiling mode
if (!UserConfigParams::m_arena_ai_stats)
m_kart_info[kart_id].m_lives--;
@ -256,7 +257,7 @@ void ThreeStrikesBattle::kartHit(const unsigned int kart_id)
{
AbstractKart * const kart = getKart(i);
if(kart->isEliminated() || kart->hasFinishedRace() ||
kart->getWorldKartId()==kart_id) continue;
kart->getWorldKartId()==(unsigned)kart_id) continue;
if(m_kart_info[i].m_lives > max_lives)
{
leader = kart;
@ -270,7 +271,7 @@ void ThreeStrikesBattle::kartHit(const unsigned int kart_id)
for(unsigned int i=0; i<Camera::getNumCameras(); i++)
{
Camera *camera = Camera::getCamera(i);
if(camera->getKart()->getWorldKartId()==kart_id)
if(camera->getKart()->getWorldKartId()==(unsigned)kart_id)
{
camera->setMode(Camera::CM_NORMAL);
camera->setKart(leader);

View File

@ -111,7 +111,7 @@ public:
// ------------------------------------------------------------------------
virtual const std::string& getIdent() const OVERRIDE;
// ------------------------------------------------------------------------
virtual void kartHit(const unsigned int kart_id) OVERRIDE;
virtual void kartHit(int kart_id, int hitter = -1) OVERRIDE;
// ------------------------------------------------------------------------
virtual void update(int ticks) OVERRIDE;
// ------------------------------------------------------------------------

View File

@ -268,7 +268,7 @@ public:
virtual void newLap(unsigned int kart_index) {}
// ------------------------------------------------------------------------
/** Called when a kart was hit by a projectile. */
virtual void kartHit(const unsigned int kart_id) {};
virtual void kartHit(int kart_id, int hitter = -1) {};
// ------------------------------------------------------------------------
virtual void onMouseClick(int x, int y) {};

View File

@ -100,8 +100,14 @@ void GameSetup::loadWorld()
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER ||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_BATTLE)
{
const bool is_ctf = race_manager->getMajorMode() ==
RaceManager::MAJOR_MODE_CAPTURE_THE_FLAG;
bool prev_val = UserConfigParams::m_random_arena_item;
UserConfigParams::m_random_arena_item = m_reverse;
if (is_ctf)
UserConfigParams::m_random_arena_item = false;
else
UserConfigParams::m_random_arena_item = m_reverse;
race_manager->setReverseTrack(false);
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
{
@ -110,6 +116,11 @@ void GameSetup::loadWorld()
else
race_manager->setTimeTarget((float)m_laps * 60.0f);
}
else
{
race_manager->setHitCaptureTime(m_hit_capture_limit,
m_battle_time_limit);
}
race_manager->startSingleRace(m_tracks.back(), -1,
false/*from_overworld*/);
UserConfigParams::m_random_arena_item = prev_val;

View File

@ -54,6 +54,10 @@ private:
int m_extra_server_info;
int m_hit_capture_limit;
float m_battle_time_limit;
public:
// ------------------------------------------------------------------------
GameSetup()
@ -114,6 +118,8 @@ public:
m_tracks.clear();
m_laps = 0;
m_reverse = false;
m_hit_capture_limit = 0;
m_battle_time_limit = 0.0f;
}
// ------------------------------------------------------------------------
void setGrandPrixTrack(int tracks_no) { m_extra_server_info = tracks_no; }
@ -159,6 +165,12 @@ public:
void sortPlayersForGrandPrix();
// ------------------------------------------------------------------------
void sortPlayersForSoccer();
// ------------------------------------------------------------------------
void setHitCaptureTime(int hc, float time)
{
m_hit_capture_limit = hc;
m_battle_time_limit = time;
}
};

View File

@ -239,6 +239,12 @@ void ClientLobby::addAllPlayers(Event* event)
}
uint32_t random_seed = data.getUInt32();
ItemManager::updateRandomSeed(random_seed);
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_BATTLE)
{
int hit_capture_limit = data.getUInt32();
float time_limit = data.getFloat();
m_game_setup->setHitCaptureTime(hit_capture_limit, time_limit);
}
configRemoteKart(players);
loadWorld();
// Switch to assign mode in case a player hasn't chosen any karts

View File

@ -1,6 +1,7 @@
#include "network/protocols/game_events_protocol.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/free_for_all.hpp"
#include "modes/soccer_world.hpp"
#include "network/event.hpp"
#include "network/game_setup.hpp"
@ -44,6 +45,7 @@ bool GameEventsProtocol::notifyEvent(Event* event)
return true;
}
uint8_t type = data.getUInt8();
FreeForAll* ffa = dynamic_cast<FreeForAll*>(World::getWorld());
SoccerWorld* sw = dynamic_cast<SoccerWorld*>(World::getWorld());
switch (type)
{
@ -65,6 +67,13 @@ bool GameEventsProtocol::notifyEvent(Event* event)
sw->handlePlayerGoalFromServer(data);
break;
}
case GE_BATTLE_KART_SCORE:
{
if (!ffa)
throw std::invalid_argument("No free for all world");
ffa->setKartScoreFromServer(data);
break;
}
default:
Log::warn("GameEventsProtocol", "Unkown message type.");
break;

View File

@ -14,7 +14,8 @@ public:
GE_KART_FINISHED_RACE = 1,
GE_PLAYER_DISCONNECT = 2,
GE_RESET_BALL = 3,
GE_PLAYER_GOAL = 4
GE_PLAYER_GOAL = 4,
GE_BATTLE_KART_SCORE = 5
}; // GameEventType
private:
void eliminatePlayer(const NetworkString &ns);

View File

@ -250,7 +250,8 @@ void ServerLobby::handleChat(Event* event)
//-----------------------------------------------------------------------------
void ServerLobby::changeTeam(Event* event)
{
if (!NetworkConfig::get()->hasTeamChoosing())
if (!NetworkConfig::get()->hasTeamChoosing() ||
!race_manager->teamEnabled())
return;
if (!checkDataSize(event, 1)) return;
NetworkString& data = event->data();
@ -508,6 +509,12 @@ void ServerLobby::asynchronousUpdate()
uint32_t random_seed = (uint32_t)StkTime::getTimeSinceEpoch();
ItemManager::updateRandomSeed(random_seed);
load_world->addUInt32(random_seed);
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_BATTLE)
{
auto hcl = getHitCaptureLimit((float)players.size());
load_world->addUInt32(hcl.first).addFloat(hcl.second);
m_game_setup->setHitCaptureTime(hcl.first, hcl.second);
}
configRemoteKart(players);
// Reset for next state usage
@ -798,11 +805,12 @@ void ServerLobby::startSelection(const Event *event)
}
}
if (NetworkConfig::get()->hasTeamChoosing())
auto players = m_game_setup->getConnectedPlayers();
const unsigned player_count = players.size();
if (NetworkConfig::get()->hasTeamChoosing() && race_manager->teamEnabled())
{
int red_count = 0;
int blue_count = 0;
auto players = m_game_setup->getConnectedPlayers();
for (auto& player : players)
{
if (player->getTeam() == SOCCER_TEAM_RED)
@ -812,7 +820,7 @@ void ServerLobby::startSelection(const Event *event)
if (red_count != 0 && blue_count != 0)
break;
}
if ((red_count == 0 || blue_count == 0) && players.size() != 1)
if ((red_count == 0 || blue_count == 0) && player_count != 1)
{
Log::warn("ServerLobby", "Bad team choosing.");
NetworkString* bt = getNetworkString();
@ -856,6 +864,22 @@ void ServerLobby::startSelection(const Event *event)
m_available_kts.second.erase(track_erase);
}
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_BATTLE &&
race_manager->getMajorMode() == RaceManager::MAJOR_MODE_FREE_FOR_ALL)
{
auto it = m_available_kts.second.begin();
while (it != m_available_kts.second.end())
{
Track* t = track_manager->getTrack(*it);
if (t->getMaxArenaPlayers() < player_count)
{
it = m_available_kts.second.erase(it);
}
else
it++;
}
}
const auto& all_k = m_available_kts.first;
const auto& all_t = m_available_kts.second;
ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size());
@ -1508,7 +1532,8 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr<STKPeer> peer,
(peer, i == 0 && !online_name.empty() ? online_name : name,
peer->getHostId(), default_kart_color, i == 0 ? online_id : 0,
per_player_difficulty, (uint8_t)i, SOCCER_TEAM_NONE);
if (NetworkConfig::get()->hasTeamChoosing())
if (NetworkConfig::get()->hasTeamChoosing() &&
race_manager->teamEnabled())
player->setTeam((SoccerTeam)(peer->getHostId() % 2));
peer->addPlayer(player);
}
@ -1570,7 +1595,7 @@ void ServerLobby::updatePlayerList(bool force_update)
pl->addUInt8(server_owner);
pl->addUInt8(profile->getPerPlayerDifficulty());
if (NetworkConfig::get()->hasTeamChoosing() &&
race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
race_manager->teamEnabled())
pl->addUInt8(profile->getTeam());
else
pl->addUInt8(SOCCER_TEAM_NONE);
@ -1807,6 +1832,47 @@ std::tuple<std::string, uint8_t, bool, bool> ServerLobby::handleVote()
true : false);
} // handleVote
// ----------------------------------------------------------------------------
std::pair<int, float> ServerLobby::getHitCaptureLimit(float num_karts)
{
// Read user_config.hpp for formula
int hit_capture_limit = std::numeric_limits<int>::max();
float time_limit = 0.0f;
if (race_manager->getMajorMode() ==
RaceManager::MAJOR_MODE_CAPTURE_THE_FLAG)
{
if (UserConfigParams::m_capture_limit_threshold > 0.0f)
{
float val = fmaxf(2.0f, num_karts *
UserConfigParams::m_capture_limit_threshold);
hit_capture_limit = (int)val;
}
if (UserConfigParams::m_time_limit_threshold_ctf > 0.0f)
{
time_limit = fmaxf(2.0f, num_karts *
(UserConfigParams::m_time_limit_threshold_ctf +
UserConfigParams::m_flag_return_timemout / 60.f) * 60.0f);
}
}
else
{
if (UserConfigParams::m_hit_limit_threshold > 0.0f)
{
float val = fminf(num_karts *
UserConfigParams::m_hit_limit_threshold, 40.0f);
hit_capture_limit = (int)val;
if (hit_capture_limit == 0)
hit_capture_limit = 1;
}
if (UserConfigParams::m_time_limit_threshold_ffa > 0.0f)
{
time_limit = fmaxf(num_karts *
UserConfigParams::m_time_limit_threshold_ffa, 2.0f) * 60.0f;
}
}
return std::make_pair(hit_capture_limit, time_limit);
} // getHitCaptureLimit
// ----------------------------------------------------------------------------
/** Called from the RaceManager of the server when the world is loaded. Marks
* the server to be ready to start the race.

View File

@ -219,7 +219,7 @@ private:
double scalingValueForTime(double time);
void checkRaceFinished();
void sendBadConnectionMessageToPeer(std::shared_ptr<STKPeer> p);
std::pair<int, float> getHitCaptureLimit(float num_karts);
public:
ServerLobby();
virtual ~ServerLobby();

View File

@ -32,10 +32,12 @@
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "karts/kart_properties_manager.hpp"
#include "modes/capture_the_flag.hpp"
#include "modes/cutscene_world.hpp"
#include "modes/demo_world.hpp"
#include "modes/easter_egg_hunt.hpp"
#include "modes/follow_the_leader.hpp"
#include "modes/free_for_all.hpp"
#include "modes/overworld.hpp"
#include "modes/profile_world.hpp"
#include "modes/standard_race.hpp"
@ -523,7 +525,14 @@ void RaceManager::startNextRace()
else if(m_minor_mode==MINOR_MODE_TUTORIAL)
World::setWorld(new TutorialWorld());
else if(m_minor_mode==MINOR_MODE_BATTLE)
World::setWorld(new ThreeStrikesBattle());
{
if (m_major_mode == MAJOR_MODE_3_STRIKES)
World::setWorld(new ThreeStrikesBattle());
else if (m_major_mode == MAJOR_MODE_FREE_FOR_ALL)
World::setWorld(new FreeForAll());
else if (m_major_mode == MAJOR_MODE_CAPTURE_THE_FLAG)
World::setWorld(new CaptureTheFlag());
}
else if(m_minor_mode==MINOR_MODE_SOCCER)
World::setWorld(new SoccerWorld());
else if(m_minor_mode==MINOR_MODE_OVERWORLD)
@ -919,7 +928,8 @@ void RaceManager::startSingleRace(const std::string &track_ident,
if (num_laps != -1) setNumLaps( num_laps );
setMajorMode(RaceManager::MAJOR_MODE_SINGLE);
if (m_minor_mode != MINOR_MODE_BATTLE)
setMajorMode(RaceManager::MAJOR_MODE_SINGLE);
setCoinTarget( 0 ); // Might still be set from a previous challenge

View File

@ -849,6 +849,12 @@ public:
}
// ------------------------------------------------------------------------
int getHitCaptureLimit() const { return m_hit_capture_limit; }
// ------------------------------------------------------------------------
bool teamEnabled() const
{
return m_minor_mode == MINOR_MODE_SOCCER ||
m_major_mode == MAJOR_MODE_CAPTURE_THE_FLAG;
}
}; // RaceManager

View File

@ -22,6 +22,7 @@
using namespace irr;
#include <algorithm>
#include <limits>
#include "challenges/unlock_manager.hpp"
#include "config/user_config.hpp"
@ -381,8 +382,10 @@ void RaceGUI::drawGlobalTimer()
bool use_digit_font = true;
float elapsed_time = World::getWorld()->getTime();
if (!race_manager->hasTimeTarget() || race_manager
->getMinorMode()==RaceManager::MINOR_MODE_SOCCER)
if (!race_manager->hasTimeTarget() ||
race_manager ->getMinorMode()==RaceManager::MINOR_MODE_SOCCER ||
race_manager->getMajorMode() == RaceManager::MAJOR_MODE_FREE_FOR_ALL ||
race_manager->getMajorMode() == RaceManager::MAJOR_MODE_CAPTURE_THE_FLAG)
{
sw = core::stringw (
StringUtils::timeToString(elapsed_time).c_str() );
@ -710,6 +713,28 @@ void RaceGUI::drawRank(const AbstractKart *kart,
float min_ratio, int meter_width,
int meter_height, float dt)
{
static video::SColor color = video::SColor(255, 255, 255, 255);
// Draw hit or capture limit in network game
if ((race_manager->getMajorMode() == RaceManager::MAJOR_MODE_FREE_FOR_ALL ||
race_manager->getMajorMode() == RaceManager::MAJOR_MODE_CAPTURE_THE_FLAG) &&
race_manager->getHitCaptureLimit() != std::numeric_limits<int>::max())
{
gui::ScalableFont* font = GUIEngine::getHighresDigitFont();
font->setScale(min_ratio * 1.0f);
font->setShadow(video::SColor(255, 128, 0, 0));
std::ostringstream oss;
oss << race_manager->getHitCaptureLimit();
core::recti pos;
pos.LowerRightCorner = core::vector2di(int(offset.X + 0.64f*meter_width),
int(offset.Y - 0.49f*meter_height));
pos.UpperLeftCorner = core::vector2di(int(offset.X + 0.64f*meter_width),
int(offset.Y - 0.49f*meter_height));
font->draw(oss.str().c_str(), pos, color, true, true);
return;
}
// Draw rank
WorldWithRank *world = dynamic_cast<WorldWithRank*>(World::getWorld());
if (!world || !world->displayRank())
@ -775,7 +800,6 @@ void RaceGUI::drawRank(const AbstractKart *kart,
pos.UpperLeftCorner = core::vector2di(int(offset.X + 0.64f*meter_width),
int(offset.Y - 0.49f*meter_height));
static video::SColor color = video::SColor(255, 255, 255, 255);
font->draw(oss.str().c_str(), pos, color, true, true);
font->setScale(1.0f);
} // drawRank

View File

@ -845,14 +845,21 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
break;
}
if (m_kart_display_infos[kart_id].m_text.size() > 0)
if (info.m_text.size() > 0)
{
core::rect<s32> pos(x+ICON_PLAYER_WIDTH, y+5,
x+ICON_PLAYER_WIDTH, y+5);
core::stringw s=info.m_text.c_str();
font->draw(s.c_str(), pos, info.m_color, false, false, NULL,
true /* ignore RTL */);
if (info.m_outlined_font)
{
GUIEngine::getOutlineFont()->draw(info.m_text, pos,
GUIEngine::getSkin()->getColor("font::normal"), false,
false, NULL, true/*ignore RTL*/);
}
else
{
font->draw(info.m_text, pos, info.m_color, false, false, NULL,
true/*ignore RTL*/);
}
}
if (info.special_title.size() > 0)

View File

@ -66,6 +66,8 @@ public:
/** Current lap of this kart, or -1 if irrelevant. */
int lap;
bool m_outlined_font = false;
}; // KartIconDisplayInfo
private:

View File

@ -42,9 +42,9 @@
#include "karts/kart_properties_manager.hpp"
#include "modes/cutscene_world.hpp"
#include "modes/demo_world.hpp"
#include "modes/free_for_all.hpp"
#include "modes/overworld.hpp"
#include "modes/soccer_world.hpp"
#include "modes/world_with_rank.hpp"
#include "network/network_config.hpp"
#include "network/stk_host.hpp"
#include "network/protocols/client_lobby.hpp"
@ -523,6 +523,7 @@ void RaceResultGUI::backToLobby()
m_width_kart_name = 0;
float max_finish_time = 0;
FreeForAll* ffa = dynamic_cast<FreeForAll*>(World::getWorld());
for (unsigned int position = first_position;
position <= race_manager->getNumberOfKarts() - sta; position++)
{
@ -543,6 +544,13 @@ void RaceResultGUI::backToLobby()
{
ri->m_finish_time_string = core::stringw(_("Eliminated"));
}
else if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_FREE_FOR_ALL ||
race_manager->getMajorMode() == RaceManager::MAJOR_MODE_CAPTURE_THE_FLAG)
{
assert(ffa);
ri->m_finish_time_string =
StringUtils::toWString(ffa->getKartScore(kart->getWorldKartId()));
}
else
{
const float time = kart->getFinishTime();