440 lines
20 KiB
C++
440 lines
20 KiB
C++
//
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
// Copyright (C) 2014-2015 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 "script_track.hpp"
|
|
|
|
#include "animations/three_d_animation.hpp"
|
|
#include "font/digit_face.hpp"
|
|
#include "font/font_manager.hpp"
|
|
#include "graphics/central_settings.hpp"
|
|
#include "graphics/stk_text_billboard.hpp"
|
|
#include "guiengine/scalable_font.hpp"
|
|
#include "input/device_manager.hpp"
|
|
#include "input/input_device.hpp"
|
|
#include "input/input_manager.hpp"
|
|
#include "modes/world.hpp"
|
|
#include "scriptengine/property_animator.hpp"
|
|
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
|
|
#include "states_screens/dialogs/race_paused_dialog.hpp"
|
|
#include "tracks/track.hpp"
|
|
#include "tracks/track_object.hpp"
|
|
#include "tracks/track_object_manager.hpp"
|
|
|
|
#include <IBillboardTextSceneNode.h>
|
|
#include <angelscript.h>
|
|
#include <assert.h>
|
|
#include <ISceneManager.h>
|
|
|
|
/** \cond DOXYGEN_IGNORE */
|
|
namespace Scripting
|
|
{
|
|
/** \endcond */
|
|
namespace Track
|
|
{
|
|
/** \addtogroup Scripting
|
|
* @{
|
|
*/
|
|
/** \addtogroup Scripting_Track Track
|
|
* @{
|
|
*/
|
|
|
|
/*
|
|
void disableAnimation(std::string *name, void *memory)
|
|
{
|
|
std::string *str = name;
|
|
std::string type = "mesh";
|
|
World::getWorld()->getTrack()->getTrackObjectManager()->disable(*str, type);
|
|
}*/
|
|
|
|
/**
|
|
* Get a track object by ID.
|
|
* @return An object of type @ref Scripting_TrackObject
|
|
*/
|
|
::TrackObject* getTrackObject(std::string* libraryInstance, std::string* objID)
|
|
{
|
|
return World::getWorld()->getTrack()->getTrackObjectManager()->getTrackObject(*libraryInstance, *objID);
|
|
}
|
|
|
|
/** Creates a trigger at the specified location */
|
|
void createTrigger(std::string* triggerID, SimpleVec3* creation_loc, float distance)
|
|
{
|
|
float x = creation_loc->getX();
|
|
float y = creation_loc->getY();
|
|
float z = creation_loc->getZ();
|
|
core::vector3df posi(x, y, z);
|
|
core::vector3df hpr(0, 0, 0);
|
|
core::vector3df scale(1.0f, 1.0f, 1.0f);
|
|
TrackObjectPresentationActionTrigger* newtrigger =
|
|
new TrackObjectPresentationActionTrigger(posi, *triggerID, distance);
|
|
::TrackObject* tobj = new ::TrackObject(posi, hpr, scale,
|
|
"none", newtrigger, false /* isDynamic */, NULL /* physics settings */);
|
|
tobj->setID(*triggerID);
|
|
World::getWorld()->getTrack()->getTrackObjectManager()->insertObject(tobj);
|
|
}
|
|
|
|
void createTextBillboard(std::string* text, SimpleVec3* location)
|
|
{
|
|
core::stringw wtext = StringUtils::utf8ToWide(*text);
|
|
DigitFace* digit_face = font_manager->getFont<DigitFace>();
|
|
core::dimension2d<u32> textsize = digit_face->getDimension(wtext.c_str());
|
|
|
|
core::vector3df xyz(location->getX(), location->getY(), location->getZ());
|
|
|
|
if (CVS->isGLSL())
|
|
{
|
|
STKTextBillboard* tb = new STKTextBillboard(wtext.c_str(), digit_face,
|
|
GUIEngine::getSkin()->getColor("font::bottom"),
|
|
GUIEngine::getSkin()->getColor("font::top"),
|
|
irr_driver->getSceneManager()->getRootSceneNode(),
|
|
irr_driver->getSceneManager(), -1, xyz,
|
|
core::vector3df(1.5f, 1.5f, 1.5f));
|
|
|
|
World::getWorld()->getTrack()->addNode(tb);
|
|
tb->drop();
|
|
}
|
|
else
|
|
{
|
|
assert(GUIEngine::getHighresDigitFont() != NULL);
|
|
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"));
|
|
World::getWorld()->getTrack()->addNode(sn);
|
|
}
|
|
}
|
|
|
|
/** Exits the race to the main menu */
|
|
void exitRace()
|
|
{
|
|
World::getWorld()->scheduleExitRace();
|
|
}
|
|
|
|
void pauseRace()
|
|
{
|
|
new RacePausedDialog(0.8f, 0.6f);
|
|
}
|
|
|
|
int getNumberOfKarts()
|
|
{
|
|
return race_manager->getNumberOfKarts();
|
|
}
|
|
|
|
int getNumLocalPlayers()
|
|
{
|
|
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();
|
|
::Track* track = World::getWorld()->getTrack();
|
|
animator->add(
|
|
new AnimatedProperty(FOG_MAX, 1,
|
|
new double[1] { track->getFogMax() },
|
|
new double[1] { maxDensity }, duration, track)
|
|
);
|
|
animator->add(
|
|
new AnimatedProperty(FOG_RANGE, 2,
|
|
new double[2] { track->getFogStart(), track->getFogEnd() },
|
|
new double[2] { start, end }, duration, track)
|
|
);
|
|
|
|
video::SColor color = track->getFogColor();
|
|
animator->add(
|
|
new AnimatedProperty(FOG_COLOR, 3,
|
|
new double[3] {
|
|
(double)color.getRed(),
|
|
(double)color.getGreen(),
|
|
(double)color.getBlue()
|
|
},
|
|
new double[3] {
|
|
(double)r,
|
|
(double)g,
|
|
(double)b
|
|
},
|
|
duration, track)
|
|
);
|
|
}
|
|
}
|
|
|
|
/** \cond DOXYGEN_IGNORE */
|
|
namespace Track
|
|
{
|
|
/** \endcond */
|
|
|
|
namespace TrackObject
|
|
{
|
|
SimpleVec3 getCenterPosition(::TrackObject* obj)
|
|
{
|
|
core::vector3df pos = obj->getAbsoluteCenterPosition();
|
|
return SimpleVec3(pos.X, pos.Y, pos.Z);
|
|
}
|
|
|
|
SimpleVec3 getOrigin(::TrackObject* obj)
|
|
{
|
|
core::vector3df pos = obj->getAbsolutePosition();
|
|
return SimpleVec3(pos.X, pos.Y, pos.Z);
|
|
}
|
|
}
|
|
|
|
// ----------- TrackObjectPresentationMesh methods -----------
|
|
// TODO: this method is WRONG, we should in most cases move not the presentation but the entire object
|
|
//void movePresentation(Vec3 *new_pos, void *memory)
|
|
//{
|
|
// core::vector3df xyz = new_pos->toIrrVector();
|
|
// core::vector3df hpr = core::vector3df(0, 0, 0);
|
|
// core::vector3df scale = core::vector3df(1, 1, 1);
|
|
// ((TrackObjectPresentation*)(memory))->move(xyz, hpr, scale, false);
|
|
//}
|
|
|
|
namespace Mesh
|
|
{
|
|
/**
|
|
* \addtogroup Scripting_Mesh Mesh (script binding)
|
|
* Type returned by trackObject.getMesh()
|
|
* @{
|
|
*/
|
|
|
|
/** Sets a loop for a skeletal animation */
|
|
// TODO: can we use a type and avoid void* ?
|
|
void setLoop(int start, int end /** \cond DOXYGEN_IGNORE */, void *memory /** \endcond */)
|
|
{
|
|
((TrackObjectPresentationMesh*)(memory))->setLoop(start, end);
|
|
}
|
|
|
|
/** Sets the current frame for a skeletal animation */
|
|
void setCurrentFrame(int frame /** \cond DOXYGEN_IGNORE */, void *memory /** \endcond */)
|
|
{
|
|
((TrackObjectPresentationMesh*)(memory))->setCurrentFrame(frame);
|
|
}
|
|
|
|
/** Get current frame in a skeletal animation */
|
|
int getCurrentFrame(/** \cond DOXYGEN_IGNORE */void *memory /** \endcond */)
|
|
{
|
|
return ((TrackObjectPresentationMesh*)(memory))->getCurrentFrame();
|
|
}
|
|
/** @} */
|
|
}
|
|
|
|
// ----------- Animator Object methods -----------
|
|
|
|
namespace Animator
|
|
{
|
|
/**
|
|
* \addtogroup Scripting_Animator Animator (script binding)
|
|
* Type returned by trackObject.getIPOAnimator()
|
|
* @{
|
|
*/
|
|
|
|
/** Pause/resumes a curve-based animation */
|
|
void setPaused(bool mode /** \cond DOXYGEN_IGNORE */, void *memory /** \endcond */)
|
|
{
|
|
((ThreeDAnimation*)(memory))->setPaused(mode);
|
|
}
|
|
|
|
/** @} */
|
|
}
|
|
|
|
// ----------- Light Object methods -----------
|
|
|
|
namespace Light
|
|
{
|
|
/**
|
|
* @addtogroup Scripting_Light Light (script binding)
|
|
* Type returned by trackObject.getLight()
|
|
* @{
|
|
*/
|
|
|
|
void setEnergy(float energy, /** \cond DOXYGEN_IGNORE */void *memory /** \endcond */)
|
|
{
|
|
((TrackObjectPresentationLight*)memory)->setEnergy(energy);
|
|
}
|
|
|
|
void animateEnergy(float energy, float duration, /** \cond DOXYGEN_IGNORE */void *memory /** \endcond */)
|
|
{
|
|
TrackObjectPresentationLight* light = ((TrackObjectPresentationLight*)memory);
|
|
PropertyAnimator::get()->add(
|
|
new AnimatedProperty(AP_LIGHT_ENERGY, 1,
|
|
new double[1] { light->getEnergy() },
|
|
new double[1] { energy }, duration, light)
|
|
);
|
|
}
|
|
|
|
/** @} */
|
|
}
|
|
|
|
|
|
// ----------- Sound Object methods -----------
|
|
|
|
namespace SoundEmitter
|
|
{
|
|
/**
|
|
* @addtogroup Scripting_SoundEmitter SoundEmitter (script binding)
|
|
* Type returned by trackObject.getSoundEmitter()
|
|
* @{
|
|
*/
|
|
|
|
// TODO: adjust all signatures to type "void*" parameters if possible
|
|
/** Stop a sound */
|
|
void stop(/** \cond DOXYGEN_IGNORE */void *memory /** \endcond */)
|
|
{
|
|
((TrackObjectPresentationSound*)memory)->stopSound();
|
|
}
|
|
|
|
/** Play the specified sound once */
|
|
void playOnce(/** \cond DOXYGEN_IGNORE */void *memory /** \endcond */)
|
|
{
|
|
((TrackObjectPresentationSound*)memory)->triggerSound(false); //false = once
|
|
}
|
|
|
|
/** Play the specified sound continuously */
|
|
void playLoop(/** \cond DOXYGEN_IGNORE */void *memory /** \endcond */)
|
|
{
|
|
((TrackObjectPresentationSound*)memory)->triggerSound(true); //true = loop
|
|
}
|
|
/** @} */
|
|
}
|
|
|
|
// ----------- ParticleEmitter Object methods -----------
|
|
|
|
namespace ParticleEmitter
|
|
{
|
|
/**
|
|
* @addtogroup Scripting_ParticleEmitter ParticleEmitter (script binding)
|
|
* Type returned by trackObject.getParticleEmitter()
|
|
* @{
|
|
*/
|
|
|
|
/** Stop particle emission */
|
|
void stop(/** \cond DOXYGEN_IGNORE */ void *memory /** \endcond */)
|
|
{
|
|
((TrackObjectPresentationParticles*)memory)->stop();
|
|
}
|
|
|
|
/** Stop particle emission */
|
|
void stopIn(float delay, /** \cond DOXYGEN_IGNORE */ void *memory /** \endcond */)
|
|
{
|
|
((TrackObjectPresentationParticles*)memory)->stopIn(delay);
|
|
}
|
|
|
|
/** Play the specified sound once */
|
|
void setEmissionRate(float rate /** \cond DOXYGEN_IGNORE */, void *memory /** \endcond */)
|
|
{
|
|
((TrackObjectPresentationParticles*)memory)->setRate(rate);
|
|
}
|
|
/** @} */
|
|
}
|
|
|
|
/** @}*/
|
|
/** @}*/
|
|
|
|
void registerScriptFunctions(asIScriptEngine *engine)
|
|
{
|
|
int r; // of type asERetCodes
|
|
|
|
engine->SetDefaultNamespace("Track");
|
|
|
|
r = engine->RegisterObjectType("TrackObject", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
|
r = engine->RegisterObjectType("PhysicalObject", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
|
r = engine->RegisterObjectType("Mesh", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0); // TrackObjectPresentationMesh
|
|
r = engine->RegisterObjectType("ParticleEmitter", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
|
r = engine->RegisterObjectType("SoundEmitter", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
|
r = engine->RegisterObjectType("Animator", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
|
r = engine->RegisterObjectType("Light", 0, asOBJ_REF | asOBJ_NOCOUNT); assert(r >= 0);
|
|
|
|
//r = engine->RegisterGlobalFunction("void disableTrackObject(const string &in)", asFUNCTION(disableTrackObject), asCALL_CDECL); assert(r >= 0);
|
|
//r = engine->RegisterGlobalFunction("void enableTrackObject(const string &in)", asFUNCTION(enableTrackObject), asCALL_CDECL); assert(r >= 0);
|
|
//r = engine->RegisterGlobalFunction("void enableTrigger(const string &in)", asFUNCTION(enableTrigger), asCALL_CDECL); assert(r >= 0);
|
|
//r = engine->RegisterGlobalFunction("void disableTrigger(const string &in)", asFUNCTION(disableTrigger), asCALL_CDECL); assert(r >= 0);
|
|
r = engine->RegisterGlobalFunction("void createTrigger(const string &in, const Vec3 &in, float distance)",
|
|
asFUNCTION(createTrigger), asCALL_CDECL); assert(r >= 0);
|
|
r = engine->RegisterGlobalFunction("void createTextBillboard(const string &in, const Vec3 &in)",
|
|
asFUNCTION(createTextBillboard), asCALL_CDECL); assert(r >= 0);
|
|
r = engine->RegisterGlobalFunction("TrackObject@ getTrackObject(const string &in, const string &in)", asFUNCTION(getTrackObject), asCALL_CDECL); assert(r >= 0);
|
|
r = engine->RegisterGlobalFunction("void exitRace()", asFUNCTION(exitRace), asCALL_CDECL); assert(r >= 0);
|
|
r = engine->RegisterGlobalFunction("void pauseRace()", asFUNCTION(pauseRace), asCALL_CDECL); assert(r >= 0);
|
|
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);
|
|
r = engine->RegisterObjectMethod("TrackObject", "SoundEmitter@ getSoundEmitter()", asMETHOD(::TrackObject, getSoundEmitter), asCALL_THISCALL); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("TrackObject", "Light@ getLight()", asMETHOD(::TrackObject, getLight), asCALL_THISCALL); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("TrackObject", "PhysicalObject@ getPhysics()", asMETHOD(::TrackObject, getPhysics), asCALL_THISCALL); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("TrackObject", "Mesh@ getMesh()", asMETHOD(::TrackObject, getMesh), asCALL_THISCALL); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("TrackObject", "ParticleEmitter@ getParticleEmitter()", asMETHOD(::TrackObject, getParticleEmitter), asCALL_THISCALL); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("TrackObject", "Animator@ getIPOAnimator()", asMETHOD(::TrackObject, getIPOAnimator), asCALL_THISCALL); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("TrackObject", "void moveTo(const Vec3 &in, bool)", asMETHOD(::TrackObject, moveTo), asCALL_THISCALL); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("TrackObject", "Vec3 getCenterPosition()", asFUNCTION(TrackObject::getCenterPosition), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("TrackObject", "Vec3 getOrigin()", asFUNCTION(TrackObject::getOrigin), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
|
|
// PhysicalObject
|
|
r = engine->RegisterObjectMethod("PhysicalObject", "bool isFlattenKartObject()", asMETHOD(PhysicalObject, isFlattenKartObject), asCALL_THISCALL); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("PhysicalObject", "void disable()", asMETHOD(PhysicalObject, disable), asCALL_THISCALL); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("PhysicalObject", "void enable()", asMETHOD(PhysicalObject, enable), asCALL_THISCALL); assert(r >= 0);
|
|
|
|
// TrackObjectPresentationMesh (Mesh or Skeletal Animation)
|
|
r = engine->RegisterObjectMethod("Mesh", "void setLoop(int start, int end)", asFUNCTION(Mesh::setLoop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("Mesh", "int getCurrentFrame()", asFUNCTION(Mesh::getCurrentFrame), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("Mesh", "void setCurrentFrame(int frame)", asFUNCTION(Mesh::setCurrentFrame), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
//r = engine->RegisterObjectMethod("Mesh", "void move(Vec3 &in)", asFUNCTION(movePresentation), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
|
|
// Particle Emitter
|
|
r = engine->RegisterObjectMethod("ParticleEmitter", "void stop()", asFUNCTION(ParticleEmitter::stop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("ParticleEmitter", "void stopIn(float)", asFUNCTION(ParticleEmitter::stopIn), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("ParticleEmitter", "void setEmissionRate(float)", asFUNCTION(ParticleEmitter::setEmissionRate), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
|
|
// Sound Effect
|
|
//r = engine->RegisterObjectMethod("SoundEmitter", "void move(Vec3 &in)", asFUNCTION(movePresentation), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("SoundEmitter", "void stop()", asFUNCTION(SoundEmitter::stop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("SoundEmitter", "void playOnce()", asFUNCTION(SoundEmitter::playOnce), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("SoundEmitter", "void playLoop()", asFUNCTION(SoundEmitter::playLoop), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
|
|
// Light
|
|
r = engine->RegisterObjectMethod("Light", "void setEnergy(float)", asFUNCTION(Light::setEnergy), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("Light", "void animateEnergy(float, float)", asFUNCTION(Light::animateEnergy), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
|
|
// Curve based Animation
|
|
//fails due to insufficient visibility to scripts TODO : Decide whether to fix visibility or introduce wrappers
|
|
//r = engine->RegisterObjectMethod("Animator", "void setPaused(bool mode)", asMETHOD(ThreeDAnimation, setPaused), asCALL_THISCALL); assert(r >= 0);
|
|
r = engine->RegisterObjectMethod("Animator", "void setPaused(bool mode)", asFUNCTION(Animator::setPaused), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
|
// TODO: add method to set current frame
|
|
// TODO: add method to launch playback from frame X to frame Y
|
|
// TODO: add method to register onAnimationComplete notifications ?
|
|
}
|
|
|
|
/** \cond DOXYGEN_IGNORE */
|
|
}
|
|
}
|
|
/** \endcond */
|
|
|