Merge remote-tracking branch 'origin/spare_tire_kart'
This commit is contained in:
commit
24f926b780
BIN
data/gui/heart.png
Normal file
BIN
data/gui/heart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
@ -1,5 +1,5 @@
|
|||||||
# Modify this file to change the last-modified date when you add/remove a file.
|
# 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_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
|
||||||
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
|
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
|
||||||
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
|
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
|
||||||
|
@ -43,10 +43,7 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
|
|||||||
m_distance_2 = 1.2f;
|
m_distance_2 = 1.2f;
|
||||||
initItem(type, xyz);
|
initItem(type, xyz);
|
||||||
|
|
||||||
Vec3 axis = -normal.cross(Vec3(0, 1, 0));
|
m_original_rotation = Track::createRotationFromNormal(normal);
|
||||||
if (axis.length() == 0)
|
|
||||||
axis = Vec3(0, 0, 1);
|
|
||||||
m_original_rotation = btQuaternion(axis, normal.angle(Vec3(0, 1, 0)));
|
|
||||||
m_rotation_angle = 0.0f;
|
m_rotation_angle = 0.0f;
|
||||||
m_original_mesh = mesh;
|
m_original_mesh = mesh;
|
||||||
m_original_lowmesh = lowres_mesh;
|
m_original_lowmesh = lowres_mesh;
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "graphics/material_manager.hpp"
|
#include "graphics/material_manager.hpp"
|
||||||
#include "io/file_manager.hpp"
|
#include "io/file_manager.hpp"
|
||||||
#include "karts/abstract_kart.hpp"
|
#include "karts/abstract_kart.hpp"
|
||||||
|
#include "karts/controller/spare_tire_ai.hpp"
|
||||||
#include "modes/linear_world.hpp"
|
#include "modes/linear_world.hpp"
|
||||||
#include "network/network_config.hpp"
|
#include "network/network_config.hpp"
|
||||||
#include "network/race_event_manager.hpp"
|
#include "network/race_event_manager.hpp"
|
||||||
@ -287,6 +288,8 @@ Item* ItemManager::newItem(const Vec3& xyz, float distance,
|
|||||||
void ItemManager::collectedItem(Item *item, AbstractKart *kart, int add_info)
|
void ItemManager::collectedItem(Item *item, AbstractKart *kart, int add_info)
|
||||||
{
|
{
|
||||||
assert(item);
|
assert(item);
|
||||||
|
// Spare tire karts don't collect items
|
||||||
|
if (dynamic_cast<SpareTireAI*>(kart->getController()) != NULL) return;
|
||||||
if( (item->getType() == Item::ITEM_BUBBLEGUM ||
|
if( (item->getType() == Item::ITEM_BUBBLEGUM ||
|
||||||
item->getType() == Item::ITEM_BUBBLEGUM_NOLOK) && kart->isShielded())
|
item->getType() == Item::ITEM_BUBBLEGUM_NOLOK) && kart->isShielded())
|
||||||
{
|
{
|
||||||
|
@ -119,7 +119,6 @@ void ArenaAI::update(float dt)
|
|||||||
if (gettingUnstuck(dt))
|
if (gettingUnstuck(dt))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
findClosestKart(true);
|
|
||||||
findTarget();
|
findTarget();
|
||||||
|
|
||||||
// After found target, convert it to local coordinate, used for skidding or
|
// After found target, convert it to local coordinate, used for skidding or
|
||||||
@ -395,7 +394,7 @@ void ArenaAI::useItems(const float dt)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Find a closest kart again, this time we ignore difficulty
|
// Find a closest kart again, this time we ignore difficulty
|
||||||
findClosestKart(false);
|
findClosestKart(false/*use_difficulty*/, false/*find_sta*/);
|
||||||
if (!m_closest_kart) return;
|
if (!m_closest_kart) return;
|
||||||
|
|
||||||
Vec3 closest_kart_point_lc =
|
Vec3 closest_kart_point_lc =
|
||||||
|
@ -65,7 +65,8 @@ protected:
|
|||||||
|
|
||||||
bool m_mini_skid;
|
bool m_mini_skid;
|
||||||
|
|
||||||
void collectItemInArena(Vec3*, int*) const;
|
void collectItemInArena(Vec3*, int*) const;
|
||||||
|
virtual void findClosestKart(bool use_difficulty, bool find_sta) = 0;
|
||||||
private:
|
private:
|
||||||
Vec3 m_target_point_lc;
|
Vec3 m_target_point_lc;
|
||||||
|
|
||||||
@ -115,7 +116,6 @@ private:
|
|||||||
void useItems(const float dt);
|
void useItems(const float dt);
|
||||||
virtual bool canSkid(float steer_fraction) OVERRIDE
|
virtual bool canSkid(float steer_fraction) OVERRIDE
|
||||||
{ return m_mini_skid; }
|
{ return m_mini_skid; }
|
||||||
virtual void findClosestKart(bool use_difficulty) = 0;
|
|
||||||
virtual void findTarget() = 0;
|
virtual void findTarget() = 0;
|
||||||
virtual bool forceBraking() { return false; }
|
virtual bool forceBraking() { return false; }
|
||||||
virtual int getCurrentNode() const = 0;
|
virtual int getCurrentNode() const = 0;
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "items/powerup.hpp"
|
#include "items/powerup.hpp"
|
||||||
#include "karts/abstract_kart.hpp"
|
#include "karts/abstract_kart.hpp"
|
||||||
#include "karts/controller/kart_control.hpp"
|
#include "karts/controller/kart_control.hpp"
|
||||||
|
#include "karts/controller/spare_tire_ai.hpp"
|
||||||
#include "modes/three_strikes_battle.hpp"
|
#include "modes/three_strikes_battle.hpp"
|
||||||
#include "tracks/arena_graph.hpp"
|
#include "tracks/arena_graph.hpp"
|
||||||
|
|
||||||
@ -65,50 +66,42 @@ BattleAI::~BattleAI()
|
|||||||
} // ~BattleAI
|
} // ~BattleAI
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
/** Resets the AI when a race is restarted.
|
void BattleAI::findClosestKart(bool use_difficulty, bool find_sta)
|
||||||
*/
|
|
||||||
void BattleAI::reset()
|
|
||||||
{
|
|
||||||
ArenaAI::reset();
|
|
||||||
} // reset
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void BattleAI::update(float dt)
|
|
||||||
{
|
|
||||||
ArenaAI::update(dt);
|
|
||||||
} // update
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void BattleAI::findClosestKart(bool use_difficulty)
|
|
||||||
{
|
{
|
||||||
float distance = 99999.9f;
|
float distance = 99999.9f;
|
||||||
const unsigned int n = m_world->getNumKarts();
|
|
||||||
int closest_kart_num = 0;
|
int closest_kart_num = 0;
|
||||||
|
const int end = m_world->getNumKarts();
|
||||||
|
|
||||||
for (unsigned int i = 0; i < n; i++)
|
for (int start_id =
|
||||||
|
find_sta ? end - race_manager->getNumSpareTireKarts() : 0;
|
||||||
|
start_id < end; start_id++)
|
||||||
{
|
{
|
||||||
const AbstractKart* kart = m_world->getKart(i);
|
const AbstractKart* kart = m_world->getKart(start_id);
|
||||||
if (kart->isEliminated()) continue;
|
const SpareTireAI* sta =
|
||||||
|
dynamic_cast<const SpareTireAI*>(kart->getController());
|
||||||
|
if (kart->isEliminated() && !(find_sta && sta && sta->isMoving()))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (kart->getWorldKartId() == m_kart->getWorldKartId())
|
if (kart->getWorldKartId() == m_kart->getWorldKartId())
|
||||||
continue; // Skip the same kart
|
continue; // Skip the same kart
|
||||||
|
|
||||||
// Test whether takes current difficulty into account for closest kart
|
// Test whether takes current difficulty into account for closest kart
|
||||||
// Notice: it don't affect aiming, this function will be called once
|
// Notice: it don't affect aiming, this function will be called once
|
||||||
// more in handleArenaItems, which ignore difficulty.
|
// more when use items, which ignore difficulty.
|
||||||
if (m_cur_difficulty == RaceManager::DIFFICULTY_EASY && use_difficulty)
|
if (m_cur_difficulty == RaceManager::DIFFICULTY_EASY && use_difficulty)
|
||||||
{
|
{
|
||||||
// Skip human players for novice mode unless only human players left
|
// Skip human players for novice mode unless only they are left
|
||||||
const AbstractKart* temp = m_world->getKart(i);
|
const AbstractKart* temp = m_world->getKart(start_id);
|
||||||
if (temp->getController()->isPlayerController() &&
|
if (temp->getController()->isPlayerController() &&
|
||||||
(m_world->getCurrentNumKarts() -
|
(m_world->getCurrentNumKarts() -
|
||||||
m_world->getCurrentNumPlayers()) > 1)
|
m_world->getCurrentNumPlayers()) > 1)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (m_cur_difficulty == RaceManager::DIFFICULTY_BEST && use_difficulty)
|
else if (m_cur_difficulty == RaceManager::DIFFICULTY_BEST &&
|
||||||
|
use_difficulty)
|
||||||
{
|
{
|
||||||
// Skip AI players for supertux mode
|
// Skip AI players for supertux mode
|
||||||
const AbstractKart* temp = m_world->getKart(i);
|
const AbstractKart* temp = m_world->getKart(start_id);
|
||||||
if (!(temp->getController()->isPlayerController()))
|
if (!(temp->getController()->isPlayerController()))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -118,7 +111,7 @@ void BattleAI::findClosestKart(bool use_difficulty)
|
|||||||
if (dist_to_kart <= distance)
|
if (dist_to_kart <= distance)
|
||||||
{
|
{
|
||||||
distance = dist_to_kart;
|
distance = dist_to_kart;
|
||||||
closest_kart_num = i;
|
closest_kart_num = start_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,9 +124,30 @@ void BattleAI::findClosestKart(bool use_difficulty)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void BattleAI::findTarget()
|
void BattleAI::findTarget()
|
||||||
{
|
{
|
||||||
|
// Find the closest kart first, it's used as fallback if no item is found.
|
||||||
|
// It takes the current difficulty into account, also collect life from
|
||||||
|
// spare tire karts when neccessary
|
||||||
|
|
||||||
|
// Collect life depends on current difficulty:
|
||||||
|
// Novice and intermediate - collect them only AI has 1 life only
|
||||||
|
// Expert and supertux - collect them if AI dones't have 3 lives
|
||||||
|
// Also when actually spare tire karts are spawned
|
||||||
|
bool find_sta = m_world->spareTireKartsSpawned() ?
|
||||||
|
((m_cur_difficulty == RaceManager::DIFFICULTY_EASY ||
|
||||||
|
m_cur_difficulty == RaceManager::DIFFICULTY_MEDIUM) &&
|
||||||
|
m_world->getKartLife(m_kart->getWorldKartId()) == 1 ?
|
||||||
|
true :
|
||||||
|
(m_cur_difficulty == RaceManager::DIFFICULTY_HARD ||
|
||||||
|
m_cur_difficulty == RaceManager::DIFFICULTY_BEST) &&
|
||||||
|
m_world->getKartLife(m_kart->getWorldKartId()) != 3 ?
|
||||||
|
true : false) : false;
|
||||||
|
|
||||||
|
findClosestKart(find_sta ? false : true/*use_difficulty*/, find_sta);
|
||||||
|
|
||||||
// Find a suitable target to drive to, either powerup or kart
|
// Find a suitable target to drive to, either powerup or kart
|
||||||
if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING &&
|
if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING &&
|
||||||
m_kart->getAttachment()->getType() != Attachment::ATTACH_SWATTER)
|
m_kart->getAttachment()->getType() != Attachment::ATTACH_SWATTER &&
|
||||||
|
!find_sta)
|
||||||
collectItemInArena(&m_target_point , &m_target_node);
|
collectItemInArena(&m_target_point , &m_target_node);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -30,21 +30,19 @@ class ThreeStrikesBattle;
|
|||||||
*/
|
*/
|
||||||
class BattleAI : public ArenaAI
|
class BattleAI : public ArenaAI
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
/** Keep a pointer to world. */
|
/** Keep a pointer to world. */
|
||||||
ThreeStrikesBattle *m_world;
|
ThreeStrikesBattle *m_world;
|
||||||
|
virtual void findClosestKart(bool use_difficulty, bool find_sta) OVERRIDE;
|
||||||
virtual void findClosestKart(bool use_difficulty) OVERRIDE;
|
|
||||||
virtual void findTarget() OVERRIDE;
|
|
||||||
virtual int getCurrentNode() const OVERRIDE;
|
virtual int getCurrentNode() const OVERRIDE;
|
||||||
|
private:
|
||||||
|
virtual void findTarget() OVERRIDE;
|
||||||
virtual float getKartDistance(const AbstractKart* kart) const OVERRIDE;
|
virtual float getKartDistance(const AbstractKart* kart) const OVERRIDE;
|
||||||
virtual bool isKartOnRoad() const OVERRIDE;
|
virtual bool isKartOnRoad() const OVERRIDE;
|
||||||
virtual bool isWaiting() const OVERRIDE;
|
virtual bool isWaiting() const OVERRIDE;
|
||||||
public:
|
public:
|
||||||
BattleAI(AbstractKart *kart);
|
BattleAI(AbstractKart *kart);
|
||||||
~BattleAI();
|
~BattleAI();
|
||||||
virtual void update (float delta) OVERRIDE;
|
|
||||||
virtual void reset () OVERRIDE;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -129,7 +129,7 @@ void SoccerAI::update(float dt)
|
|||||||
} // update
|
} // update
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void SoccerAI::findClosestKart(bool use_difficulty)
|
void SoccerAI::findClosestKart(bool use_difficulty, bool find_sta)
|
||||||
{
|
{
|
||||||
float distance = 99999.9f;
|
float distance = 99999.9f;
|
||||||
const unsigned int n = m_world->getNumKarts();
|
const unsigned int n = m_world->getNumKarts();
|
||||||
@ -165,6 +165,7 @@ void SoccerAI::findClosestKart(bool use_difficulty)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void SoccerAI::findTarget()
|
void SoccerAI::findTarget()
|
||||||
{
|
{
|
||||||
|
findClosestKart(true/*use_difficulty*/, false/*find_sta*/);
|
||||||
// Check if this AI kart is the one who will chase the ball
|
// Check if this AI kart is the one who will chase the ball
|
||||||
if (m_world->getBallChaser(m_cur_team) == (signed)m_kart->getWorldKartId())
|
if (m_world->getBallChaser(m_cur_team) == (signed)m_kart->getWorldKartId())
|
||||||
{
|
{
|
||||||
|
@ -65,7 +65,7 @@ private:
|
|||||||
|
|
||||||
virtual bool canSkid(float steer_fraction) OVERRIDE
|
virtual bool canSkid(float steer_fraction) OVERRIDE
|
||||||
{ return m_mini_skid && !(m_overtake_ball || m_chasing_ball); }
|
{ return m_mini_skid && !(m_overtake_ball || m_chasing_ball); }
|
||||||
virtual void findClosestKart(bool use_difficulty) OVERRIDE;
|
virtual void findClosestKart(bool use_difficulty, bool find_sta) OVERRIDE;
|
||||||
virtual void findTarget() OVERRIDE;
|
virtual void findTarget() OVERRIDE;
|
||||||
virtual bool forceBraking() OVERRIDE { return m_force_brake; }
|
virtual bool forceBraking() OVERRIDE { return m_force_brake; }
|
||||||
virtual int getCurrentNode() const OVERRIDE;
|
virtual int getCurrentNode() const OVERRIDE;
|
||||||
|
136
src/karts/controller/spare_tire_ai.cpp
Normal file
136
src/karts/controller/spare_tire_ai.cpp
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
//
|
||||||
|
// SuperTuxKart - a fun racing game with go-kart
|
||||||
|
// Copyright (C) 2016 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 "karts/controller/spare_tire_ai.hpp"
|
||||||
|
|
||||||
|
#include "karts/abstract_kart.hpp"
|
||||||
|
#include "karts/kart_gfx.hpp"
|
||||||
|
#include "karts/max_speed.hpp"
|
||||||
|
#include "modes/three_strikes_battle.hpp"
|
||||||
|
#include "states_screens/race_gui.hpp"
|
||||||
|
#include "tracks/arena_graph.hpp"
|
||||||
|
#include "tracks/arena_node.hpp"
|
||||||
|
#include "physics/physics.hpp"
|
||||||
|
#include "utils/random_generator.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
SpareTireAI::SpareTireAI(AbstractKart *kart)
|
||||||
|
: BattleAI(kart)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
// Don't call our own setControllerName, since this will add a
|
||||||
|
// billboard showing 'AIBaseController' to the kart.
|
||||||
|
Controller::setControllerName("SpareTireAI");
|
||||||
|
|
||||||
|
// Pre-load the 4 nodes of bounding box defined by battle world
|
||||||
|
memcpy(m_fixed_target_nodes, m_graph->getBBNodes(), 4 * sizeof(int));
|
||||||
|
|
||||||
|
// Reverse the order depends on world ID, so not all spare tire karts go
|
||||||
|
// the same way
|
||||||
|
if (m_kart->getWorldKartId() % 2 != 0)
|
||||||
|
{
|
||||||
|
std::reverse(std::begin(m_fixed_target_nodes),
|
||||||
|
std::end(m_fixed_target_nodes));
|
||||||
|
}
|
||||||
|
} // SpareTireAI
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** Resets the AI when a race is restarted.
|
||||||
|
*/
|
||||||
|
void SpareTireAI::reset()
|
||||||
|
{
|
||||||
|
BattleAI::reset();
|
||||||
|
m_idx = 0;
|
||||||
|
m_timer = 0.0f;
|
||||||
|
} // reset
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void SpareTireAI::update(float dt)
|
||||||
|
{
|
||||||
|
BattleAI::update(dt);
|
||||||
|
m_kart->setSlowdown(MaxSpeed::MS_DECREASE_AI, 0.5f, /*fade_in_time*/0.0f);
|
||||||
|
m_timer -= dt;
|
||||||
|
if (m_timer < 0.0f)
|
||||||
|
unspawn();
|
||||||
|
} // update
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void SpareTireAI::findDefaultPath()
|
||||||
|
{
|
||||||
|
// Randomly find a start node for spare tire kart to move
|
||||||
|
assert(m_idx == -1);
|
||||||
|
|
||||||
|
RandomGenerator random;
|
||||||
|
m_idx = random.get(4);
|
||||||
|
m_target_node = m_fixed_target_nodes[m_idx];
|
||||||
|
|
||||||
|
} // findDefaultPath
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void SpareTireAI::findTarget()
|
||||||
|
{
|
||||||
|
assert(m_idx != -1 && m_idx < 4);
|
||||||
|
if (getCurrentNode() == m_fixed_target_nodes[m_idx])
|
||||||
|
m_idx = m_idx == 3 ? 0 : m_idx + 1;
|
||||||
|
|
||||||
|
const int chosen_node = m_fixed_target_nodes[m_idx];
|
||||||
|
m_target_node = chosen_node;
|
||||||
|
m_target_point = m_graph->getNode(chosen_node)->getCenter();
|
||||||
|
} // findTarget
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void SpareTireAI::spawn(float time_to_last)
|
||||||
|
{
|
||||||
|
findDefaultPath();
|
||||||
|
m_timer = time_to_last;
|
||||||
|
|
||||||
|
World::getWorld()->getPhysics()->addKart(m_kart);
|
||||||
|
m_kart->startEngineSFX();
|
||||||
|
m_kart->getKartGFX()->reset();
|
||||||
|
m_kart->getNode()->setVisible(true);
|
||||||
|
|
||||||
|
} // spawn
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void SpareTireAI::unspawn()
|
||||||
|
{
|
||||||
|
m_idx = -1;
|
||||||
|
m_kart->eliminate();
|
||||||
|
} // unspawn
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void SpareTireAI::crashed(const AbstractKart *k)
|
||||||
|
{
|
||||||
|
// Nothing happen when two spare tire karts crash each other
|
||||||
|
if (dynamic_cast<const SpareTireAI*>(k->getController()) != NULL) return;
|
||||||
|
|
||||||
|
// Tell player that they have max 3 lives only
|
||||||
|
if (m_world->getKartLife(k->getWorldKartId()) == 3)
|
||||||
|
{
|
||||||
|
World::getWorld()->getRaceGUI()->addMessage
|
||||||
|
(_("You can have at most 3 lives!"), k, 2.0f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise increase one life for that kart and unspawn
|
||||||
|
m_world->addKartLife(k->getWorldKartId());
|
||||||
|
World::getWorld()->getRaceGUI()->addMessage(_("+1 life."), k, 2.0f);
|
||||||
|
unspawn();
|
||||||
|
|
||||||
|
} // crashed
|
48
src/karts/controller/spare_tire_ai.hpp
Normal file
48
src/karts/controller/spare_tire_ai.hpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// SuperTuxKart - a fun racing game with go-kart
|
||||||
|
// Copyright (C) 2016 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 HEADER_SPARE_TIRE_AI_HPP
|
||||||
|
#define HEADER_SPARE_TIRE_AI_HPP
|
||||||
|
|
||||||
|
#include "karts/controller/battle_ai.hpp"
|
||||||
|
|
||||||
|
/** The AI for spare tire karts in battle mode, allowing kart to gain life.
|
||||||
|
* \ingroup controller
|
||||||
|
*/
|
||||||
|
class SpareTireAI : public BattleAI
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int m_fixed_target_nodes[4];
|
||||||
|
|
||||||
|
int m_idx;
|
||||||
|
|
||||||
|
float m_timer;
|
||||||
|
|
||||||
|
virtual void findTarget() OVERRIDE;
|
||||||
|
void findDefaultPath();
|
||||||
|
public:
|
||||||
|
SpareTireAI(AbstractKart *kart);
|
||||||
|
virtual void crashed(const AbstractKart *k) OVERRIDE;
|
||||||
|
virtual void update(float delta) OVERRIDE;
|
||||||
|
virtual void reset() OVERRIDE;
|
||||||
|
void spawn(float time_to_last);
|
||||||
|
void unspawn();
|
||||||
|
bool isMoving() const { return m_idx != -1; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -50,6 +50,7 @@
|
|||||||
#include "karts/abstract_kart_animation.hpp"
|
#include "karts/abstract_kart_animation.hpp"
|
||||||
#include "karts/cached_characteristic.hpp"
|
#include "karts/cached_characteristic.hpp"
|
||||||
#include "karts/controller/end_controller.hpp"
|
#include "karts/controller/end_controller.hpp"
|
||||||
|
#include "karts/controller/spare_tire_ai.hpp"
|
||||||
#include "karts/explosion_animation.hpp"
|
#include "karts/explosion_animation.hpp"
|
||||||
#include "karts/kart_gfx.hpp"
|
#include "karts/kart_gfx.hpp"
|
||||||
#include "karts/kart_model.hpp"
|
#include "karts/kart_model.hpp"
|
||||||
@ -862,6 +863,9 @@ void Kart::finishedRace(float time, bool from_server)
|
|||||||
m_kart_model->finishedRace();
|
m_kart_model->finishedRace();
|
||||||
race_manager->kartFinishedRace(this, time);
|
race_manager->kartFinishedRace(this, time);
|
||||||
|
|
||||||
|
// If this is spare tire kart, end now
|
||||||
|
if (dynamic_cast<SpareTireAI*>(m_controller) != NULL) return;
|
||||||
|
|
||||||
if ((race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
if ((race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL ||
|
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL ||
|
||||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||||
|
@ -149,7 +149,8 @@ void KartGFX::addEffect(KartGFXType type, const std::string &file_name,
|
|||||||
const Vec3 &position, bool important)
|
const Vec3 &position, bool important)
|
||||||
{
|
{
|
||||||
if (!UserConfigParams::m_graphical_effects &&
|
if (!UserConfigParams::m_graphical_effects &&
|
||||||
(!important || m_kart->getType() == RaceManager::KT_AI))
|
(!important || m_kart->getType() == RaceManager::KT_AI ||
|
||||||
|
m_kart->getType() == RaceManager::KT_SPARE_TIRE))
|
||||||
{
|
{
|
||||||
m_all_emitters.push_back(NULL);
|
m_all_emitters.push_back(NULL);
|
||||||
return;
|
return;
|
||||||
|
@ -494,7 +494,7 @@ const std::vector<int> KartPropertiesManager::getKartsInGroup(
|
|||||||
* to this list.
|
* to this list.
|
||||||
*/
|
*/
|
||||||
void KartPropertiesManager::getRandomKartList(int count,
|
void KartPropertiesManager::getRandomKartList(int count,
|
||||||
RemoteKartInfoList& existing_karts,
|
RemoteKartInfoList* existing_karts,
|
||||||
std::vector<std::string> *ai_list)
|
std::vector<std::string> *ai_list)
|
||||||
{
|
{
|
||||||
// First: set up flags (based on global kart
|
// First: set up flags (based on global kart
|
||||||
@ -504,18 +504,22 @@ void KartPropertiesManager::getRandomKartList(int count,
|
|||||||
used.resize(getNumberOfKarts(), false);
|
used.resize(getNumberOfKarts(), false);
|
||||||
|
|
||||||
std::vector<std::string> random_kart_queue;
|
std::vector<std::string> random_kart_queue;
|
||||||
for (unsigned int i=0; i<existing_karts.size(); i++)
|
if (existing_karts != NULL)
|
||||||
{
|
{
|
||||||
try
|
for (unsigned int i=0; i<existing_karts->size(); i++)
|
||||||
{
|
{
|
||||||
int id = getKartId(existing_karts[i].getKartName());
|
try
|
||||||
used[id] = true;
|
{
|
||||||
}
|
int id = getKartId((*existing_karts)[i].getKartName());
|
||||||
catch (std::runtime_error& ex)
|
used[id] = true;
|
||||||
{
|
}
|
||||||
(void)ex;
|
catch (std::runtime_error& ex)
|
||||||
Log::error("[KartPropertiesManager]", "getRandomKartList : WARNING, "
|
{
|
||||||
"can't find kart '%s'", existing_karts[i].getKartName().c_str());
|
(void)ex;
|
||||||
|
Log::error("[KartPropertiesManager]", "getRandomKartList : "
|
||||||
|
"WARNING, can't find kart '%s'",
|
||||||
|
(*existing_karts)[i].getKartName().c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(unsigned int i=0; i<ai_list->size(); i++)
|
for(unsigned int i=0; i<ai_list->size(); i++)
|
||||||
|
@ -94,7 +94,7 @@ public:
|
|||||||
void selectKartName(const std::string &kart_name);
|
void selectKartName(const std::string &kart_name);
|
||||||
bool testAndSetKart(int kartid);
|
bool testAndSetKart(int kartid);
|
||||||
void getRandomKartList(int count,
|
void getRandomKartList(int count,
|
||||||
RemoteKartInfoList& existing_karts,
|
RemoteKartInfoList* existing_karts,
|
||||||
std::vector<std::string> *ai_list);
|
std::vector<std::string> *ai_list);
|
||||||
void setHatMeshName(const std::string &hat_name);
|
void setHatMeshName(const std::string &hat_name);
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "karts/kart_properties.hpp"
|
#include "karts/kart_properties.hpp"
|
||||||
#include "karts/rescue_animation.hpp"
|
#include "karts/rescue_animation.hpp"
|
||||||
#include "karts/controller/local_player_controller.hpp"
|
#include "karts/controller/local_player_controller.hpp"
|
||||||
|
#include "karts/controller/network_player_controller.hpp"
|
||||||
#include "physics/physics.hpp"
|
#include "physics/physics.hpp"
|
||||||
#include "states_screens/race_gui_base.hpp"
|
#include "states_screens/race_gui_base.hpp"
|
||||||
#include "tracks/track.hpp"
|
#include "tracks/track.hpp"
|
||||||
@ -421,11 +422,9 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
|
|||||||
m_num_players ++;
|
m_num_players ++;
|
||||||
break;
|
break;
|
||||||
case RaceManager::KT_NETWORK_PLAYER:
|
case RaceManager::KT_NETWORK_PLAYER:
|
||||||
break; // Avoid compiler warning about enum not handled.
|
controller = new NetworkPlayerController(new_kart);
|
||||||
//controller = new NetworkController(kart_ident, position, init_pos,
|
m_num_players++;
|
||||||
// global_player_id);
|
break;
|
||||||
//m_num_players++;
|
|
||||||
//break;
|
|
||||||
case RaceManager::KT_AI:
|
case RaceManager::KT_AI:
|
||||||
controller = loadAIController(new_kart);
|
controller = loadAIController(new_kart);
|
||||||
break;
|
break;
|
||||||
@ -433,6 +432,8 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
|
|||||||
break;
|
break;
|
||||||
case RaceManager::KT_LEADER:
|
case RaceManager::KT_LEADER:
|
||||||
break;
|
break;
|
||||||
|
case RaceManager::KT_SPARE_TIRE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_kart->setController(controller);
|
new_kart->setController(controller);
|
||||||
|
@ -23,15 +23,20 @@
|
|||||||
#include "graphics/camera.hpp"
|
#include "graphics/camera.hpp"
|
||||||
#include "graphics/irr_driver.hpp"
|
#include "graphics/irr_driver.hpp"
|
||||||
#include "io/file_manager.hpp"
|
#include "io/file_manager.hpp"
|
||||||
#include "karts/abstract_kart.hpp"
|
#include "karts/kart.hpp"
|
||||||
|
#include "karts/controller/spare_tire_ai.hpp"
|
||||||
#include "karts/kart_model.hpp"
|
#include "karts/kart_model.hpp"
|
||||||
#include "karts/kart_properties.hpp"
|
#include "karts/kart_properties.hpp"
|
||||||
|
#include "karts/kart_properties_manager.hpp"
|
||||||
#include "physics/physics.hpp"
|
#include "physics/physics.hpp"
|
||||||
#include "states_screens/race_gui_base.hpp"
|
#include "states_screens/race_gui_base.hpp"
|
||||||
|
#include "tracks/arena_graph.hpp"
|
||||||
|
#include "tracks/arena_node.hpp"
|
||||||
#include "tracks/track.hpp"
|
#include "tracks/track.hpp"
|
||||||
#include "tracks/track_object_manager.hpp"
|
#include "tracks/track_object_manager.hpp"
|
||||||
#include "utils/constants.hpp"
|
#include "utils/constants.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <IMeshSceneNode.h>
|
#include <IMeshSceneNode.h>
|
||||||
|
|
||||||
@ -73,6 +78,7 @@ void ThreeStrikesBattle::init()
|
|||||||
ThreeStrikesBattle::~ThreeStrikesBattle()
|
ThreeStrikesBattle::~ThreeStrikesBattle()
|
||||||
{
|
{
|
||||||
m_tires.clearWithoutDeleting();
|
m_tires.clearWithoutDeleting();
|
||||||
|
m_spare_tire_karts.clear();
|
||||||
|
|
||||||
irr_driver->dropAllTextures(m_tire);
|
irr_driver->dropAllTextures(m_tire);
|
||||||
// Remove the mesh from the cache so that the mesh is properly
|
// Remove the mesh from the cache so that the mesh is properly
|
||||||
@ -88,11 +94,25 @@ void ThreeStrikesBattle::reset()
|
|||||||
{
|
{
|
||||||
WorldWithRank::reset();
|
WorldWithRank::reset();
|
||||||
|
|
||||||
|
m_next_sta_spawn_time =
|
||||||
|
race_manager->getDifficulty() == RaceManager::DIFFICULTY_BEST ? 40.0f :
|
||||||
|
race_manager->getDifficulty() == RaceManager::DIFFICULTY_HARD ? 30.0f :
|
||||||
|
race_manager->getDifficulty() == RaceManager::DIFFICULTY_MEDIUM ?
|
||||||
|
25.0f : 20.0f;
|
||||||
|
|
||||||
const unsigned int kart_amount = (unsigned int)m_karts.size();
|
const unsigned int kart_amount = (unsigned int)m_karts.size();
|
||||||
|
|
||||||
for(unsigned int n=0; n<kart_amount; n++)
|
for(unsigned int n=0; n<kart_amount; n++)
|
||||||
{
|
{
|
||||||
m_kart_info[n].m_lives = 3;
|
if (dynamic_cast<SpareTireAI*>(m_karts[n]->getController()) != NULL)
|
||||||
|
{
|
||||||
|
// STA has no life
|
||||||
|
m_kart_info[n].m_lives = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_kart_info[n].m_lives = 3;
|
||||||
|
}
|
||||||
|
|
||||||
// no positions in this mode
|
// no positions in this mode
|
||||||
m_karts[n]->setPosition(-1);
|
m_karts[n]->setPosition(-1);
|
||||||
@ -132,6 +152,18 @@ void ThreeStrikesBattle::reset()
|
|||||||
m_track->getTrackObjectManager()->removeObject(obj);
|
m_track->getTrackObjectManager()->removeObject(obj);
|
||||||
}
|
}
|
||||||
m_tires.clearWithoutDeleting();
|
m_tires.clearWithoutDeleting();
|
||||||
|
|
||||||
|
// Finish all spare tire karts first
|
||||||
|
if (!m_spare_tire_karts.empty())
|
||||||
|
{
|
||||||
|
updateKartRanks();
|
||||||
|
for (unsigned int i = 0; i < m_spare_tire_karts.size(); i++)
|
||||||
|
{
|
||||||
|
m_spare_tire_karts[i]->finishedRace(0.0f);
|
||||||
|
m_spare_tire_karts[i]->getNode()->setVisible(false);
|
||||||
|
m_eliminated_karts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
} // reset
|
} // reset
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -142,6 +174,20 @@ void ThreeStrikesBattle::reset()
|
|||||||
*/
|
*/
|
||||||
void ThreeStrikesBattle::kartAdded(AbstractKart* kart, scene::ISceneNode* node)
|
void ThreeStrikesBattle::kartAdded(AbstractKart* kart, scene::ISceneNode* node)
|
||||||
{
|
{
|
||||||
|
if (kart->getType() == RaceManager::KartType::KT_SPARE_TIRE)
|
||||||
|
{
|
||||||
|
// Add heart billboard above it
|
||||||
|
video::ITexture *heart =
|
||||||
|
irr_driver->getTexture(FileManager::GUI, "heart.png");
|
||||||
|
float height = kart->getKartHeight() + 0.5f;
|
||||||
|
|
||||||
|
scene::ISceneNode* billboard = irr_driver->addBillboard
|
||||||
|
(core::dimension2d<irr::f32>(0.8f, 0.8f), heart, kart->getNode(),
|
||||||
|
true);
|
||||||
|
billboard->setPosition(core::vector3df(0, height, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float coord = -kart->getKartLength()*0.5f;
|
float coord = -kart->getKartLength()*0.5f;
|
||||||
|
|
||||||
scene::IMeshSceneNode* tire_node = irr_driver->addMesh(m_tire, "3strikestire", node);
|
scene::IMeshSceneNode* tire_node = irr_driver->addMesh(m_tire, "3strikestire", node);
|
||||||
@ -165,6 +211,15 @@ void ThreeStrikesBattle::kartHit(const unsigned int kart_id)
|
|||||||
{
|
{
|
||||||
if (isRaceOver()) return;
|
if (isRaceOver()) return;
|
||||||
|
|
||||||
|
SpareTireAI* sta =
|
||||||
|
dynamic_cast<SpareTireAI*>(m_karts[kart_id]->getController());
|
||||||
|
if (sta)
|
||||||
|
{
|
||||||
|
// Unspawn the spare tire kart if it get hit
|
||||||
|
sta->unspawn();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
assert(kart_id < m_karts.size());
|
assert(kart_id < m_karts.size());
|
||||||
// make kart lose a life, ignore if in profiling mode
|
// make kart lose a life, ignore if in profiling mode
|
||||||
if (!UserConfigParams::m_arena_ai_stats)
|
if (!UserConfigParams::m_arena_ai_stats)
|
||||||
@ -305,6 +360,7 @@ void ThreeStrikesBattle::update(float dt)
|
|||||||
WorldWithRank::update(dt);
|
WorldWithRank::update(dt);
|
||||||
WorldWithRank::updateTrack(dt);
|
WorldWithRank::updateTrack(dt);
|
||||||
|
|
||||||
|
spawnSpareTireKarts();
|
||||||
if (m_track->hasNavMesh())
|
if (m_track->hasNavMesh())
|
||||||
updateSectorForKarts();
|
updateSectorForKarts();
|
||||||
|
|
||||||
@ -446,7 +502,7 @@ bool ThreeStrikesBattle::isRaceOver()
|
|||||||
return (irr_driver->getRealTime()-m_start_time)*0.001f > 20.0f;
|
return (irr_driver->getRealTime()-m_start_time)*0.001f > 20.0f;
|
||||||
|
|
||||||
// for tests : never over when we have a single player there :)
|
// for tests : never over when we have a single player there :)
|
||||||
if (race_manager->getNumberOfKarts()==1 &&
|
if (race_manager->getNumberOfKarts() - m_spare_tire_karts.size () ==1 &&
|
||||||
getCurrentNumKarts()==1 &&
|
getCurrentNumKarts()==1 &&
|
||||||
UserConfigParams::m_artist_debug_mode)
|
UserConfigParams::m_artist_debug_mode)
|
||||||
{
|
{
|
||||||
@ -509,6 +565,16 @@ void ThreeStrikesBattle::enterRaceOverState()
|
|||||||
{
|
{
|
||||||
WorldWithRank::enterRaceOverState();
|
WorldWithRank::enterRaceOverState();
|
||||||
|
|
||||||
|
// Unspawn all spare tire karts if neccesary
|
||||||
|
for (unsigned int i = 0; i < m_spare_tire_karts.size(); i++)
|
||||||
|
{
|
||||||
|
SpareTireAI* sta =
|
||||||
|
dynamic_cast<SpareTireAI*>(m_spare_tire_karts[i]->getController());
|
||||||
|
assert(sta);
|
||||||
|
if (sta->isMoving())
|
||||||
|
sta->unspawn();
|
||||||
|
}
|
||||||
|
|
||||||
if (UserConfigParams::m_arena_ai_stats)
|
if (UserConfigParams::m_arena_ai_stats)
|
||||||
{
|
{
|
||||||
float runtime = (irr_driver->getRealTime()-m_start_time)*0.001f;
|
float runtime = (irr_driver->getRealTime()-m_start_time)*0.001f;
|
||||||
@ -521,3 +587,164 @@ void ThreeStrikesBattle::enterRaceOverState()
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // enterRaceOverState
|
} // enterRaceOverState
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool ThreeStrikesBattle::spareTireKartsSpawned() const
|
||||||
|
{
|
||||||
|
if (m_spare_tire_karts.empty()) return false;
|
||||||
|
|
||||||
|
// Spare tire karts are spawned if at least 1 of them needs update
|
||||||
|
SpareTireAI* sta =
|
||||||
|
dynamic_cast<SpareTireAI*>(m_spare_tire_karts[0]->getController());
|
||||||
|
assert(sta);
|
||||||
|
|
||||||
|
return sta->isMoving();
|
||||||
|
} // spareTireKartsSpawned
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void ThreeStrikesBattle::addKartLife(unsigned int id)
|
||||||
|
{
|
||||||
|
m_kart_info[id].m_lives++;
|
||||||
|
updateKartRanks();
|
||||||
|
|
||||||
|
scene::ISceneNode* kart_node = m_karts[id]->getNode();
|
||||||
|
core::list<scene::ISceneNode*>& children =
|
||||||
|
const_cast<core::list<scene::ISceneNode*>&>(kart_node->getChildren());
|
||||||
|
for (core::list<scene::ISceneNode*>::Iterator it = children.begin();
|
||||||
|
it != children.end(); it++)
|
||||||
|
{
|
||||||
|
scene::ISceneNode* curr = *it;
|
||||||
|
if (core::stringc(curr->getName()) == "tire1")
|
||||||
|
{
|
||||||
|
curr->setVisible(m_kart_info[id].m_lives >= 3);
|
||||||
|
}
|
||||||
|
else if (core::stringc(curr->getName()) == "tire2")
|
||||||
|
{
|
||||||
|
curr->setVisible(m_kart_info[id].m_lives >= 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // addKartLife
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void ThreeStrikesBattle::spawnSpareTireKarts()
|
||||||
|
{
|
||||||
|
if (m_spare_tire_karts.empty() ||
|
||||||
|
getTimeSinceStart() < m_next_sta_spawn_time)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const float period =
|
||||||
|
race_manager->getDifficulty() == RaceManager::DIFFICULTY_BEST ? 40.0f :
|
||||||
|
race_manager->getDifficulty() == RaceManager::DIFFICULTY_HARD ? 30.0f :
|
||||||
|
race_manager->getDifficulty() == RaceManager::DIFFICULTY_MEDIUM ?
|
||||||
|
25.0f : 20.0f;
|
||||||
|
const float inc_factor =
|
||||||
|
race_manager->getDifficulty() == RaceManager::DIFFICULTY_BEST ? 0.7f :
|
||||||
|
race_manager->getDifficulty() == RaceManager::DIFFICULTY_HARD ? 0.65f :
|
||||||
|
race_manager->getDifficulty() == RaceManager::DIFFICULTY_MEDIUM ?
|
||||||
|
0.6f : 0.55f;
|
||||||
|
|
||||||
|
// Spawn spare tire kart when necessary
|
||||||
|
// The lifespan for sta: inc_factor / period * 1000 / 2
|
||||||
|
// So in easier mode the sta lasts longer than spawn period
|
||||||
|
const float lifespan = inc_factor / period * 1000;
|
||||||
|
m_next_sta_spawn_time = lifespan + (getTimeSinceStart() * inc_factor) +
|
||||||
|
getTimeSinceStart();
|
||||||
|
int kart_has_few_lives = 0;
|
||||||
|
for (unsigned int i = 0; i < m_kart_info.size(); i++)
|
||||||
|
{
|
||||||
|
if (m_kart_info[i].m_lives > 0 && m_kart_info[i].m_lives < 3)
|
||||||
|
kart_has_few_lives++;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ratio = kart_has_few_lives / (inc_factor * 2);
|
||||||
|
if (ratio < 1.5f) return;
|
||||||
|
unsigned int spawn_sta = unsigned(ratio);
|
||||||
|
if (spawn_sta > m_spare_tire_karts.size())
|
||||||
|
spawn_sta = m_spare_tire_karts.size();
|
||||||
|
m_race_gui->addMessage(_P("%i spare tire kart has been spawned!",
|
||||||
|
"%i spare tire karts have been spawned!",
|
||||||
|
spawn_sta), NULL, 2.0f);
|
||||||
|
for (unsigned int i = 0; i < spawn_sta; i++)
|
||||||
|
{
|
||||||
|
SpareTireAI* sta = dynamic_cast<SpareTireAI*>
|
||||||
|
(m_spare_tire_karts[i]->getController());
|
||||||
|
assert(sta);
|
||||||
|
sta->spawn(lifespan);
|
||||||
|
}
|
||||||
|
} // spawnSpareTireKarts
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void ThreeStrikesBattle::loadCustomModels()
|
||||||
|
{
|
||||||
|
// Pre-add spare tire karts if there are more than certain number of karts
|
||||||
|
ArenaGraph* ag = ArenaGraph::get();
|
||||||
|
if (ag && m_karts.size() > 4)
|
||||||
|
{
|
||||||
|
// Spare tire karts only added with large arena
|
||||||
|
const int all_nodes = ag->getNumNodes();
|
||||||
|
if (all_nodes > 500)
|
||||||
|
{
|
||||||
|
// Don't create too many spare tire karts
|
||||||
|
const unsigned int max_sta_num = unsigned(m_karts.size() * 0.8f);
|
||||||
|
unsigned int pos_created = 0;
|
||||||
|
std::vector<int> used;
|
||||||
|
std::vector<btTransform> pos;
|
||||||
|
|
||||||
|
// Fill all current starting position into used first
|
||||||
|
for (unsigned int i = 0; i < getNumberOfRescuePositions(); i++)
|
||||||
|
{
|
||||||
|
int node = -1;
|
||||||
|
ag->findRoadSector(getRescueTransform(i).getOrigin(), &node,
|
||||||
|
NULL, true);
|
||||||
|
assert(node != -1);
|
||||||
|
used.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find random nodes to pre-spawn spare tire karts
|
||||||
|
RandomGenerator random;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
const int node = random.get(all_nodes);
|
||||||
|
if (std::find(used.begin(), used.end(), node) != used.end())
|
||||||
|
continue;
|
||||||
|
const ArenaNode* n = ag->getNode(node);
|
||||||
|
btTransform t;
|
||||||
|
t.setOrigin(n->getCenter());
|
||||||
|
t.setRotation(Track::createRotationFromNormal(n->getNormal()));
|
||||||
|
pos.push_back(t);
|
||||||
|
pos_created++;
|
||||||
|
used.push_back(node);
|
||||||
|
if (pos_created >= max_sta_num) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute a random kart list
|
||||||
|
std::vector<std::string> sta_list;
|
||||||
|
kart_properties_manager->getRandomKartList(pos.size(), NULL,
|
||||||
|
&sta_list);
|
||||||
|
|
||||||
|
assert(sta_list.size() == pos.size());
|
||||||
|
// Now add them
|
||||||
|
for (unsigned int i = 0; i < pos.size(); i++)
|
||||||
|
{
|
||||||
|
AbstractKart* sta = new Kart(sta_list[i], m_karts.size(),
|
||||||
|
m_karts.size() + 1, pos[i], PLAYER_DIFFICULTY_NORMAL,
|
||||||
|
KRT_RED);
|
||||||
|
sta->init(RaceManager::KartType::KT_SPARE_TIRE);
|
||||||
|
sta->setController(new SpareTireAI(sta));
|
||||||
|
|
||||||
|
m_karts.push_back(sta);
|
||||||
|
race_manager->addSpareTireKart(sta_list[i]);
|
||||||
|
m_track->adjustForFog(sta->getNode());
|
||||||
|
|
||||||
|
// Copy STA pointer to m_spare_tire_karts array, allowing them
|
||||||
|
// to respawn easily
|
||||||
|
m_spare_tire_karts.push_back(sta);
|
||||||
|
}
|
||||||
|
unsigned int sta_num = race_manager->getNumSpareTireKarts();
|
||||||
|
assert(m_spare_tire_karts.size() == sta_num);
|
||||||
|
Log::info("ThreeStrikesBattle","%d spare tire kart(s) created.",
|
||||||
|
sta_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // loadCustomModels
|
||||||
|
@ -77,44 +77,63 @@ private:
|
|||||||
int m_start_time;
|
int m_start_time;
|
||||||
int m_total_hit;
|
int m_total_hit;
|
||||||
|
|
||||||
public:
|
std::vector<AbstractKart*> m_spare_tire_karts;
|
||||||
|
float m_next_sta_spawn_time;
|
||||||
|
|
||||||
|
public:
|
||||||
/** Used to show a nice graph when battle is over */
|
/** Used to show a nice graph when battle is over */
|
||||||
struct BattleEvent
|
struct BattleEvent
|
||||||
{
|
{
|
||||||
float m_time;
|
float m_time;
|
||||||
std::vector<BattleInfo> m_kart_info;
|
std::vector<BattleInfo> m_kart_info;
|
||||||
};
|
};
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
std::vector<BattleEvent> m_battle_events;
|
std::vector<BattleEvent> m_battle_events;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
ThreeStrikesBattle();
|
ThreeStrikesBattle();
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
virtual ~ThreeStrikesBattle();
|
virtual ~ThreeStrikesBattle();
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
virtual void init() OVERRIDE;
|
virtual void init() OVERRIDE;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
// clock events
|
// clock events
|
||||||
virtual bool isRaceOver() OVERRIDE;
|
virtual bool isRaceOver() OVERRIDE;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
virtual void terminateRace() OVERRIDE;
|
virtual void terminateRace() OVERRIDE;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
// overriding World methods
|
// overriding World methods
|
||||||
virtual void reset() OVERRIDE;
|
virtual void reset() OVERRIDE;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
//virtual void getDefaultCollectibles(int& collectible_type, int& amount);
|
|
||||||
virtual bool useFastMusicNearEnd() const OVERRIDE { return false; }
|
|
||||||
virtual void getKartsDisplayInfo(
|
virtual void getKartsDisplayInfo(
|
||||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
|
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
|
||||||
virtual bool raceHasLaps() OVERRIDE { return false; }
|
// ------------------------------------------------------------------------
|
||||||
|
virtual bool raceHasLaps() OVERRIDE { return false; }
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
virtual const std::string& getIdent() const OVERRIDE;
|
virtual const std::string& getIdent() const OVERRIDE;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
virtual void kartHit(const unsigned int kart_id) OVERRIDE;
|
virtual void kartHit(const unsigned int kart_id) OVERRIDE;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
virtual void update(float dt) OVERRIDE;
|
virtual void update(float dt) OVERRIDE;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
virtual void kartAdded(AbstractKart* kart, scene::ISceneNode* node) OVERRIDE;
|
virtual void kartAdded(AbstractKart* kart, scene::ISceneNode* node)
|
||||||
|
OVERRIDE;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
virtual void enterRaceOverState() OVERRIDE;
|
virtual void enterRaceOverState() OVERRIDE;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
virtual void loadCustomModels() OVERRIDE;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
void updateKartRanks();
|
void updateKartRanks();
|
||||||
void increaseRescueCount() { m_total_rescue++; }
|
// ------------------------------------------------------------------------
|
||||||
|
void increaseRescueCount() { m_total_rescue++; }
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
void addKartLife(unsigned int id);
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
int getKartLife(unsigned int id) const { return m_kart_info[id].m_lives; }
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
bool spareTireKartsSpawned() const;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
void spawnSpareTireKarts();
|
||||||
|
|
||||||
}; // ThreeStrikesBattles
|
}; // ThreeStrikesBattles
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "karts/controller/end_controller.hpp"
|
#include "karts/controller/end_controller.hpp"
|
||||||
#include "karts/controller/local_player_controller.hpp"
|
#include "karts/controller/local_player_controller.hpp"
|
||||||
#include "karts/controller/skidding_ai.hpp"
|
#include "karts/controller/skidding_ai.hpp"
|
||||||
|
#include "karts/controller/spare_tire_ai.hpp"
|
||||||
#include "karts/controller/test_ai.hpp"
|
#include "karts/controller/test_ai.hpp"
|
||||||
#include "karts/controller/network_player_controller.hpp"
|
#include "karts/controller/network_player_controller.hpp"
|
||||||
#include "karts/kart.hpp"
|
#include "karts/kart.hpp"
|
||||||
@ -220,13 +221,16 @@ void World::init()
|
|||||||
|
|
||||||
} // for i
|
} // for i
|
||||||
|
|
||||||
|
// Load other custom models if needed
|
||||||
|
loadCustomModels();
|
||||||
|
|
||||||
// Now that all models are loaded, apply the overrides
|
// Now that all models are loaded, apply the overrides
|
||||||
irr_driver->applyObjectPassShader();
|
irr_driver->applyObjectPassShader();
|
||||||
|
|
||||||
// Must be called after all karts are created
|
// Must be called after all karts are created
|
||||||
m_race_gui->init();
|
m_race_gui->init();
|
||||||
|
|
||||||
powerup_manager->updateWeightsForRace(num_karts);
|
powerup_manager->updateWeightsForRace(race_manager->getNumberOfKarts());
|
||||||
|
|
||||||
if (UserConfigParams::m_weather_effects)
|
if (UserConfigParams::m_weather_effects)
|
||||||
{
|
{
|
||||||
@ -368,6 +372,8 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
|
|||||||
break;
|
break;
|
||||||
case RaceManager::KT_LEADER:
|
case RaceManager::KT_LEADER:
|
||||||
break;
|
break;
|
||||||
|
case RaceManager::KT_SPARE_TIRE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_kart->setController(controller);
|
new_kart->setController(controller);
|
||||||
@ -477,6 +483,7 @@ World::~World()
|
|||||||
race_manager->setRecordRace(false);
|
race_manager->setRecordRace(false);
|
||||||
race_manager->setWatchingReplay(false);
|
race_manager->setWatchingReplay(false);
|
||||||
race_manager->setTimeTarget(0.0f);
|
race_manager->setTimeTarget(0.0f);
|
||||||
|
race_manager->setSpareTireKartNum(0);
|
||||||
|
|
||||||
Camera::removeAllCameras();
|
Camera::removeAllCameras();
|
||||||
|
|
||||||
@ -973,8 +980,11 @@ void World::update(float dt)
|
|||||||
const int kart_amount = (int)m_karts.size();
|
const int kart_amount = (int)m_karts.size();
|
||||||
for (int i = 0 ; i < kart_amount; ++i)
|
for (int i = 0 ; i < kart_amount; ++i)
|
||||||
{
|
{
|
||||||
|
SpareTireAI* sta =
|
||||||
|
dynamic_cast<SpareTireAI*>(m_karts[i]->getController());
|
||||||
// Update all karts that are not eliminated
|
// Update all karts that are not eliminated
|
||||||
if(!m_karts[i]->isEliminated()) m_karts[i]->update(dt) ;
|
if(!m_karts[i]->isEliminated() || (sta && sta->isMoving()))
|
||||||
|
m_karts[i]->update(dt);
|
||||||
}
|
}
|
||||||
PROFILER_POP_CPU_MARKER();
|
PROFILER_POP_CPU_MARKER();
|
||||||
|
|
||||||
|
@ -360,6 +360,8 @@ public:
|
|||||||
void delayedSelfDestruct();
|
void delayedSelfDestruct();
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
virtual void escapePressed();
|
virtual void escapePressed();
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
virtual void loadCustomModels() {}
|
||||||
|
|
||||||
/** Set the network mode (true if networked) */
|
/** Set the network mode (true if networked) */
|
||||||
void setNetworkWorld(bool is_networked) { m_is_network_world = is_networked; }
|
void setNetworkWorld(bool is_networked) { m_is_network_world = is_networked; }
|
||||||
|
@ -199,7 +199,8 @@ void WorldStatus::updateTime(const float dt)
|
|||||||
m_auxiliary_timer += dt;
|
m_auxiliary_timer += dt;
|
||||||
|
|
||||||
if (UserConfigParams::m_artist_debug_mode &&
|
if (UserConfigParams::m_artist_debug_mode &&
|
||||||
race_manager->getNumberOfKarts() == 1 &&
|
race_manager->getNumberOfKarts() -
|
||||||
|
race_manager->getNumSpareTireKarts() == 1 &&
|
||||||
race_manager->getTrackName() != "tutorial")
|
race_manager->getTrackName() != "tutorial")
|
||||||
{
|
{
|
||||||
m_auxiliary_timer += dt * 6;
|
m_auxiliary_timer += dt * 6;
|
||||||
@ -276,7 +277,8 @@ void WorldStatus::updateTime(const float dt)
|
|||||||
// In artist debug mode, when without opponents, skip the
|
// In artist debug mode, when without opponents, skip the
|
||||||
// ready/set/go counter faster
|
// ready/set/go counter faster
|
||||||
if (UserConfigParams::m_artist_debug_mode &&
|
if (UserConfigParams::m_artist_debug_mode &&
|
||||||
race_manager->getNumberOfKarts() == 1 &&
|
race_manager->getNumberOfKarts() -
|
||||||
|
race_manager->getNumSpareTireKarts() == 1 &&
|
||||||
race_manager->getTrackName() != "tutorial")
|
race_manager->getTrackName() != "tutorial")
|
||||||
{
|
{
|
||||||
m_auxiliary_timer += dt*6;
|
m_auxiliary_timer += dt*6;
|
||||||
@ -302,7 +304,8 @@ void WorldStatus::updateTime(const float dt)
|
|||||||
// In artist debug mode, when without opponents,
|
// In artist debug mode, when without opponents,
|
||||||
// skip the ready/set/go counter faster
|
// skip the ready/set/go counter faster
|
||||||
if (UserConfigParams::m_artist_debug_mode &&
|
if (UserConfigParams::m_artist_debug_mode &&
|
||||||
race_manager->getNumberOfKarts() == 1 &&
|
race_manager->getNumberOfKarts() -
|
||||||
|
race_manager->getNumSpareTireKarts() == 1 &&
|
||||||
race_manager->getTrackName() != "tutorial")
|
race_manager->getTrackName() != "tutorial")
|
||||||
{
|
{
|
||||||
m_auxiliary_timer += dt*6;
|
m_auxiliary_timer += dt*6;
|
||||||
@ -327,7 +330,8 @@ void WorldStatus::updateTime(const float dt)
|
|||||||
// In artist debug mode, when without opponents,
|
// In artist debug mode, when without opponents,
|
||||||
// skip the ready/set/go counter faster
|
// skip the ready/set/go counter faster
|
||||||
if (UserConfigParams::m_artist_debug_mode &&
|
if (UserConfigParams::m_artist_debug_mode &&
|
||||||
race_manager->getNumberOfKarts() == 1 &&
|
race_manager->getNumberOfKarts() -
|
||||||
|
race_manager->getNumSpareTireKarts() == 1 &&
|
||||||
race_manager->getTrackName() != "tutorial")
|
race_manager->getTrackName() != "tutorial")
|
||||||
{
|
{
|
||||||
m_auxiliary_timer += dt*6;
|
m_auxiliary_timer += dt*6;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "modes/world_with_rank.hpp"
|
#include "modes/world_with_rank.hpp"
|
||||||
|
|
||||||
#include "karts/abstract_kart.hpp"
|
#include "karts/abstract_kart.hpp"
|
||||||
|
#include "karts/controller/spare_tire_ai.hpp"
|
||||||
#include "karts/kart_properties.hpp"
|
#include "karts/kart_properties.hpp"
|
||||||
#include "race/history.hpp"
|
#include "race/history.hpp"
|
||||||
#include "tracks/graph.hpp"
|
#include "tracks/graph.hpp"
|
||||||
@ -251,7 +252,9 @@ void WorldWithRank::updateSectorForKarts()
|
|||||||
assert(n == m_kart_track_sector.size());
|
assert(n == m_kart_track_sector.size());
|
||||||
for (unsigned int i = 0; i < n; i++)
|
for (unsigned int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
if (m_karts[i]->isEliminated()) continue;
|
SpareTireAI* sta =
|
||||||
getTrackSector(i)->update(m_karts[i]->getXYZ());
|
dynamic_cast<SpareTireAI*>(m_karts[i]->getController());
|
||||||
|
if (!m_karts[i]->isEliminated() || (sta && sta->isMoving()))
|
||||||
|
getTrackSector(i)->update(m_karts[i]->getXYZ());
|
||||||
}
|
}
|
||||||
} // updateSectorForKarts
|
} // updateSectorForKarts
|
||||||
|
@ -84,6 +84,7 @@ RaceManager::RaceManager()
|
|||||||
setTrack("jungle");
|
setTrack("jungle");
|
||||||
m_default_ai_list.clear();
|
m_default_ai_list.clear();
|
||||||
setNumPlayers(0);
|
setNumPlayers(0);
|
||||||
|
setSpareTireKartNum(0);
|
||||||
} // RaceManager
|
} // RaceManager
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -288,7 +289,7 @@ void RaceManager::computeRandomKartList()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(n>0)
|
if(n>0)
|
||||||
kart_properties_manager->getRandomKartList(n, m_player_karts,
|
kart_properties_manager->getRandomKartList(n, &m_player_karts,
|
||||||
&m_ai_kart_list );
|
&m_ai_kart_list );
|
||||||
|
|
||||||
if (m_ai_kart_override != "")
|
if (m_ai_kart_override != "")
|
||||||
|
@ -236,9 +236,10 @@ public:
|
|||||||
DIFFICULTY_COUNT};
|
DIFFICULTY_COUNT};
|
||||||
|
|
||||||
/** Different kart types: A local player, a player connected via network,
|
/** Different kart types: A local player, a player connected via network,
|
||||||
* an AI kart, the leader kart (currently not used), a ghost kart. */
|
* an AI kart, the leader kart (currently not used), a ghost kart and
|
||||||
|
* spare tire karts which allow gain life in battle mode */
|
||||||
enum KartType { KT_PLAYER, KT_NETWORK_PLAYER, KT_AI, KT_LEADER,
|
enum KartType { KT_PLAYER, KT_NETWORK_PLAYER, KT_AI, KT_LEADER,
|
||||||
KT_GHOST };
|
KT_GHOST, KT_SPARE_TIRE };
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_started_from_overworld;
|
bool m_started_from_overworld;
|
||||||
@ -329,6 +330,7 @@ private:
|
|||||||
GrandPrixData m_grand_prix;
|
GrandPrixData m_grand_prix;
|
||||||
SavedGrandPrix* m_saved_gp;
|
SavedGrandPrix* m_saved_gp;
|
||||||
int m_num_karts;
|
int m_num_karts;
|
||||||
|
unsigned int m_num_spare_tire_karts;
|
||||||
unsigned int m_num_finished_karts;
|
unsigned int m_num_finished_karts;
|
||||||
unsigned int m_num_finished_players;
|
unsigned int m_num_finished_players;
|
||||||
int m_coin_target;
|
int m_coin_target;
|
||||||
@ -751,6 +753,24 @@ public:
|
|||||||
{
|
{
|
||||||
return m_watching_replay;
|
return m_watching_replay;
|
||||||
} // isWatchingReplay
|
} // isWatchingReplay
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
void addSpareTireKart(const std::string& name)
|
||||||
|
{
|
||||||
|
m_kart_status.push_back(KartStatus(name, 0, -1, -1,
|
||||||
|
-1, KT_SPARE_TIRE, PLAYER_DIFFICULTY_NORMAL));
|
||||||
|
m_num_spare_tire_karts++;
|
||||||
|
m_num_karts++;
|
||||||
|
} // addSpareTireKart
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
void setSpareTireKartNum(unsigned int i)
|
||||||
|
{
|
||||||
|
m_num_spare_tire_karts = i;
|
||||||
|
} // setSpareTireKartNum
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
unsigned int getNumSpareTireKarts() const
|
||||||
|
{
|
||||||
|
return m_num_spare_tire_karts;
|
||||||
|
} // getNumSpareTireKarts
|
||||||
|
|
||||||
}; // RaceManager
|
}; // RaceManager
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ using namespace irr;
|
|||||||
#include "items/attachment_manager.hpp"
|
#include "items/attachment_manager.hpp"
|
||||||
#include "items/powerup_manager.hpp"
|
#include "items/powerup_manager.hpp"
|
||||||
#include "karts/abstract_kart.hpp"
|
#include "karts/abstract_kart.hpp"
|
||||||
#include "karts/controller/controller.hpp"
|
#include "karts/controller/spare_tire_ai.hpp"
|
||||||
#include "karts/kart_properties.hpp"
|
#include "karts/kart_properties.hpp"
|
||||||
#include "karts/kart_properties_manager.hpp"
|
#include "karts/kart_properties_manager.hpp"
|
||||||
#include "modes/follow_the_leader.hpp"
|
#include "modes/follow_the_leader.hpp"
|
||||||
@ -104,6 +104,18 @@ RaceGUI::RaceGUI()
|
|||||||
else
|
else
|
||||||
m_lap_width = font->getDimension(L"9/9").Width;
|
m_lap_width = font->getDimension(L"9/9").Width;
|
||||||
|
|
||||||
|
} // RaceGUI
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
RaceGUI::~RaceGUI()
|
||||||
|
{
|
||||||
|
} // ~Racegui
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void RaceGUI::init()
|
||||||
|
{
|
||||||
|
RaceGUIBase::init();
|
||||||
// Technically we only need getNumLocalPlayers, but using the
|
// Technically we only need getNumLocalPlayers, but using the
|
||||||
// global kart id to find the data for a specific kart.
|
// global kart id to find the data for a specific kart.
|
||||||
int n = race_manager->getNumberOfKarts();
|
int n = race_manager->getNumberOfKarts();
|
||||||
@ -111,12 +123,7 @@ RaceGUI::RaceGUI()
|
|||||||
m_animation_states.resize(n);
|
m_animation_states.resize(n);
|
||||||
m_rank_animation_duration.resize(n);
|
m_rank_animation_duration.resize(n);
|
||||||
m_last_ranks.resize(n);
|
m_last_ranks.resize(n);
|
||||||
} // RaceGUI
|
} // init
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
RaceGUI::~RaceGUI()
|
|
||||||
{
|
|
||||||
} // ~Racegui
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
/** Reset the gui before a race. It initialised all rank animation related
|
/** Reset the gui before a race. It initialised all rank animation related
|
||||||
@ -369,13 +376,18 @@ void RaceGUI::drawGlobalMiniMap()
|
|||||||
for(unsigned int i=0; i<world->getNumKarts(); i++)
|
for(unsigned int i=0; i<world->getNumKarts(); i++)
|
||||||
{
|
{
|
||||||
const AbstractKart *kart = world->getKart(i);
|
const AbstractKart *kart = world->getKart(i);
|
||||||
if(kart->isEliminated()) continue; // don't draw eliminated kart
|
const SpareTireAI* sta =
|
||||||
|
dynamic_cast<const SpareTireAI*>(kart->getController());
|
||||||
|
// don't draw eliminated kart
|
||||||
|
if(kart->isEliminated() && !(sta && sta->isMoving())) continue;
|
||||||
const Vec3& xyz = kart->getXYZ();
|
const Vec3& xyz = kart->getXYZ();
|
||||||
Vec3 draw_at;
|
Vec3 draw_at;
|
||||||
world->getTrack()->mapPoint2MiniMap(xyz, &draw_at);
|
world->getTrack()->mapPoint2MiniMap(xyz, &draw_at);
|
||||||
draw_at *= UserConfigParams::m_scale_rtts_factor;
|
draw_at *= UserConfigParams::m_scale_rtts_factor;
|
||||||
|
|
||||||
video::ITexture* icon = kart->getKartProperties()->getMinimapIcon();
|
video::ITexture* icon = sta ?
|
||||||
|
irr_driver->getTexture(FileManager::GUI, "heart.png") :
|
||||||
|
kart->getKartProperties()->getMinimapIcon();
|
||||||
|
|
||||||
// int marker_height = m_marker->getSize().Height;
|
// int marker_height = m_marker->getSize().Height;
|
||||||
core::rect<s32> source(core::position2di(0, 0), icon->getSize());
|
core::rect<s32> source(core::position2di(0, 0), icon->getSize());
|
||||||
|
@ -119,6 +119,7 @@ public:
|
|||||||
|
|
||||||
RaceGUI();
|
RaceGUI();
|
||||||
~RaceGUI();
|
~RaceGUI();
|
||||||
|
virtual void init();
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
virtual void renderGlobal(float dt);
|
virtual void renderGlobal(float dt);
|
||||||
virtual void renderPlayerView(const Camera *camera, float dt);
|
virtual void renderPlayerView(const Camera *camera, float dt);
|
||||||
|
@ -638,8 +638,11 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
|
|||||||
y_space = irr_driver->getActualScreenSize().Height - y_base;
|
y_space = irr_driver->getActualScreenSize().Height - y_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int sta = race_manager->getNumSpareTireKarts();
|
||||||
|
const unsigned int num_karts = race_manager->getNumberOfKarts() - sta;
|
||||||
|
|
||||||
// -2 because that's the spacing further on
|
// -2 because that's the spacing further on
|
||||||
int ICON_PLAYER_WIDTH = y_space / race_manager->getNumberOfKarts() - 2;
|
int ICON_PLAYER_WIDTH = y_space / num_karts - 2;
|
||||||
|
|
||||||
int icon_width_max = (int)(50*(irr_driver->getActualScreenSize().Width/800.0f));
|
int icon_width_max = (int)(50*(irr_driver->getActualScreenSize().Width/800.0f));
|
||||||
int icon_width_min = (int)(35*(irr_driver->getActualScreenSize().Height/600.0f));
|
int icon_width_min = (int)(35*(irr_driver->getActualScreenSize().Height/600.0f));
|
||||||
@ -664,10 +667,11 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
|
|||||||
int ICON_WIDTH = ICON_PLAYER_WIDTH * 4 / 5;
|
int ICON_WIDTH = ICON_PLAYER_WIDTH * 4 / 5;
|
||||||
|
|
||||||
WorldWithRank *world = (WorldWithRank*)(World::getWorld());
|
WorldWithRank *world = (WorldWithRank*)(World::getWorld());
|
||||||
|
|
||||||
//initialize m_previous_icons_position
|
//initialize m_previous_icons_position
|
||||||
if(m_previous_icons_position.size()==0)
|
if(m_previous_icons_position.size()==0)
|
||||||
{
|
{
|
||||||
for(unsigned int i=0; i<race_manager->getNumberOfKarts(); i++)
|
for(unsigned int i=0; i<num_karts; i++)
|
||||||
{
|
{
|
||||||
const AbstractKart *kart = world->getKart(i);
|
const AbstractKart *kart = world->getKart(i);
|
||||||
int position = kart->getPosition();
|
int position = kart->getPosition();
|
||||||
@ -686,7 +690,7 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
|
|||||||
int previous_y=y_base-ICON_PLAYER_WIDTH-2;
|
int previous_y=y_base-ICON_PLAYER_WIDTH-2;
|
||||||
|
|
||||||
gui::ScalableFont* font = GUIEngine::getFont();
|
gui::ScalableFont* font = GUIEngine::getFont();
|
||||||
const unsigned int kart_amount = world->getNumKarts();
|
const unsigned int kart_amount = world->getNumKarts() - sta;
|
||||||
|
|
||||||
//where is the limit to hide last icons
|
//where is the limit to hide last icons
|
||||||
int y_icons_limit=irr_driver->getActualScreenSize().Height-bottom_margin-ICON_PLAYER_WIDTH;
|
int y_icons_limit=irr_driver->getActualScreenSize().Height-bottom_margin-ICON_PLAYER_WIDTH;
|
||||||
|
@ -460,17 +460,17 @@ void RaceResultGUI::backToLobby()
|
|||||||
WorldWithRank *rank_world = (WorldWithRank*)World::getWorld();
|
WorldWithRank *rank_world = (WorldWithRank*)World::getWorld();
|
||||||
|
|
||||||
unsigned int first_position = 1;
|
unsigned int first_position = 1;
|
||||||
|
unsigned int sta = race_manager->getNumSpareTireKarts();
|
||||||
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||||
first_position = 2;
|
first_position = 2;
|
||||||
|
|
||||||
// Use only the karts that are supposed to be displayed (and
|
// Use only the karts that are supposed to be displayed (and
|
||||||
// ignore e.g. the leader in a FTL race).
|
// ignore e.g. the leader in a FTL race).
|
||||||
unsigned int num_karts = race_manager->getNumberOfKarts() - first_position + 1;
|
unsigned int num_karts = race_manager->getNumberOfKarts() - first_position + 1 - sta;
|
||||||
|
|
||||||
// In FTL races the leader kart is not displayed
|
// In FTL races the leader kart is not displayed
|
||||||
m_all_row_infos.resize(num_karts);
|
m_all_row_infos.resize(num_karts);
|
||||||
|
|
||||||
|
|
||||||
// Determine the kart to display in the right order,
|
// Determine the kart to display in the right order,
|
||||||
// and the maximum width for the kart name column
|
// and the maximum width for the kart name column
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
@ -478,7 +478,7 @@ void RaceResultGUI::backToLobby()
|
|||||||
float max_finish_time = 0;
|
float max_finish_time = 0;
|
||||||
|
|
||||||
for (unsigned int position = first_position;
|
for (unsigned int position = first_position;
|
||||||
position <= race_manager->getNumberOfKarts(); position++)
|
position <= race_manager->getNumberOfKarts() - sta; position++)
|
||||||
{
|
{
|
||||||
const AbstractKart *kart = rank_world->getKartAtPosition(position);
|
const AbstractKart *kart = rank_world->getKartAtPosition(position);
|
||||||
|
|
||||||
|
@ -44,6 +44,8 @@ ArenaGraph::ArenaGraph(const std::string &navmesh, const XMLNode *node)
|
|||||||
if (node && race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
|
if (node && race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
|
||||||
loadGoalNodes(node);
|
loadGoalNodes(node);
|
||||||
|
|
||||||
|
loadBoundingBoxNodes();
|
||||||
|
|
||||||
} // ArenaGraph
|
} // ArenaGraph
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -240,6 +240,8 @@ void DriveGraph::load(const std::string &quad_file_name,
|
|||||||
m_lap_length = l;
|
m_lap_length = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadBoundingBoxNodes();
|
||||||
|
|
||||||
} // load
|
} // load
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -46,6 +46,7 @@ Graph::Graph()
|
|||||||
m_new_rtt = NULL;
|
m_new_rtt = NULL;
|
||||||
m_bb_min = Vec3( 99999, 99999, 99999);
|
m_bb_min = Vec3( 99999, 99999, 99999);
|
||||||
m_bb_max = Vec3(-99999, -99999, -99999);
|
m_bb_max = Vec3(-99999, -99999, -99999);
|
||||||
|
memset(m_bb_nodes, 0, 4 * sizeof(int));
|
||||||
} // Graph
|
} // Graph
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -621,3 +622,16 @@ int Graph::findOutOfRoadSector(const Vec3& xyz, const int curr_sector,
|
|||||||
}
|
}
|
||||||
return min_sector;
|
return min_sector;
|
||||||
} // findOutOfRoadSector
|
} // findOutOfRoadSector
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void Graph::loadBoundingBoxNodes()
|
||||||
|
{
|
||||||
|
m_bb_nodes[0] = findOutOfRoadSector(Vec3(m_bb_min.x(), 0, m_bb_min.z()),
|
||||||
|
-1/*curr_sector*/, NULL/*all_sectors*/, true/*ignore_vertical*/);
|
||||||
|
m_bb_nodes[1] = findOutOfRoadSector(Vec3(m_bb_min.x(), 0, m_bb_max.z()),
|
||||||
|
-1/*curr_sector*/, NULL/*all_sectors*/, true/*ignore_vertical*/);
|
||||||
|
m_bb_nodes[2] = findOutOfRoadSector(Vec3(m_bb_max.x(), 0, m_bb_min.z()),
|
||||||
|
-1/*curr_sector*/, NULL/*all_sectors*/, true/*ignore_vertical*/);
|
||||||
|
m_bb_nodes[3] = findOutOfRoadSector(Vec3(m_bb_max.x(), 0, m_bb_max.z()),
|
||||||
|
-1/*curr_sector*/, NULL/*all_sectors*/, true/*ignore_vertical*/);
|
||||||
|
} // loadBoundingBoxNodes
|
||||||
|
@ -62,12 +62,18 @@ protected:
|
|||||||
void createQuad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
|
void createQuad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
|
||||||
const Vec3 &p3, unsigned int node_index,
|
const Vec3 &p3, unsigned int node_index,
|
||||||
bool invisible, bool ai_ignore, bool is_arena, bool ignore);
|
bool invisible, bool ai_ignore, bool is_arena, bool ignore);
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
/** Map 4 bounding box points to 4 closest graph nodes. */
|
||||||
|
void loadBoundingBoxNodes();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** The 2d bounding box, used for hashing. */
|
/** The 2d bounding box, used for hashing. */
|
||||||
Vec3 m_bb_min;
|
Vec3 m_bb_min;
|
||||||
Vec3 m_bb_max;
|
Vec3 m_bb_max;
|
||||||
|
|
||||||
|
/** The 4 closest graph nodes to the bounding box. */
|
||||||
|
int m_bb_nodes[4];
|
||||||
|
|
||||||
RTT* m_new_rtt;
|
RTT* m_new_rtt;
|
||||||
|
|
||||||
/** The node of the graph mesh. */
|
/** The node of the graph mesh. */
|
||||||
@ -149,6 +155,12 @@ public:
|
|||||||
const int curr_sector = UNKNOWN_SECTOR,
|
const int curr_sector = UNKNOWN_SECTOR,
|
||||||
std::vector<int> *all_sectors = NULL,
|
std::vector<int> *all_sectors = NULL,
|
||||||
bool ignore_vertical = false) const;
|
bool ignore_vertical = false) const;
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
const Vec3& getBBMin() const { return m_bb_min; }
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
const Vec3& getBBMax() const { return m_bb_max; }
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
const int* getBBNodes() const { return m_bb_nodes; }
|
||||||
|
|
||||||
}; // Graph
|
}; // Graph
|
||||||
|
|
||||||
|
@ -702,11 +702,7 @@ btQuaternion Track::getArenaStartRotation(const Vec3& xyz, float heading)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Vec3& normal = Graph::get()->getQuad(node)->getNormal();
|
const Vec3& normal = Graph::get()->getQuad(node)->getNormal();
|
||||||
Vec3 axis = -normal.cross(Vec3(0, 1, 0));
|
btQuaternion q = createRotationFromNormal(normal);
|
||||||
if (axis.length() == 0)
|
|
||||||
axis = Vec3(0, 0, 1);
|
|
||||||
|
|
||||||
btQuaternion q(axis, normal.angle(Vec3(0, 1, 0)));
|
|
||||||
btMatrix3x3 m;
|
btMatrix3x3 m;
|
||||||
m.setRotation(q);
|
m.setRotation(q);
|
||||||
return btQuaternion(m.getColumn(1), heading * DEGREE_TO_RAD) * q;
|
return btQuaternion(m.getColumn(1), heading * DEGREE_TO_RAD) * q;
|
||||||
|
@ -397,6 +397,14 @@ public:
|
|||||||
|
|
||||||
static const float NOHIT;
|
static const float NOHIT;
|
||||||
|
|
||||||
|
static btQuaternion createRotationFromNormal(const Vec3& normal)
|
||||||
|
{
|
||||||
|
Vec3 axis = -normal.cross(Vec3(0, 1, 0));
|
||||||
|
if (axis.length() == 0)
|
||||||
|
axis = Vec3(0, 0, 1);
|
||||||
|
return btQuaternion(axis, normal.angle(Vec3(0, 1, 0)));
|
||||||
|
} // createRotationFromNormal
|
||||||
|
|
||||||
Track (const std::string &filename);
|
Track (const std::string &filename);
|
||||||
~Track ();
|
~Track ();
|
||||||
void cleanup ();
|
void cleanup ();
|
||||||
|
@ -182,12 +182,9 @@ void changeCameraTarget(u32 num)
|
|||||||
{
|
{
|
||||||
AbstractKart* kart = world->getKart(num - 1);
|
AbstractKart* kart = world->getKart(num - 1);
|
||||||
if (kart == NULL) return;
|
if (kart == NULL) return;
|
||||||
if (kart->isEliminated()) return;
|
|
||||||
cam->setMode(Camera::CM_NORMAL);
|
cam->setMode(Camera::CM_NORMAL);
|
||||||
cam->setKart(kart);
|
cam->setKart(kart);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return;
|
|
||||||
|
|
||||||
} // changeCameraTarget
|
} // changeCameraTarget
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user