This commit is contained in:
hiker 2016-04-26 12:50:51 +10:00
commit 031ae27919
37 changed files with 27280 additions and 255 deletions

View File

@ -1,4 +1,16 @@
## SupertTuxKart 0.9.1
## SuperTuxKart 0.9.2
* Ghost replay races by Benau
* Battle mode AI by Benau
* Soccer mode AI by Benau
* New subsea track by samuncle
* TTF font rendering by Benau
* Kart properties refactor by Flakebi
* Scripting work under the hood
* Work on the track editor by mhp
* Tweak to challenges
* Bugfixes
## SuperTuxKart 0.9.1
* Many bug fixes
* Started to use scripting in tracks
* Significant audio performance improvements

View File

@ -16,6 +16,7 @@ First, make sure that you have the following packages installed:
* OpenAL (recommended: openal-soft-devel)
* Ogg (libogg-dev)
* Vorbis (libvorbis-dev)
* Freetype (libfreetype6-dev)
* libcurl (libcurl-devel)
* libbluetooth (bluez-devel)
* libpng (libpng-devel)
@ -26,7 +27,7 @@ Ubuntu command:
```
sudo apt-get install autoconf automake build-essential cmake libogg-dev libvorbis-dev libopenal-dev libxxf86vm-dev \
libgl1-mesa-dev libglu1-mesa-dev libcurl4-openssl-dev libfribidi-dev libbluetooth-dev libxrandr-dev
libgl1-mesa-dev libglu1-mesa-dev libcurl4-openssl-dev libfribidi-dev libbluetooth-dev libxrandr-dev libfreetype6-dev
```
Unpack the files from the tarball like this:

Binary file not shown.

View File

@ -1,19 +1,19 @@
<?xml version="1.0"?>
<challenge version="2">
<track id="subsea" laps="2"/>
<track id="abyss" laps="3"/>
<mode major="single" minor="quickrace"/>
<requirements trophies="0"/>
<hard>
<karts number="5"/>
<requirements position="1" time="205"/>
<requirements position="1" time="160"/>
</hard>
<medium>
<karts number="4"/>
<requirements time="258"/>
<requirements time="185"/>
</medium>
<easy>
<karts number="4"/>
<requirements time="330"/>
<requirements time="270"/>
</easy>
</challenge>

View File

@ -4,7 +4,7 @@
<track id="sandtrack" laps="3" reverse="false" />
<track id="farm" laps="3" reverse="false" />
<track id="olivermath" laps="4" reverse="false" />
<track id="subsea" laps="2" reverse="false" />
<track id="abyss" laps="3" reverse="false" />
<track id="scotland" laps="3" reverse="false" />
</supertuxkart_grand_prix>

View File

@ -12,7 +12,15 @@
<list id="replay_list" x="0" y="0" width="100%" height="100%"/>
</box>
<spacer width="100%" height="2%" />
<button x="1%" id="record-ghost" I18N="In the ghost replay selection screen" text="Record ghost replay" />
<div width="99%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="replay_difficulty_toggle" text_align="left"/>
<spacer width="10"/>
<label proportion="1" height="100%" text_align="left" I18N="In the ghost replay selection screen" text="Only show replays matching the current difficulty"/>
</div>
</div>
<spacer width="100%" height="1%" />
<button x="1%" id="record-ghost" I18N="In the ghost replay selection screen" text="Record ghost replay"/>
</div>
</stkgui>

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<stkgui>
<div x="2%" y="2%" width="96%" height="96%" layout="horizontal-row">
<button id="continue" width="250" align="bottom" text="Continue"/>
<spacer width="20"/>
<button id="save" width="250" align="bottom" text="Save Grand Prix"/>
<div x="2%" y="2%" width="96%" height="96%" layout="vertical-row">
<spacer proportion="1"/>
<button id="save" width="450" align="center" text="Save Grand Prix"/>
<spacer height="20"/>
<button id="continue" width="450" align="center" text="Continue"/>
</div>
</stkgui>

View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<stkgui>
<div x="2%" y="2%" width="96%" height="96%" layout="horizontal-row">
<button id="continue" width="250" align="bottom" text="Continue"/>
<spacer width="20"/>
<button id="save" width="250" align="bottom" text="Save Grand Prix"/>
<div x="2%" y="2%" width="96%" height="96%" layout="vertical-row">
<spacer proportion="1"/>
<button id="save" width="450" align="center" text="Save Grand Prix"/>
<spacer height="20"/>
<button id="continue" width="450" align="center" text="Continue"/>
</div>
</stkgui>

View File

@ -13,7 +13,7 @@
square_items="true" child_width="128" child_height="128" />
<spacer height="15" width="10"/>
<div width="90%" align="center" layout="vertical-row" height="fit">
<div width="90%" align="center" layout="vertical-row" proportion="1">
<div width="100%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="online" I18N="In the user screen" text_align="left"/>
<spacer width="10"/>
@ -44,15 +44,16 @@
I18N="In the user screen" text="Password"/>
<textbox id="password" proportion="2" height="fit" I18N="In the user screen"/>
</div>
</div>
<div width="80%" align="center" layout="vertical-row" height="fit">
<label id="message" width="80%" align="center" text_align="left"/>
<spacer height="20" width="20"/>
<label id="message" width="100%" text_align="center"/>
</div>
<spacer width="20" proportion="1"/>
<div width="90%" align="center" layout="vertical-row" height="13%" height="fit" align="bottom">
<buttonbar id="options" width="100%" height="100%" align="center">
<div width="90%" align="center" layout="vertical-row" height="fit">
<buttonbar id="options" width="100%" height="80" align="center">
<icon-button id="ok" width="64" height="64" icon="gui/green_check.png"
I18N="In the user screen" text="OK" label_location="bottom"/>
<icon-button id="new_user" width="64" height="64" icon="gui/blue_plus.png"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -966,6 +966,21 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m
}
#endif
if (race_manager->getReverseTrack() &&
m_mirror_axis_when_reverse != ' ')
{
irr::video::S3DVertex* mbVertices = (video::S3DVertex*)mb->getVertices();
for (unsigned int i = 0; i < mb->getVertexCount(); i++)
{
core::vector2df &tc = mb->getTCoords(i);
if (m_mirror_axis_when_reverse == 'V')
tc.Y = 1 - tc.Y;
else
tc.X = 1 - tc.X;
}
} // reverse track and texture needs mirroring
} // setMaterialProperties
//-----------------------------------------------------------------------------

View File

@ -123,6 +123,7 @@ FileManager::FileManager()
m_subdir_name[LIBRARY ] = "library";
m_subdir_name[MODEL ] = "models";
m_subdir_name[MUSIC ] = "music";
m_subdir_name[REPLAY ] = "replay";
m_subdir_name[SCRIPT ] = "tracks";
m_subdir_name[SFX ] = "sfx";
m_subdir_name[SKIN ] = "skins";

View File

@ -48,7 +48,7 @@ public:
* The last entry ASSET_COUNT specifies the number of entries. */
enum AssetType {ASSET_MIN,
CHALLENGE=ASSET_MIN,
GFX, GRANDPRIX, GUI, LIBRARY, MODEL, MUSIC,
GFX, GRANDPRIX, GUI, LIBRARY, MODEL, MUSIC, REPLAY,
SCRIPT, SFX, SHADER, SKIN, TEXTURE, TTF,
TRANSLATION, ASSET_MAX = TRANSLATION,
ASSET_COUNT};
@ -138,7 +138,13 @@ public:
bool abort_on_error=false) const;
std::string getAsset(AssetType type, const std::string &name) const;
std::string getAsset(const std::string &name) const;
// ------------------------------------------------------------------------
/** Returns the directory of an asset. */
std::string getAssetDirectory(AssetType type) const
{
return m_subdir_name[type];
}
// ------------------------------------------------------------------------
std::string searchMusic(const std::string& file_name) const;
std::string searchTexture(const std::string& fname) const;
std::string getUserConfigFile(const std::string& fname) const;

View File

@ -112,6 +112,7 @@ void GhostKart::update(float dt)
center_shift = getTrans().getBasis() * center_shift;
Moveable::updateGraphics(dt, center_shift, btQuaternion(0, 0, 0, 1));
Moveable::updatePosition();
getKartModel()->update(dt, dt*(m_all_physic_info[idx].m_speed),
m_all_physic_info[idx].m_steer, m_all_physic_info[idx].m_speed, idx);

View File

@ -128,7 +128,18 @@ void Moveable::update(float dt)
{
if(m_body->getInvMass()!=0)
m_motion_state->getWorldTransform(m_transform);
m_velocityLC = getVelocity()*m_transform.getBasis();
m_velocityLC = getVelocity()*m_transform.getBasis();
updatePosition();
updateGraphics(dt, Vec3(0,0,0), btQuaternion(0, 0, 0, 1));
} // update
//-----------------------------------------------------------------------------
/** Updates the current position and rotation. This function is also called
* by ghost karts for getHeading() to work.
*/
void Moveable::updatePosition()
{
Vec3 forw_vec = m_transform.getBasis().getColumn(0);
m_heading = -atan2f(forw_vec.getZ(), forw_vec.getX());
@ -138,9 +149,7 @@ void Moveable::update(float dt)
Vec3 up = getTrans().getBasis().getColumn(1);
m_pitch = atan2(up.getZ(), fabsf(up.getY()));
m_roll = atan2(up.getX(), up.getY());
updateGraphics(dt, Vec3(0,0,0), btQuaternion(0, 0, 0, 1));
} // update
} // updatePosition
//-----------------------------------------------------------------------------
/** Creates the bullet rigid body for this moveable.

View File

@ -110,6 +110,7 @@ public:
const btTransform
&getTrans() const {return m_transform;}
void setTrans(const btTransform& t);
void updatePosition();
}
; // class Moveable

View File

@ -40,7 +40,6 @@ ReplayPlay *ReplayPlay::m_replay_play = NULL;
ReplayPlay::ReplayPlay()
{
m_current_replay_file = 0;
m_custom_replay_file = false;
} // ReplayPlay
//-----------------------------------------------------------------------------
@ -64,6 +63,22 @@ void ReplayPlay::reset()
void ReplayPlay::loadAllReplayFile()
{
m_replay_file_list.clear();
// Load stock replay first
std::set<std::string> pre_record;
file_manager->listFiles(pre_record, file_manager
->getAssetDirectory(FileManager::REPLAY), /*is_full_path*/ true);
for (std::set<std::string>::iterator i = pre_record.begin();
i != pre_record.end(); ++i)
{
if (!addReplayFile(*i, /*custom_replay*/ true))
{
// Skip invalid replay file
continue;
}
}
// Now user recorded replay
std::set<std::string> files;
file_manager->listFiles(files, file_manager->getReplayDir(),
/*is_full_path*/ false);
@ -77,13 +92,12 @@ void ReplayPlay::loadAllReplayFile()
continue;
}
}
} // loadAllReplayFile
//-----------------------------------------------------------------------------
bool ReplayPlay::addReplayFile(const std::string& fn, bool custom_replay)
{
// custom_replay is true when full path of filename is given
m_custom_replay_file = custom_replay;
char s[1024], s1[1024];
if (StringUtils::getExtension(fn) != "replay") return false;
@ -92,6 +106,8 @@ bool ReplayPlay::addReplayFile(const std::string& fn, bool custom_replay)
if (fd == NULL) return false;
ReplayData rd;
// custom_replay is true when full path of filename is given
rd.m_custom_replay_file = custom_replay;
rd.m_filename = fn;
fgets(s, 1023, fd);
@ -196,7 +212,8 @@ void ReplayPlay::load()
m_ghost_karts.clearAndDeleteAll();
char s[1024];
FILE *fd = openReplayFile(/*writeable*/false, m_custom_replay_file);
FILE *fd = openReplayFile(/*writeable*/false,
m_replay_file_list.at(m_current_replay_file).m_custom_replay_file);
if(!fd)
{
Log::error("Replay", "Can't read '%s', ghost replay disabled.",

View File

@ -55,6 +55,7 @@ public:
std::string m_track_name;
std::vector<std::string> m_kart_list;
bool m_reverse;
bool m_custom_replay_file;
unsigned int m_difficulty;
unsigned int m_laps;
float m_min_time;
@ -93,8 +94,6 @@ private:
unsigned int m_current_replay_file;
bool m_custom_replay_file;
std::vector<ReplayData> m_replay_file_list;
/** All ghost karts. */

View File

@ -93,7 +93,7 @@ namespace Scripting
FILE *f = fopen(script_path.c_str(), "rb");
if (f == NULL)
{
Log::debug("Scripting", "File does not exist : {0}", script_path.c_str());
Log::debug("Scripting", "File does not exist : %s", script_path.c_str());
return "";
}

View File

@ -112,14 +112,14 @@ namespace Scripting
scene::ISceneManager* sm = irr_driver->getSceneManager();
scene::ISceneNode* sn =
sm->addBillboardTextSceneNode(GUIEngine::getHighresDigitFont(),
wtext.c_str(),
NULL,
core::dimension2df(textsize.Width / 35.0f,
textsize.Height / 35.0f),
xyz,
-1, // id
GUIEngine::getSkin()->getColor("font::bottom"),
GUIEngine::getSkin()->getColor("font::top"));
wtext.c_str(),
NULL,
core::dimension2df(textsize.Width / 35.0f,
textsize.Height / 35.0f),
xyz,
-1, // id
GUIEngine::getSkin()->getColor("font::bottom"),
GUIEngine::getSkin()->getColor("font::top"));
World::getWorld()->getTrack()->addNode(sn);
}
}
@ -145,6 +145,11 @@ namespace Scripting
return race_manager->getNumLocalPlayers();
}
bool isTrackReverse()
{
return race_manager->getReverseTrack();
}
void setFog(float maxDensity, float start, float end, int r, int g, int b, float duration)
{
PropertyAnimator* animator = PropertyAnimator::get();
@ -377,6 +382,7 @@ namespace Scripting
r = engine->RegisterGlobalFunction("void setFog(float maxDensity, float start, float end, int r, int g, int b, float duration)", asFUNCTION(setFog), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("int getNumberOfKarts()", asFUNCTION(getNumberOfKarts), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("int getNumLocalPlayers()", asFUNCTION(getNumLocalPlayers), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("bool isReverse()", asFUNCTION(isTrackReverse), asCALL_CDECL); assert(r >= 0);
// TrackObject
r = engine->RegisterObjectMethod("TrackObject", "void setEnabled(bool status)", asMETHOD(::TrackObject, setEnabled), asCALL_THISCALL); assert(r >= 0);

View File

@ -39,10 +39,15 @@ GhostReplayInfoDialog::GhostReplayInfoDialog(unsigned int replay_id)
LabelWidget *name = getWidget<LabelWidget>("name");
assert(name);
name->setText(stringw((m_rd.m_filename).c_str()), false);
name->setText(stringw((m_rd.m_custom_replay_file ? StringUtils::getBasename
(m_rd.m_filename) : m_rd.m_filename).c_str()), false);
m_back_widget = getWidget<IconButtonWidget>("back");
m_back_widget->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
// Non-deletable for custom (standard) replay file
getWidget<IconButtonWidget>("remove")->setActive(!m_rd.m_custom_replay_file);
m_action_widget = getWidget<RibbonWidget>("actions");
m_record_widget = getWidget<CheckBoxWidget>("record-race");
m_watch_widget = getWidget<CheckBoxWidget>("watch-only");
@ -76,8 +81,8 @@ GUIEngine::EventPropagation
if(selection == "start")
{
bool reverse = m_rd.m_reverse;
std::string track_name = m_rd.m_track_name;
bool reverse = m_rd.m_reverse;
std::string track_name = m_rd.m_track_name;
int laps = m_rd.m_laps;
int replay_id = m_replay_id;

View File

@ -62,6 +62,10 @@ void GhostReplaySelection::loadedFromFile()
m_replay_list_widget = getWidget<GUIEngine::ListWidget>("replay_list");
assert(m_replay_list_widget != NULL);
m_replay_list_widget->setColumnListener(this);
m_replay_difficulty_toggle_widget =
getWidget<GUIEngine::CheckBoxWidget>("replay_difficulty_toggle");
m_replay_difficulty_toggle_widget->setState(true);
m_same_difficulty = m_replay_difficulty_toggle_widget->getState();
} // loadedFromFile
// ----------------------------------------------------------------------------
@ -82,6 +86,7 @@ void GhostReplaySelection::beforeAddingWidget()
void GhostReplaySelection::init()
{
Screen::init();
m_cur_difficulty = race_manager->getDifficulty();
refresh(/*forced_update*/false);
} // init
@ -97,6 +102,10 @@ void GhostReplaySelection::loadList()
{
const ReplayPlay::ReplayData& rd = ReplayPlay::get()->getReplayData(i);
if (m_same_difficulty && m_cur_difficulty !=
(RaceManager::Difficulty)rd.m_difficulty)
continue;
std::vector<GUIEngine::ListWidget::ListCell> row;
Track* t = track_manager->getTrack(rd.m_track_name);
row.push_back(GUIEngine::ListWidget::ListCell
@ -113,7 +122,7 @@ void GhostReplaySelection::loadList()
(StringUtils::toWString(rd.m_laps), -1, 1, true));
row.push_back(GUIEngine::ListWidget::ListCell
(StringUtils::toWString(rd.m_min_time) + L"s", -1, 1, true));
m_replay_list_widget->addItem("replay", row);
m_replay_list_widget->addItem(StringUtils::toString(i), row);
}
} // loadList
@ -132,11 +141,13 @@ void GhostReplaySelection::eventCallback(GUIEngine::Widget* widget,
}
else if (name == m_replay_list_widget->m_properties[GUIEngine::PROP_ID])
{
int selected_index = m_replay_list_widget->getSelectionID();
int selected_index = -1;
const bool success = StringUtils::fromString(m_replay_list_widget
->getSelectionInternalName(), selected_index);
// This can happen e.g. when the list is empty and the user
// clicks somewhere.
if (selected_index >= (signed)ReplayPlay::get()->getNumReplayFile() ||
selected_index < 0)
selected_index < 0 || !success)
{
return;
}
@ -148,6 +159,11 @@ void GhostReplaySelection::eventCallback(GUIEngine::Widget* widget,
TracksScreen::getInstance()->setOfficalTrack(false);
TracksScreen::getInstance()->push();
}
else if (name == "replay_difficulty_toggle")
{
m_same_difficulty = m_replay_difficulty_toggle_widget->getState();
refresh(/*forced_update*/false);
}
} // eventCallback

View File

@ -21,6 +21,7 @@
#include "guiengine/screen.hpp"
#include "guiengine/widgets.hpp"
#include "race/race_manager.hpp"
#include "states_screens/dialogs/message_dialog.hpp"
namespace GUIEngine { class Widget; }
@ -41,9 +42,12 @@ private:
GhostReplaySelection();
~GhostReplaySelection();
GUIEngine::ListWidget* m_replay_list_widget;
std::string m_file_to_be_deleted;
bool m_sort_desc;
GUIEngine::ListWidget* m_replay_list_widget;
GUIEngine::CheckBoxWidget* m_replay_difficulty_toggle_widget;
RaceManager::Difficulty m_cur_difficulty;
std::string m_file_to_be_deleted;
bool m_same_difficulty;
bool m_sort_desc;
public:

View File

@ -52,6 +52,7 @@
using namespace irr::core;
using namespace irr::gui;
using namespace irr::video;
using namespace GUIEngine;
const float DURATION = 15.0f;
@ -112,6 +113,8 @@ void GrandPrixLose::init()
m_phase = 1;
m_global_time = 0.0f;
getWidget<ButtonWidget>("continue")->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
} // init
// -------------------------------------------------------------------------------------

View File

@ -55,6 +55,7 @@
using namespace irr::core;
using namespace irr::gui;
using namespace irr::video;
using namespace GUIEngine;
const float KARTS_X = -0.95f;
const float KARTS_DELTA_X = 1.9f;
@ -172,6 +173,7 @@ void GrandPrixWin::init()
m_phase = 1;
SFXManager::get()->quickSound("gp_end");
getWidget<ButtonWidget>("continue")->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
} // init
// -------------------------------------------------------------------------------------

View File

@ -192,7 +192,7 @@ void TracksScreen::buildTrackList()
if (!(curr_group_name == DEFAULT_GROUP_NAME ||
curr_group_name == ALL_TRACK_GROUPS_ID) && m_offical_track)
{
tracks_widget->setText(_("Only Offical track is supported."));
tracks_widget->setText(_("Only official tracks are supported."));
tracks_widget->updateItemDisplay();
return;
}

View File

@ -930,18 +930,6 @@ void Track::convertTrackToBullet(scene::ISceneNode *node)
if (mb->getVertexType() == video::EVT_STANDARD)
{
irr::video::S3DVertex* mbVertices=(video::S3DVertex*)mb->getVertices();
if (race_manager->getReverseTrack() &&
material->getMirrorAxisInReverse() != ' ')
{
for (unsigned int i = 0; i < mb->getVertexCount(); i++)
{
core::vector2df &tc = mb->getTCoords(i);
if (material->getMirrorAxisInReverse() == 'V')
tc.Y = 1 - tc.Y;
else
tc.X = 1 - tc.X;
}
} // reverse track and texture needs mirroring
for (unsigned int matrix_index = 0; matrix_index < matrices.size(); matrix_index++)
{
for (unsigned int j = 0; j < mb->getIndexCount(); j += 3)