Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for skippable cutscenes #1513

Merged
merged 9 commits into from
Sep 11, 2020
48 changes: 48 additions & 0 deletions src/object/cutscene_info.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SuperTux
// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
//
// 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, see <http://www.gnu.org/licenses/>.

#include "object/cutscene_info.hpp"

#include <stdio.h>

#include "object/camera.hpp"
#include "supertux/resources.hpp"
#include "video/drawing_context.hpp"

CutsceneInfo::CutsceneInfo(/*const Vector& pos*/ const Camera& cam, const std::string& text_, const Level& parent) :
position(cam.get_translation() + *(new Vector(32, 32))),
Semphriss marked this conversation as resolved.
Show resolved Hide resolved
text(text_),
camera(cam),
level(parent)
{
}

void
CutsceneInfo::update(float dt_sec)
{
position = camera.get_translation() + *(new Vector(32, 32));
Semphriss marked this conversation as resolved.
Show resolved Hide resolved
}

void
CutsceneInfo::draw(DrawingContext& context)
{
if (level.m_is_in_cutscene && !level.m_skip_cutscene)
{
context.color().draw_text(Resources::normal_font, text, position, ALIGN_LEFT, LAYER_OBJECTS+1000, CutsceneInfo::text_color);
Semphriss marked this conversation as resolved.
Show resolved Hide resolved
}
}

/* EOF */
47 changes: 47 additions & 0 deletions src/object/cutscene_info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SuperTux
// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
//
// 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, see <http://www.gnu.org/licenses/>.

#ifndef HEADER_SUPERTUX_OBJECT_CUTSCENE_INFO_HPP
#define HEADER_SUPERTUX_OBJECT_CUTSCENE_INFO_HPP

#include "math/vector.hpp"
#include "object/camera.hpp"
#include "supertux/game_object.hpp"
#include "supertux/level.hpp"
#include "video/color.hpp"

class CutsceneInfo final : public GameObject
{
static Color text_color;
public:
CutsceneInfo(/*const Vector& pos*/ const Camera& cam, const std::string& text_, const Level& parent);
virtual bool is_saveable() const override {
return false;
}

virtual void update(float dt_sec) override;
virtual void draw(DrawingContext& context) override;

private:
Vector position;
std::string text;
const Camera& camera;
const Level& level;
};

#endif

/* EOF */
95 changes: 90 additions & 5 deletions src/scripting/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,104 @@ bool is_christmas()
return g_config->christmas_mode;
}

void start_cutscene(HSQUIRRELVM vm)
Semphriss marked this conversation as resolved.
Show resolved Hide resolved
{
auto session = GameSession::current();
if (session == nullptr)
{
log_info << "No game session" << std::endl;
return;
}

if (session->get_current_level().m_is_in_cutscene)
{
log_warning << "start_cutscene(): starting a new cutscene above another one, ending preceeding cutscene (use end_cutscene() in scripts!)" << std::endl;
}

session->get_current_level().m_is_in_cutscene = true;
session->get_current_level().m_skip_cutscene = false;
}

void end_cutscene(HSQUIRRELVM vm)
{
auto session = GameSession::current();
if (session == nullptr)
{
log_info << "No game session" << std::endl;
return;
}

if (!session->get_current_level().m_is_in_cutscene)
{
log_warning << "end_cutscene(): no cutscene to end, resetting status anyways" << std::endl;
}

session->get_current_level().m_is_in_cutscene = false;
session->get_current_level().m_skip_cutscene = false;
}

bool check_cutscene(HSQUIRRELVM vm)
{
auto session = GameSession::current();
if (session == nullptr)
{
log_info << "No game session" << std::endl;
return false;
}

return session->get_current_level().m_is_in_cutscene;
}

void wait(HSQUIRRELVM vm, float seconds)
{
if (auto squirrelenv = static_cast<SquirrelEnvironment*>(sq_getforeignptr(vm)))
if(GameSession::current()->get_current_level().m_skip_cutscene)
{
squirrelenv->wait_for_seconds(vm, seconds);
if (auto squirrelenv = static_cast<SquirrelEnvironment*>(sq_getforeignptr(vm)))
{
// wait anyways, to prevent scripts like `while (true) {wait(0.1); ...}`
squirrelenv->wait_for_seconds(vm, 0);
}
else if (auto squirrelvm = static_cast<SquirrelVirtualMachine*>(sq_getsharedforeignptr(vm)))
{
squirrelvm->wait_for_seconds(vm, 0);
}
else
{
log_warning << "wait(): no VM or environment available\n";
}
}
else if (auto squirrelvm = static_cast<SquirrelVirtualMachine*>(sq_getsharedforeignptr(vm)))
else if(GameSession::current()->get_current_level().m_is_in_cutscene)
{
squirrelvm->wait_for_seconds(vm, seconds);
if (auto squirrelenv = static_cast<SquirrelEnvironment*>(sq_getforeignptr(vm)))
{
// wait anyways, to prevent scripts like `while (true) {wait(0.1); ...}` from freezing the game
squirrelenv->skippable_wait_for_seconds(vm, seconds);
//GameSession::current()->set_scheduler(squirrelenv->get_scheduler());
}
else if (auto squirrelvm = static_cast<SquirrelVirtualMachine*>(sq_getsharedforeignptr(vm)))
{
squirrelvm->skippable_wait_for_seconds(vm, seconds);
//GameSession::current()->set_scheduler(squirrelvm->get_scheduler());
}
else
{
log_warning << "wait(): no VM or environment available\n";
}
}
else
{
log_warning << "wait(): no VM or environment available\n";
if (auto squirrelenv = static_cast<SquirrelEnvironment*>(sq_getforeignptr(vm)))
{
squirrelenv->wait_for_seconds(vm, seconds);
}
else if (auto squirrelvm = static_cast<SquirrelVirtualMachine*>(sq_getsharedforeignptr(vm)))
{
squirrelvm->wait_for_seconds(vm, seconds);
}
else
{
log_warning << "wait(): no VM or environment available\n";
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/scripting/functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ void set_next_worldmap(const std::string& dirname, const std::string& spawnpoint
/** Load and display a level (on next screenswitch) */
void load_level(const std::string& filename);

/** Manages skippable cutscenes (cancels calls to wait()) */
void start_cutscene(HSQUIRRELVM vm);
void end_cutscene(HSQUIRRELVM vm);
bool check_cutscene(HSQUIRRELVM vm);

/** Suspend the script execution for the specified number of seconds */
void wait(HSQUIRRELVM vm, float seconds) __suspend;

Expand Down
100 changes: 86 additions & 14 deletions src/scripting/wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1583,8 +1583,7 @@ static SQInteger Gradient_set_colors_wrapper(HSQUIRRELVM vm)
}

try {
_this->set_colors(static_cast<float> (arg0), static_cast<float> (arg1), static_cast<float> (arg2),
static_cast<float> (arg3), static_cast<float> (arg4), static_cast<float> (arg5));
_this->set_colors(static_cast<float> (arg0), static_cast<float> (arg1), static_cast<float> (arg2), static_cast<float> (arg3), static_cast<float> (arg4), static_cast<float> (arg5));

return 0;

Expand Down Expand Up @@ -1633,8 +1632,7 @@ static SQInteger Gradient_fade_color1_wrapper(HSQUIRRELVM vm)
}

try {
_this->fade_color1(static_cast<float> (arg0), static_cast<float> (arg1), static_cast<float> (arg2),
static_cast<float> (arg3));
_this->fade_color1(static_cast<float> (arg0), static_cast<float> (arg1), static_cast<float> (arg2), static_cast<float> (arg3));

return 0;

Expand Down Expand Up @@ -1683,8 +1681,7 @@ static SQInteger Gradient_fade_color2_wrapper(HSQUIRRELVM vm)
}

try {
_this->fade_color2(static_cast<float> (arg0), static_cast<float> (arg1), static_cast<float> (arg2),
static_cast<float> (arg3));
_this->fade_color2(static_cast<float> (arg0), static_cast<float> (arg1), static_cast<float> (arg2), static_cast<float> (arg3));

return 0;

Expand Down Expand Up @@ -1748,9 +1745,7 @@ static SQInteger Gradient_fade_colors_wrapper(HSQUIRRELVM vm)
}

try {
_this->fade_colors(static_cast<float> (arg0), static_cast<float> (arg1), static_cast<float> (arg2),
static_cast<float> (arg3), static_cast<float> (arg4), static_cast<float> (arg5),
static_cast<float> (arg6));
_this->fade_colors(static_cast<float> (arg0), static_cast<float> (arg1), static_cast<float> (arg2), static_cast<float> (arg3), static_cast<float> (arg4), static_cast<float> (arg5), static_cast<float> (arg6));

return 0;

Expand All @@ -1764,7 +1759,6 @@ static SQInteger Gradient_fade_colors_wrapper(HSQUIRRELVM vm)

}


static SQInteger Gradient_swap_colors_wrapper(HSQUIRRELVM vm)
{
SQUserPointer data;
Expand Down Expand Up @@ -2111,15 +2105,14 @@ static SQInteger Platform_set_action_wrapper(HSQUIRRELVM vm)
sq_throwerror(vm, _SC("Argument 1 not a string"));
return SQ_ERROR;
}

SQInteger arg1;
if(SQ_FAILED(sq_getinteger(vm, 3, &arg1))) {
sq_throwerror(vm, _SC("Argument 2 not a integer"));
sq_throwerror(vm, _SC("Argument 2 not an integer"));
return SQ_ERROR;
}

try {
_this->set_action(static_cast<const char*> (arg0), static_cast<int> (arg1));
_this->set_action(arg0, static_cast<int> (arg1));

return 0;

Expand Down Expand Up @@ -5934,6 +5927,64 @@ static SQInteger load_level_wrapper(HSQUIRRELVM vm)

}

static SQInteger start_cutscene_wrapper(HSQUIRRELVM vm)
{
HSQUIRRELVM arg0 = vm;

try {
scripting::start_cutscene(arg0);

return 0;

} catch(std::exception& e) {
sq_throwerror(vm, e.what());
return SQ_ERROR;
} catch(...) {
sq_throwerror(vm, _SC("Unexpected exception while executing function 'start_cutscene'"));
return SQ_ERROR;
}

}

static SQInteger end_cutscene_wrapper(HSQUIRRELVM vm)
{
HSQUIRRELVM arg0 = vm;

try {
scripting::end_cutscene(arg0);

return 0;

} catch(std::exception& e) {
sq_throwerror(vm, e.what());
return SQ_ERROR;
} catch(...) {
sq_throwerror(vm, _SC("Unexpected exception while executing function 'end_cutscene'"));
return SQ_ERROR;
}

}

static SQInteger check_cutscene_wrapper(HSQUIRRELVM vm)
{
HSQUIRRELVM arg0 = vm;

try {
bool return_value = scripting::check_cutscene(arg0);

sq_pushbool(vm, return_value);
return 1;

} catch(std::exception& e) {
sq_throwerror(vm, e.what());
return SQ_ERROR;
} catch(...) {
sq_throwerror(vm, _SC("Unexpected exception while executing function 'check_cutscene'"));
return SQ_ERROR;
}

}

static SQInteger wait_wrapper(HSQUIRRELVM vm)
{
HSQUIRRELVM arg0 = vm;
Expand Down Expand Up @@ -7548,6 +7599,27 @@ void register_supertux_wrapper(HSQUIRRELVM v)
throw SquirrelError(v, "Couldn't register function 'load_level'");
}

sq_pushstring(v, "start_cutscene", -1);
sq_newclosure(v, &start_cutscene_wrapper, 0);
sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, "x|t");
if(SQ_FAILED(sq_createslot(v, -3))) {
throw SquirrelError(v, "Couldn't register function 'start_cutscene'");
}

sq_pushstring(v, "end_cutscene", -1);
sq_newclosure(v, &end_cutscene_wrapper, 0);
sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, "x|t");
if(SQ_FAILED(sq_createslot(v, -3))) {
throw SquirrelError(v, "Couldn't register function 'end_cutscene'");
}

sq_pushstring(v, "check_cutscene", -1);
sq_newclosure(v, &check_cutscene_wrapper, 0);
sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, "x|t");
if(SQ_FAILED(sq_createslot(v, -3))) {
throw SquirrelError(v, "Couldn't register function 'check_cutscene'");
}

sq_pushstring(v, "wait", -1);
sq_newclosure(v, &wait_wrapper, 0);
sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, "x|tn");
Expand Down Expand Up @@ -8354,7 +8426,7 @@ void register_supertux_wrapper(HSQUIRRELVM v)
if(SQ_FAILED(sq_createslot(v, -3))) {
throw SquirrelError(v, "Couldn't register function 'stop_moving'");
}

sq_pushstring(v, "set_action", -1);
sq_newclosure(v, &Platform_set_action_wrapper, 0);
sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, "x|tsi");
Expand Down
Loading