Merge branch 'dev' of github.com:supertuxkart/stk-code into dev

This commit is contained in:
hiker 2018-11-17 22:55:28 +11:00
commit f4b02c096a
34 changed files with 319 additions and 229 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -15,21 +15,21 @@
</div>
</div>
<spacer height="2%"/>
<div x="2%" width="96%" height="fit" layout="horizontal-row">
<box proportion="4" height="fit" layout="vertical-row">
<div x="2%" width="96%" height="18%" layout="horizontal-row">
<box proportion="4" height="100%" layout="vertical-row">
<textbox id="chat" width="100%"/>
<spacer height="10"/>
<spacer height="20%"/>
<div width="100%" height="fit" layout="horizontal-row">
<button id="send" width="20%" height="fit" I18N="In the network lobby" text="Send" />
<spacer width="1%"/>
<label id="timeout-message" width="79%" height="fit"/>
<button id="send" width="20%" height="fit" I18N="In the network lobby" text="Send"/>
<spacer width="3%"/>
<label id="timeout-message" width="79%" height="fit" text="" word_wrap="true" align="center"/>
</div>
</box>
<spacer width="3%"/>
<icon-button id="start" proportion="1" width="64" height="64" icon="gui/icons/green_check.png" align="top"
I18N="In the network lobby" text="Start race"/>
<icon-button id="exit" proportion="1" width="64" height="64" icon="gui/icons/main_quit.png" align="top"
I18N="In the network lobby" text="Exit"/>
<icon-button id="config" proportion="1" width="64" height="64" icon="gui/icons/main_options.png" align="top"
I18N="In the network lobby" text="Server Configuration"/>
</div>
<spacer height="1%"/>
</div>

View File

@ -8,7 +8,7 @@
isn't an item, it is internally
handled as one, so list it here -->
<bubblegum model="bubblegum.spm" lowmodel="bubblegum-low.spm" glow="246 150 209"/>
<bubblegum-nolok model="bubblegum-nolok.spm" lowmodel="bubblegum-nolok-low.spm"/>
<bubblegum-nolok model="bubblegum-nolok.spm" lowmodel="bubblegum-nolok-low.spm" glow="20 190 0"/>
<easter-egg model="easter_egg.spm" glow="0 60 120" />
</items>

View File

@ -350,9 +350,9 @@ void FontWithFace::dumpGlyphPage()
*/
void FontWithFace::setDPI()
{
const int screen_width = irr_driver->getFrameSize().Width;
const int screen_height = irr_driver->getFrameSize().Height;
const int screen_width = irr_driver->getActualScreenSize().Width;
const int screen_height = irr_driver->getActualScreenSize().Height;
if (UserConfigParams::m_hidpi_enabled)
{
float scale = screen_height / 480.0f;

View File

@ -120,7 +120,8 @@ using namespace gui;
virtual void setDrawBackground(bool) { }
void openScreenKeyboard();
s32 getCursorPosInBox() const { return CursorPos; }
s32 getTextCount() const { return (s32)Text.size(); }
protected:
//! Breaks the single text line.
void breakText();

View File

@ -434,8 +434,3 @@ void IconButtonWidget::setVisible(bool visible)
m_label->setVisible(visible);
}
// -----------------------------------------------------------------------------
void IconButtonWidget::setText(const wchar_t *s)
{
m_label->setText(s);
}

View File

@ -170,8 +170,6 @@ namespace GUIEngine
Widget::elementRemoved();
m_label = NULL;
}
// --------------------------------------------------------------------
virtual void setText(const wchar_t *s) OVERRIDE;
};
}

View File

@ -209,3 +209,22 @@ EventPropagation TextBoxWidget::onActivationInput(const int playerID)
// event to avoid breaking something
return EVENT_BLOCK;
}
// -----------------------------------------------------------------------------
EventPropagation TextBoxWidget::rightPressed(const int playerID)
{
if (((MyCGUIEditBox*)m_element)->getTextCount() ==
((MyCGUIEditBox*)m_element)->getCursorPosInBox())
return EVENT_BLOCK;
return EVENT_LET;
} // rightPressed
// -----------------------------------------------------------------------------
EventPropagation TextBoxWidget::leftPressed (const int playerID)
{
if (((MyCGUIEditBox*)m_element)->getCursorPosInBox() == 0)
return EVENT_BLOCK;
return EVENT_LET;
} // leftPressed

View File

@ -77,6 +77,9 @@ namespace GUIEngine
virtual void setActive(bool active=true);
virtual EventPropagation onActivationInput(const int playerID);
virtual EventPropagation rightPressed(const int playerID);
virtual EventPropagation leftPressed (const int playerID);
};
}

View File

@ -653,9 +653,7 @@ void Flyable::restoreState(BareNetworkString *buffer, int count)
m_body->setInterpolationAngularVelocity(av);
setTrans(t);
}
uint16_t hit_and_ticks = buffer->getUInt16();
// Next network version remove ~(1 << 15)
m_ticks_since_thrown = hit_and_ticks & ~(1 << 15);
m_ticks_since_thrown = buffer->getUInt16();
m_has_server_state = true;
} // restoreState

View File

@ -74,10 +74,13 @@ void ItemState::setDisappearCounter()
// -----------------------------------------------------------------------
/** Initialises an item.
* \param type Type for this item.
* \param xyz The position for this item.
* \param normal The normal for this item.
*/
void ItemState::initItem(ItemType type, const Vec3& xyz)
void ItemState::initItem(ItemType type, const Vec3& xyz, const Vec3& normal)
{
m_xyz = xyz;
m_normal = normal;
m_original_type = ITEM_NONE;
m_ticks_till_return = 0;
setDisappearCounter();
@ -133,6 +136,16 @@ void ItemState::collected(const AbstractKart *kart)
}
} // collected
// ----------------------------------------------------------------------------
/** Returns the graphical type of this item should be using (takes nolok into
* account). */
Item::ItemType ItemState::getGrahpicalType() const
{
return m_previous_owner && m_previous_owner->getIdent() == "nolok" &&
getType() == ITEM_BUBBLEGUM ?
ITEM_BUBBLEGUM_NOLOK : getType();
} // getGrahpicalType
// ============================================================================
/** Constructor for an item.
* \param type Type of the item.
@ -156,7 +169,7 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
m_was_available_previously = true;
m_distance_2 = 1.2f;
initItem(type, xyz);
initItem(type, xyz, normal);
m_graphical_type = type;
m_original_rotation = shortestArcQuat(Vec3(0, 1, 0), normal);
m_listener = NULL;
@ -181,7 +194,7 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
}
m_node = lodnode;
setType(type);
handleNewMesh(getType());
handleNewMesh(getGrahpicalType());
#ifdef DEBUG
std::string debug_name("item: ");
@ -206,7 +219,7 @@ Item::Item(const Vec3& xyz, float distance, TriggerItemListener* trigger)
: ItemState(ITEM_TRIGGER)
{
m_distance_2 = distance*distance;
initItem(ITEM_TRIGGER, xyz);
initItem(ITEM_TRIGGER, xyz, /*normal not required*/Vec3(0,0,0));
m_graphical_type = ITEM_TRIGGER;
m_original_rotation = btQuaternion(0, 0, 0, 1);
m_node = NULL;
@ -218,10 +231,12 @@ Item::Item(const Vec3& xyz, float distance, TriggerItemListener* trigger)
/** Initialises the item. Note that m_distance_2 must be defined before calling
* this function, since it pre-computes some values based on this.
* \param type Type of the item.
* \param xyz Position of this item.
* \param normal Normal for this item.
*/
void Item::initItem(ItemType type, const Vec3 &xyz)
void Item::initItem(ItemType type, const Vec3 &xyz, const Vec3&normal)
{
ItemState::initItem(type, xyz);
ItemState::initItem(type, xyz, normal);
// Now determine in which quad this item is, and its distance
// from the center within this quad.
m_graph_node = Graph::UNKNOWN_SECTOR;
@ -345,7 +360,7 @@ void Item::updateGraphics(float dt)
if (m_graphical_type != getType())
{
handleNewMesh(getType());
handleNewMesh(getGrahpicalType());
m_graphical_type = getType();
}

View File

@ -119,10 +119,17 @@ private:
* will always reappear after a while. */
int m_used_up_counter;
/** The original position - saves calls to m_node->getPosition()
* and then converting this value to a Vec3. */
/** The position of this ItemState. */
Vec3 m_xyz;
/** The original rotation of the item. While this is technically a visual
* only value (atm, it could be used for collision detection), it is
* required to make sure a client can display items with the right normal
* (in case that a client would get a different (or no) normal from a
* raycast).
*/
Vec3 m_normal;
/** The 'owner' of the item, i.e. the kart that dropped this item.
* Is NULL if the item is part of the track. */
const AbstractKart *m_previous_owner;
@ -154,7 +161,7 @@ protected:
public:
ItemState(ItemType type, const AbstractKart *owner=NULL, int id = -1);
void initItem(ItemType type, const Vec3& xyz);
void initItem(ItemType type, const Vec3& xyz, const Vec3& normal);
void update(int ticks);
void setDisappearCounter();
virtual void collected(const AbstractKart *kart);
@ -273,6 +280,8 @@ public:
/** Returns the type of this item. */
ItemType getType() const { return m_type; }
// ------------------------------------------------------------------------
ItemType getGrahpicalType() const;
// ------------------------------------------------------------------------
/** Returns the original type of this item. */
ItemType getOriginalType() const { return m_original_type; }
// ------------------------------------------------------------------------
@ -305,6 +314,12 @@ public:
// ------------------------------------------------------------------------
/** Returns the XYZ position of the item. */
const Vec3& getXYZ() const { return m_xyz; }
// ------------------------------------------------------------------------
/** Returns the normal of the ItemState. */
const Vec3 getNormal() const
{
return m_normal;
}
}; // class ItemState
// ============================================================================
@ -350,7 +365,7 @@ private:
* would not be collected. Used by the AI to avoid items. */
Vec3 *m_avoidance_points[2];
void initItem(ItemType type, const Vec3 &xyz);
void initItem(ItemType type, const Vec3 &xyz, const Vec3 &normal);
void setMesh(scene::IMesh* mesh, scene::IMesh* lowres_mesh);
void handleNewMesh(ItemType type);
@ -432,6 +447,12 @@ public:
return m_avoidance_points[1];
} // getAvoidancePoint
// ------------------------------------------------------------------------
/** Returns the normal of the item. */
const Vec3 getNormal() const
{
return quatRotate(m_original_rotation, Vec3(0,1,0));
}
// ------------------------------------------------------------------------
scene::ISceneNode *getSceneNode()
{

View File

@ -43,7 +43,8 @@ ItemEventInfo::ItemEventInfo(BareNetworkString *buffer, int *count)
if (m_type == IEI_NEW)
{
m_xyz = buffer->getVec3();
*count -= 12;
m_normal = buffer->getVec3();
*count -= 24;
}
else // IEI_COLLECT
{
@ -71,7 +72,10 @@ void ItemEventInfo::saveState(BareNetworkString *buffer)
// Only new item and collecting items need the index and kart id:
buffer->addUInt8(m_kart_id).addUInt16(m_index);
if (m_type == IEI_NEW)
{
buffer->add(m_xyz);
buffer->add(m_normal);
}
else if (m_type == IEI_COLLECT)
buffer->addUInt16(m_ticks_till_return);
}

View File

@ -52,6 +52,9 @@ private:
/** In case of new items the position of the new item. */
Vec3 m_xyz;
/** The normal of an item. */
Vec3 m_normal;
/** Ticks for the item to return, atm used by collecting banana
* with bomb to delay the return for banana. */
int16_t m_ticks_till_return;
@ -76,9 +79,9 @@ public:
* need to encode the new item type.
*/
ItemEventInfo(int ticks, ItemState::ItemType type, int index,
int kart_id, const Vec3 &xyz)
int kart_id, const Vec3 &xyz, const Vec3 &normal)
: m_ticks(ticks), m_index(index), m_kart_id(kart_id), m_xyz(xyz),
m_ticks_till_return(0)
m_normal(normal), m_ticks_till_return(0)
{
m_type = IEI_NEW;
} // ItemEventInfo(new item)
@ -125,6 +128,13 @@ public:
return m_xyz;
} // getXYZ
// --------------------------------------------------------------------
/** Returns the normal of a new item only. */
const Vec3& getNormal() const
{
assert(isNewItem());
return m_normal;
} // getNormal
// --------------------------------------------------------------------
/** Returns the ticks till return, used only by collection events. */
int getTicksTillReturn() const { return m_ticks_till_return; }
// --------------------------------------------------------------------

View File

@ -257,42 +257,44 @@ unsigned int ItemManager::insertItem(Item *item)
* bubblegum).
* \param type Type of the item.
* \param kart The kart that drops the new item.
* \param xyz Can be used to overwrite the item location (used in networking).
* \param server_xyz Can be used to overwrite the item location.
* \param server_normal The normal as seen on the server.
*/
Item* ItemManager::dropNewItem(ItemState::ItemType type,
const AbstractKart *kart, const Vec3 *xyz)
const AbstractKart *kart,
const Vec3 *server_xyz,
const Vec3 *server_normal)
{
Vec3 hit_point;
Vec3 normal;
if (NetworkConfig::get()->isNetworking() &&
NetworkConfig::get()->isClient() && !server_xyz) return NULL;
Vec3 normal, pos;
const Material* material_hit;
Vec3 pos = xyz ? *xyz : kart->getXYZ();
Vec3 to = pos + kart->getTrans().getBasis() * Vec3(0, -10000, 0);
Track::getCurrentTrack()->getTriangleMesh().castRay(pos, to,
&hit_point,
&material_hit,
&normal);
// We will get no material if the kart is 'over nothing' when dropping
// the bubble gum. In most cases this means that the item does not need
// to be created (and we just return NULL). Only exception: if the server
// has sent a 'new item' event (which means its raycast found terrain),
// but the client does not have found a terrain (e.g. differences in
// position or more likely floating point differences). In this case, we
// must use the server position. In this and only this case xyz is not
// NULL (and then contains the server's position for the item).
if (!material_hit && !xyz) return NULL;
if (!material_hit)
if (!server_xyz)
{
// We are on a client which has received a new item event. Still
// create this item
normal.setValue(0, 1, 0); // Arbitrary, we don't have a normal
pos = *xyz;
// We are doing a new drop locally, i.e. not based on
// server data. So we need a raycast to find the correct
// location and normal of the item:
pos = server_xyz ? *server_xyz : kart->getXYZ();
Vec3 to = pos + kart->getTrans().getBasis() * Vec3(0, -10000, 0);
Vec3 hit_point;
Track::getCurrentTrack()->getTriangleMesh().castRay(pos, to,
&hit_point,
&material_hit,
&normal);
// We will get no material if the kart is 'over nothing' when dropping
// the bubble gum. In most cases this means that the item does not need
// to be created (and we just return NULL).
if (!material_hit) return NULL;
normal.normalize();
pos = hit_point + kart->getTrans().getBasis() * Vec3(0, -0.05f, 0);
}
else
{
normal.normalize();
pos = hit_point + kart->getTrans().getBasis() * Vec3(0, -0.05f, 0);
// We are on a client which has received a new item event from the
// server. So use the server's data for the new item:
normal = *server_normal;
pos = *server_xyz;
}
ItemState::ItemType mesh_type = type;

View File

@ -133,7 +133,9 @@ public:
virtual Item* placeItem (ItemState::ItemType type, const Vec3& xyz,
const Vec3 &normal);
virtual Item* dropNewItem (ItemState::ItemType type,
const AbstractKart* parent, const Vec3 *xyz=NULL);
const AbstractKart* parent,
const Vec3 *server_xyz = NULL,
const Vec3 *normal = NULL);
virtual Item* placeTrigger (const Vec3& xyz, float distance,
TriggerItemListener* listener);
void update (int ticks);

View File

@ -148,23 +148,29 @@ void NetworkItemManager::switchItems()
* \param type Type of the item.
* \param kart In case of a dropped item used to avoid that a kart
* is affected by its own items.
* \param server_xyz In case of rewind the server's position of this item.
* \param server_normal In case of rewind the server's normal of this item.
*/
Item* NetworkItemManager::dropNewItem(ItemState::ItemType type,
const AbstractKart *kart, const Vec3 *xyz)
const AbstractKart *kart,
const Vec3 *server_xyz,
const Vec3 *server_normal)
{
Item *item = ItemManager::dropNewItem(type, kart, xyz);
Item *item = ItemManager::dropNewItem(type, kart, server_xyz, server_normal);
if(!item) return NULL;
// Nothing else to do for client
if (NetworkConfig::get()->isClient()) return item;
assert(!server_xyz);
// Server: store the data for this event:
m_item_events.lock();
m_item_events.getData().emplace_back(World::getWorld()->getTicksSinceStart(),
type, item->getItemId(),
kart->getWorldKartId(),
xyz ? *xyz : kart->getXYZ() );
item->getXYZ(),
item->getNormal());
m_item_events.unlock();
return item;
} // dropNewItem
@ -409,7 +415,7 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
AbstractKart *kart = world->getKart(iei.getKartId());
ItemState *is = new ItemState(iei.getNewItemType(), kart,
iei.getIndex() );
is->initItem(iei.getNewItemType(), iei.getXYZ());
is->initItem(iei.getNewItemType(), iei.getXYZ(), iei.getNormal());
if (m_switch_ticks >= 0)
{
ItemState::ItemType new_type = m_switch_to[is->getType()];
@ -491,8 +497,9 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
// A new item was dropped according to the server that is not
// yet part of the current state --> create new item
Vec3 xyz = is->getXYZ();
Vec3 normal = is->getNormal();
Item *item_new = dropNewItem(is->getType(), is->getPreviousOwner(),
&xyz);
&xyz, &normal );
if (i != item_new->getItemId())
{
// The newly created item on the client has been given a

View File

@ -80,8 +80,10 @@ public:
int ticks) OVERRIDE;
virtual void collectedItem(ItemState *item, AbstractKart *kart) OVERRIDE;
virtual void switchItems() OVERRIDE;
virtual Item* dropNewItem(ItemState::ItemType type, const AbstractKart *kart,
const Vec3 *xyz=NULL) OVERRIDE;
virtual Item* dropNewItem(ItemState::ItemType type,
const AbstractKart *kart,
const Vec3 *server_xyz = NULL,
const Vec3 *server_normal = NULL) OVERRIDE;
virtual BareNetworkString* saveState(std::vector<std::string>* ru)
OVERRIDE;
virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;

View File

@ -2672,7 +2672,7 @@ float Kart::applyAirFriction(float engine_power)
//Instead of making increasing gears have enormous power gaps, apply friction
float mass_factor = m_kart_properties->getMass()/350.0f;
float compense_linear_slowdown = 39.33f*getSpeed()*mass_factor;
float compense_linear_slowdown = 39.33f*fabsf(getSpeed())*mass_factor;
engine_power += compense_linear_slowdown;

View File

@ -155,7 +155,7 @@ BareNetworkString* KartRewinder::saveState(std::vector<std::string>* ru)
buffer->add(body->getLinearVelocity());
buffer->add(body->getAngularVelocity());
buffer->addUInt16(m_vehicle->getTimedRotationTicks());
buffer->add(m_vehicle->getTimedRotation());
buffer->addFloat(m_vehicle->getTimedRotation());
// For collision rewind
buffer->addUInt16(m_bounce_back_ticks);
@ -262,10 +262,10 @@ void KartRewinder::restoreState(BareNetworkString *buffer, int count)
}
uint16_t time_rot = buffer->getUInt16();
float timed_rotation_y = buffer->getFloat();
// Set timed rotation divides by time_rot
m_vehicle->setTimedRotation(time_rot,
stk_config->ticks2Time(time_rot)
* buffer->getVec3());
stk_config->ticks2Time(time_rot) * timed_rotation_y);
// Collision rewind
m_bounce_back_ticks = buffer->getUInt16();

View File

@ -87,7 +87,7 @@ void Skidding::reset()
btVector3 rot(0, 0, 0);
// Only access the vehicle if the kart is not a ghost
if (!m_kart->isGhostKart())
m_kart->getVehicle()->setTimedRotation(0, rot);
m_kart->getVehicle()->setTimedRotation(0, 0);
} // reset
// ----------------------------------------------------------------------------
@ -535,9 +535,9 @@ void Skidding::update(int ticks, bool is_on_ground,
float t = std::min(skid_time_float, kp->getSkidVisualTime());
t = std::min(t, kp->getSkidRevertVisualTime());
btVector3 rot(0, m_visual_rotation * kp->getSkidPostSkidRotateFactor(), 0);
m_kart->getVehicle()->setTimedRotation(
(uint16_t)stk_config->time2Ticks(t), rot);
(uint16_t)stk_config->time2Ticks(t),
m_visual_rotation * kp->getSkidPostSkidRotateFactor());
// skid_time is used to count backwards for the GFX
m_skid_time = stk_config->time2Ticks(t);
if(bonus_time>0)

View File

@ -35,7 +35,7 @@
#include <algorithm>
const Vec3 g_kart_flag_offset(0.0, 0.2f, -0.5f);
const float g_capture_length = 2.0f;
const float g_capture_length = 3.0f;
const int g_captured_score = 10;
// ----------------------------------------------------------------------------

View File

@ -627,6 +627,10 @@ void LinearWorld::getKartsDisplayInfo(
}
rank_info.m_text = irr::core::stringw(str.c_str());
}
else if (kart->hasFinishedRace())
{
rank_info.m_text = kart->getController()->getName();
}
else
{
rank_info.m_text = "";

View File

@ -75,7 +75,7 @@ ClientLobby::ClientLobby(const TransportAddress& a, std::shared_ptr<Server> s)
: LobbyProtocol(NULL)
{
m_waiting_for_game = false;
m_server_auto_lap = false;
m_server_auto_game_time = false;
m_received_server_result = false;
m_state.store(NONE);
m_server_address = a;
@ -697,6 +697,9 @@ void ClientLobby::updatePlayerList(Event* event)
if (d == PLAYER_DIFFICULTY_HANDICAP)
std::get<3>(pl) = _("%s (handicapped)", std::get<3>(pl));
std::get<5>(pl) = (KartTeam)data.getUInt8();
bool ready = data.getUInt8() == 1;
if (ready)
std::get<4>(pl) = 4;
players.push_back(pl);
}
@ -841,7 +844,7 @@ void ClientLobby::startSelection(Event* event)
SFXManager::get()->quickSound("wee");
const NetworkString& data = event->data();
bool skip_kart_screen = data.getUInt8() == 1;
m_server_auto_lap = data.getUInt8() == 1;
m_server_auto_game_time = data.getUInt8() == 1;
const unsigned kart_num = data.getUInt16();
const unsigned track_num = data.getUInt16();
m_available_karts.clear();

View File

@ -71,7 +71,7 @@ private:
bool m_waiting_for_game;
bool m_server_auto_lap;
bool m_server_auto_game_time;
bool m_received_server_result;
@ -111,7 +111,7 @@ public:
{ return m_state.load() == REQUESTING_CONNECTION; }
bool isLobbyReady() const { return m_state.load() == CONNECTED; }
bool isWaitingForGame() const { return m_waiting_for_game; }
bool isServerAutoLap() const { return m_server_auto_lap; }
bool isServerAutoGameTime() const { return m_server_auto_game_time; }
virtual bool isRacing() const OVERRIDE { return m_state.load() == RACING; }
void clearPlayers();
};

View File

@ -460,6 +460,8 @@ void ServerLobby::asynchronousUpdate()
!m_game_setup->isGrandPrixStarted())
{
resetPeersReady();
if (m_timeout.load() != std::numeric_limits<int64_t>::max())
updatePlayerList();
m_timeout.store(std::numeric_limits<int64_t>::max());
}
if (m_timeout.load() < (int64_t)StkTime::getRealTimeMs() ||
@ -833,7 +835,9 @@ void ServerLobby::startSelection(const Event *event)
}
if (ServerConfig::m_owner_less)
{
m_peers_ready.at(event->getPeerSP()) = true;
m_peers_ready.at(event->getPeerSP()) =
!m_peers_ready.at(event->getPeerSP());
updatePlayerList();
return;
}
if (event->getPeerSP() != m_server_owner.lock())
@ -879,7 +883,7 @@ void ServerLobby::startSelection(const Event *event)
ns->setSynchronous(true);
ns->addUInt8(LE_START_SELECTION).addUInt8(
m_game_setup->isGrandPrixStarted() ? 1 : 0)
.addUInt8(ServerConfig::m_auto_lap_ratio > 0.0f ? 1 : 0);
.addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0);
// Remove karts / tracks from server that are not supported on all clients
std::set<std::string> karts_erase, tracks_erase;
@ -1744,6 +1748,11 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server)
pl->addUInt8(profile->getTeam());
else
pl->addUInt8(KART_TEAM_NONE);
std::shared_ptr<STKPeer> p = profile->getPeer();
uint8_t ready = (!game_started &&
m_peers_ready.find(p) != m_peers_ready.end() &&
m_peers_ready.at(p)) ? 1 : 0;
pl->addUInt8(ready);
}
// Don't send this message to in-game players
@ -1876,14 +1885,14 @@ void ServerLobby::playerVote(Event* event)
if (race_manager->modeHasLaps())
{
if (ServerConfig::m_auto_lap_ratio > 0.0f)
if (ServerConfig::m_auto_game_time_ratio > 0.0f)
{
Track* t = track_manager->getTrack(track_name);
if (t)
{
lap = (uint8_t)(fmaxf(1.0f,
(float)t->getDefaultNumberOfLaps() *
ServerConfig::m_auto_lap_ratio));
ServerConfig::m_auto_game_time_ratio));
}
else
{
@ -1895,6 +1904,20 @@ void ServerLobby::playerVote(Event* event)
else if (lap == 0)
lap = (uint8_t)3;
}
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER &&
ServerConfig::m_auto_game_time_ratio > 0.0f)
{
if (m_game_setup->isSoccerGoalTarget())
{
lap = (uint8_t)(ServerConfig::m_auto_game_time_ratio *
UserConfigParams::m_num_goals);
}
else
{
lap = (uint8_t)(ServerConfig::m_auto_game_time_ratio *
UserConfigParams::m_soccer_time_limit);
}
}
NetworkString other = NetworkString(PROTOCOL_LOBBY_ROOM);
std::string name = StringUtils::wideToUtf8(event->getPeer()
@ -2445,6 +2468,7 @@ void ServerLobby::addWaitingPlayersToGame()
void ServerLobby::resetServer()
{
addWaitingPlayersToGame();
resetPeersReady();
m_state = NetworkConfig::get()->isLAN() ?
WAITING_FOR_START_GAME : REGISTER_SELF_ADDRESS;
updatePlayerList(true/*update_when_reset_server*/);

View File

@ -238,12 +238,17 @@ namespace ServerConfig
"(time-limit-threshold-ctf + flag-return-timemout / 60.0)) * 60.0,"
" negative value to disable time limit."));
SERVER_CFG_PREFIX FloatServerConfigParam m_auto_lap_ratio
SERVER_CFG_DEFAULT(FloatServerConfigParam(-1.0f, "auto-lap-ratio",
"Value used by server to automatically calculate "
"lap of each race in network game, if more than 0.0f, the number of "
"lap of each track vote in linear race will be determined by "
"max(1.0f, auto-lap-ratio * default lap of that track)."));
SERVER_CFG_PREFIX FloatServerConfigParam m_auto_game_time_ratio
SERVER_CFG_DEFAULT(FloatServerConfigParam(-1.0f, "auto-game-time-ratio",
"Value used by server to automatically estimate each game time. "
"For races, it decides the lap of each race in network game, "
"if more than 0.0f, the number of lap of each track vote in "
"linear race will be determined by "
"max(1.0f, auto-game-time-ratio * default lap of that track). "
"For soccer if more than 0.0f, for time limit game it will be "
"auto-game-time-ratio * soccer-time-limit in UserConfig, for goal "
"limit game it will be auto-game-time-ratio * numgoals "
"in UserConfig, -1 to disable for all."));
SERVER_CFG_PREFIX IntServerConfigParam m_max_ping
SERVER_CFG_DEFAULT(IntServerConfigParam(300, "max-ping",

View File

@ -121,7 +121,7 @@ void btKart::reset()
m_num_wheels_on_ground = 0;
m_additional_impulse = btVector3(0,0,0);
m_ticks_additional_impulse = 0;
m_additional_rotation = btVector3(0,0,0);
m_additional_rotation = 0;
m_ticks_additional_rotation = 0;
m_max_speed = -1.0f;
m_min_speed = 0.0f;
@ -522,9 +522,9 @@ void btKart::updateVehicle( btScalar step )
btTransform &t = m_chassisBody->getWorldTransform();
// We have fixed timestep
float dt = stk_config->ticks2Time(1);
btQuaternion add_rot(m_additional_rotation.getY()*dt,
m_additional_rotation.getX()*dt,
m_additional_rotation.getZ()*dt);
btQuaternion add_rot(m_additional_rotation * dt,
0.0f,
0.0f);
t.setRotation(t.getRotation()*add_rot);
m_chassisBody->setWorldTransform(t);
// Also apply the rotation to the interpolated world transform.

View File

@ -83,8 +83,8 @@ private:
/** The time the additional impulse should be applied. */
uint16_t m_ticks_additional_impulse;
/** Additional rotation that is applied over a certain amount of time. */
btVector3 m_additional_rotation;
/** Additional rotation in y-axis that is applied over a certain amount of time. */
float m_additional_rotation;
/** Duration over which the additional rotation is applied. */
uint16_t m_ticks_additional_rotation;
@ -236,21 +236,26 @@ public:
{ return m_ticks_additional_impulse; }
// ------------------------------------------------------------------------
const btVector3& getAdditionalImpulse() const
{ return m_additional_impulse; }
{ return m_additional_impulse; }
// ------------------------------------------------------------------------
/** Sets a rotation that is applied over a certain amount of time (to avoid
* a too rapid changes in the kart).
* \param t Ticks for the rotation to be applied.
* \param torque The rotation to apply. */
void setTimedRotation(uint16_t t, const btVector3 &rot)
* \param rot_in_y_axis The rotation in y-axis to apply. */
void setTimedRotation(uint16_t t, float rot_in_y_axis)
{
if(t>0) m_additional_rotation = rot / (stk_config->ticks2Time(t));
if (t > 0)
{
m_additional_rotation =
rot_in_y_axis / (stk_config->ticks2Time(t));
}
m_ticks_additional_rotation = t;
} // setTimedTorque
// ------------------------------------------------------------------------
const btVector3& getTimedRotation() const { return m_additional_rotation; }
float getTimedRotation() const { return m_additional_rotation; }
// ------------------------------------------------------------------------
uint16_t getTimedRotationTicks() const { return m_ticks_additional_rotation; }
uint16_t getTimedRotationTicks() const
{ return m_ticks_additional_rotation; }
// ------------------------------------------------------------------------
/** Sets the maximum speed for this kart. */
void setMaxSpeed(float new_max_speed)

View File

@ -70,7 +70,6 @@ NetworkingLobby::NetworkingLobby() : Screen("online/networking_lobby.stkgui")
m_header = NULL;
m_text_bubble = NULL;
m_timeout_message = NULL;
m_exit_widget = NULL;
m_start_button = NULL;
m_player_list = NULL;
m_chat_box = NULL;
@ -106,9 +105,6 @@ void NetworkingLobby::loadedFromFile()
m_player_list = getWidget<ListWidget>("players");
assert(m_player_list!= NULL);
m_exit_widget = getWidget<IconButtonWidget>("exit");
assert(m_exit_widget != NULL);
m_icon_bank = new irr::gui::STKModifiedSpriteBank(GUIEngine::getGUIEnv());
video::ITexture* icon_1 = irr_driver->getTexture
(file_manager->getAsset(FileManager::GUI_ICON, "crown.png"));
@ -118,10 +114,13 @@ void NetworkingLobby::loadedFromFile()
(file_manager->getAsset(FileManager::GUI_ICON, "main_help.png"));
video::ITexture* icon_4 = irr_driver->getTexture
(file_manager->getAsset(FileManager::GUI_ICON, "hourglass.png"));
video::ITexture* icon_5 = irr_driver->getTexture
(file_manager->getAsset(FileManager::GUI_ICON, "green_check.png"));
m_icon_bank->addTextureAsSprite(icon_1);
m_icon_bank->addTextureAsSprite(icon_2);
m_icon_bank->addTextureAsSprite(icon_3);
m_icon_bank->addTextureAsSprite(icon_4);
m_icon_bank->addTextureAsSprite(icon_5);
const int screen_width = irr_driver->getFrameSize().Width;
m_icon_bank->setScale(screen_width > 1280 ? 0.4f : 0.25f);
} // loadedFromFile
@ -140,6 +139,7 @@ void NetworkingLobby::init()
{
Screen::init();
getWidget("config")->setVisible(false);
m_player_names.clear();
m_allow_change_team = false;
m_has_auto_start_in_server = false;
@ -152,7 +152,7 @@ void NetworkingLobby::init()
//I18N: In the networking lobby
m_header->setText(_("Lobby"), false);
m_server_info_height = GUIEngine::getFont()->getDimension(L"X").Height;
m_start_button->setText(_("Start race"));
m_start_button->setLabel(_("Start race"));
m_start_button->setVisible(false);
m_state = LS_CONNECTING;
getWidget("chat")->setVisible(false);
@ -245,12 +245,11 @@ void NetworkingLobby::onUpdate(float delta)
if (cl && cl->isWaitingForGame())
{
m_start_button->setVisible(false);
m_exit_widget->setVisible(true);
m_timeout_message->setVisible(true);
//I18N: In the networking lobby, show when player is required to wait
//before the current game finish
core::stringw msg = _("Please wait for current game to end.");
m_timeout_message->setText(msg, true);
m_timeout_message->setText(msg, false);
core::stringw total_msg;
for (auto& string : m_server_info)
{
@ -281,7 +280,7 @@ void NetworkingLobby::onUpdate(float delta)
_P("Game will start if there is more than %d player.",
"Game will start if there are more than %d players.",
(int)(m_min_start_game_players - 1));
m_timeout_message->setText(msg, true);
m_timeout_message->setText(msg, false);
}
if (m_cur_starting_timer != std::numeric_limits<int64_t>::max())
@ -292,11 +291,12 @@ void NetworkingLobby::onUpdate(float delta)
remain = 0;
//I18N: In the networking lobby, display the starting timeout
//for owner-less server to begin a game
core::stringw msg = _P("Starting after %d second "
"or everyone pressed 'Ready' button.",
"Starting after %d seconds "
"or everyone pressed 'Ready' button.", (int)remain);
m_timeout_message->setText(msg, true);
core::stringw msg = _P("Starting after %d second, "
"or once everyone has pressed the 'Ready' button.",
"Starting after %d seconds, "
"or once everyone has pressed the 'Ready' button.",
(int)remain);
m_timeout_message->setText(msg, false);
}
}
else
@ -307,9 +307,8 @@ void NetworkingLobby::onUpdate(float delta)
if (m_state == LS_ADD_PLAYERS)
{
m_text_bubble->setText(_("Everyone:\nPress the 'Select' button to "
"join the game"), true);
"join the game"), false);
m_start_button->setVisible(false);
m_exit_widget->setVisible(false);
if (!GUIEngine::ModalDialog::isADialogActive())
{
input_manager->getDeviceManager()->setAssignMode(DETECT_NEW);
@ -319,7 +318,6 @@ void NetworkingLobby::onUpdate(float delta)
}
m_start_button->setVisible(false);
m_exit_widget->setVisible(true);
if (!cl || !cl->isLobbyReady())
{
core::stringw connect_msg;
@ -333,7 +331,7 @@ void NetworkingLobby::onUpdate(float delta)
connect_msg =
StringUtils::loadingDots(_("Finding a quick play server"));
}
m_text_bubble->setText(connect_msg, true);
m_text_bubble->setText(connect_msg, false);
m_start_button->setVisible(false);
}
else
@ -436,10 +434,6 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name,
sendChat(m_chat_box->getText());
m_chat_box->setText("");
} // send chat message
else if (name == m_exit_widget->m_properties[PROP_ID])
{
StateManager::get()->escapePressed();
}
else if (name == m_start_button->m_properties[PROP_ID])
{
// Send a message to the server to start
@ -578,7 +572,7 @@ void NetworkingLobby::initAutoStartTimer(bool grand_prix_started,
//I18N: In the networking lobby, ready button is to allow player to tell
//server that he is ready for next game for owner less server
m_start_button->setText(_("Ready"));
m_start_button->setLabel(_("Ready"));
m_has_auto_start_in_server = true;
m_min_start_game_players = grand_prix_started ? 0 : min_players;
m_start_timeout = start_timeout;

View File

@ -82,7 +82,6 @@ private:
GUIEngine::LabelWidget* m_header;
GUIEngine::LabelWidget* m_text_bubble;
GUIEngine::LabelWidget* m_timeout_message;
GUIEngine::IconButtonWidget* m_exit_widget;
GUIEngine::IconButtonWidget* m_start_button;
GUIEngine::ListWidget* m_player_list;
GUIEngine::TextBoxWidget* m_chat_box;

View File

@ -273,6 +273,8 @@ void TracksScreen::init()
{
// Notice: for arena (battle / soccer) lap and reverse will be mapped to
// goals / time limit and random item location
auto cl = LobbyProtocol::get<ClientLobby>();
assert(cl);
if (UserConfigParams::m_num_laps == 0 ||
UserConfigParams::m_num_laps > 20)
UserConfigParams::m_num_laps = 1;
@ -297,25 +299,34 @@ void TracksScreen::init()
}
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
{
m_laps->setVisible(true);
getWidget("lap-text")->setVisible(true);
auto cl = LobbyProtocol::get<ClientLobby>();
assert(cl);
if (cl->getGameSetup()->isSoccerGoalTarget())
if (cl->isServerAutoGameTime())
{
//I18N: In track screen
getWidget<LabelWidget>("lap-text")->setText(_("Number of goals to win"), false);
m_laps->setValue(UserConfigParams::m_num_goals);
m_laps->setMin(1);
m_laps->setMax(10);
getWidget("lap-text")->setVisible(false);
m_laps->setVisible(false);
m_laps->setValue(0);
}
else
{
//I18N: In track screen
getWidget<LabelWidget>("lap-text")->setText(_("Maximum time (min.)"), false);
m_laps->setValue(UserConfigParams::m_soccer_time_limit);
m_laps->setMin(1);
m_laps->setMax(15);
m_laps->setVisible(true);
getWidget("lap-text")->setVisible(true);
auto cl = LobbyProtocol::get<ClientLobby>();
assert(cl);
if (cl->getGameSetup()->isSoccerGoalTarget())
{
//I18N: In track screen
getWidget<LabelWidget>("lap-text")->setText(_("Number of goals to win"), false);
m_laps->setValue(UserConfigParams::m_num_goals);
m_laps->setMin(1);
m_laps->setMax(10);
}
else
{
//I18N: In track screen
getWidget<LabelWidget>("lap-text")->setText(_("Maximum time (min.)"), false);
m_laps->setValue(UserConfigParams::m_soccer_time_limit);
m_laps->setMin(1);
m_laps->setMax(15);
}
}
getWidget("reverse-text")->setVisible(true);
//I18N: In track screen
@ -325,9 +336,7 @@ void TracksScreen::init()
}
else
{
auto cl = LobbyProtocol::get<ClientLobby>();
assert(cl);
if (cl->isServerAutoLap())
if (cl->isServerAutoGameTime())
{
getWidget("lap-text")->setVisible(false);
m_laps->setVisible(false);

View File

@ -197,6 +197,7 @@ RaceGUI::RaceGUI()
m_blue_flag = irr_driver->getTexture(FileManager::GUI_ICON, "blue_flag.png");
m_soccer_ball = irr_driver->getTexture(FileManager::GUI_ICON, "soccer_ball_normal.png");
m_heart_icon = irr_driver->getTexture(FileManager::GUI_ICON, "heart.png");
m_champion = irr_driver->getTexture(FileManager::GUI_ICON, "gp_new.png");
} // RaceGUI
//-----------------------------------------------------------------------------
@ -307,8 +308,6 @@ void RaceGUI::renderGlobal(float dt)
drawGlobalPlayerIcons(0);
}
}
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
drawScores();
#endif
} // renderGlobal
@ -354,55 +353,6 @@ void RaceGUI::renderPlayerView(const Camera *camera, float dt)
drawLap(kart, viewport, scaling);
} // renderPlayerView
//-----------------------------------------------------------------------------
/** Shows the current soccer result.
*/
void RaceGUI::drawScores()
{
#ifndef SERVER_ONLY
SoccerWorld* sw = dynamic_cast<SoccerWorld*>(World::getWorld());
int offset_y = 5;
int offset_x = 5;
gui::ScalableFont* font = GUIEngine::getTitleFont();
static video::SColor color = video::SColor(255,255,255,255);
//Draw two teams score
irr::video::ITexture *team_icon = m_red_team;
for(unsigned int i=0; i<2; i++)
{
core::recti position(offset_x, offset_y,
offset_x + 2*m_minimap_player_size, offset_y + 2*m_minimap_player_size);
core::stringw score = StringUtils::toWString(sw->getScore((KartTeam)i));
int string_height =
GUIEngine::getFont()->getDimension(score.c_str()).Height;
core::recti pos(position.UpperLeftCorner.X + 5,
position.LowerRightCorner.Y + offset_y,
position.LowerRightCorner.X,
position.LowerRightCorner.Y + string_height);
font->setBlackBorder(true);
font->draw(score.c_str(),pos,color);
font->setBlackBorder(false);
if (i == 1)
{
team_icon = m_blue_team;
}
core::rect<s32> indicator_pos(offset_x, offset_y,
offset_x + (int)(m_minimap_player_size*2),
offset_y + (int)(m_minimap_player_size*2));
core::rect<s32> source_rect(core::position2d<s32>(0,0),
team_icon->getSize());
draw2DImage(team_icon,indicator_pos,source_rect,
NULL,NULL,true);
offset_x += position.LowerRightCorner.X + 30;
}
#endif
} // drawScores
//-----------------------------------------------------------------------------
/** Displays the racing time on the screen.
*/
@ -843,29 +793,6 @@ void RaceGUI::drawRank(const AbstractKart *kart,
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->setBlackBorder(true);
font->draw(oss.str().c_str(), pos, color, true, true);
font->setBlackBorder(false);
font->setScale(1.0f);
return;
}
// Draw rank
WorldWithRank *world = dynamic_cast<WorldWithRank*>(World::getWorld());
@ -1223,14 +1150,50 @@ void RaceGUI::drawLap(const AbstractKart* kart,
- m_lap_width - 10;
pos.LowerRightCorner.X = viewport.LowerRightCorner.X;
// Draw CTF scores with red score - blue score
// Draw CTF / soccer scores with red score - blue score (score limit)
CaptureTheFlag* ctf = dynamic_cast<CaptureTheFlag*>(World::getWorld());
if (ctf)
SoccerWorld* sw = dynamic_cast<SoccerWorld*>(World::getWorld());
FreeForAll* ffa = dynamic_cast<FreeForAll*>(World::getWorld());
static video::SColor color = video::SColor(255, 255, 255, 255);
int hit_capture_limit =
race_manager->getHitCaptureLimit() != std::numeric_limits<int>::max()
? race_manager->getHitCaptureLimit() : -1;
int score_limit = sw && !race_manager->hasTimeTarget() ?
race_manager->getMaxGoal() : ctf ? hit_capture_limit : -1;
if (!ctf && ffa && hit_capture_limit != -1)
{
int icon_width = irr_driver->getActualScreenSize().Height/19;
core::rect<s32> indicator_pos(viewport.LowerRightCorner.X - (icon_width+10),
pos.UpperLeftCorner.Y,
viewport.LowerRightCorner.X - 10,
pos.UpperLeftCorner.Y + icon_width);
core::rect<s32> source_rect(core::position2d<s32>(0,0),
m_champion->getSize());
draw2DImage(m_champion, indicator_pos, source_rect,
NULL, NULL, true);
gui::ScalableFont* font = GUIEngine::getHighresDigitFont();
font->setBlackBorder(true);
pos.UpperLeftCorner.X += 30;
font->draw(StringUtils::toWString(hit_capture_limit).c_str(), pos, color);
font->setBlackBorder(false);
font->setScale(1.0f);
return;
}
if (ctf || sw)
{
if (score_limit != -1)
pos.UpperLeftCorner.X -= 80;
int red_score = ctf ? ctf->getRedScore() : sw->getScore(KART_TEAM_RED);
int blue_score = ctf ? ctf->getBlueScore() : sw->getScore(KART_TEAM_BLUE);
gui::ScalableFont* font = GUIEngine::getHighresDigitFont();
font->setBlackBorder(true);
font->setScale(scaling.Y < 1.0f ? 0.5f: 1.0f);
core::stringw text = StringUtils::toWString(ctf->getRedScore());
core::stringw text = StringUtils::toWString(red_score);
font->draw(text, pos, video::SColor(255, 255, 0, 0));
core::dimension2du d = font->getDimension(text.c_str());
pos += core::position2di(d.Width, 0);
@ -1238,9 +1201,17 @@ void RaceGUI::drawLap(const AbstractKart* kart,
font->draw(text, pos, video::SColor(255, 255, 255, 255));
d = font->getDimension(text.c_str());
pos += core::position2di(d.Width, 0);
text = StringUtils::toWString(ctf->getBlueScore());
text = StringUtils::toWString(blue_score);
font->draw(text, pos, video::SColor(255, 0, 0, 255));
font->setScale(1.0f);
pos += core::position2di(d.Width, 0);
if (score_limit != -1)
{
text = L" (";
text += StringUtils::toWString(score_limit);
text += L")";
font->draw(text, pos, video::SColor(255, 255, 255, 255));
}
font->setBlackBorder(false);
return;
}
@ -1267,7 +1238,6 @@ void RaceGUI::drawLap(const AbstractKart* kart,
pos.UpperLeftCorner.X -= icon_width;
pos.LowerRightCorner.X -= icon_width;
static video::SColor color = video::SColor(255, 255, 255, 255);
std::ostringstream out;
out << lap + 1 << "/" << race_manager->getNumLaps();

View File

@ -99,6 +99,8 @@ private:
irr::video::ITexture *m_blue_flag;
irr::video::ITexture *m_soccer_ball;
irr::video::ITexture *m_heart_icon;
/** Texture for the hit limit icon*/
irr::video::ITexture* m_champion;
/** Animation state: none, getting smaller (old value),
* getting bigger (new number). */
@ -140,8 +142,6 @@ private:
void drawGlobalMiniMap ();
void drawGlobalTimer ();
void drawLiveDifference ();
void drawScores();
public: