#include "script_system.h"
#include <iostream>
#include "game.h"
#include "message_system.h"
#include "animation_system.h"
#include "character_system.h"
#include "transform_system.h"
#include "effect_system.h"
#include "camera_system.h"
#include "vector.h"
ScriptSystem::ScriptSystem(Game& game) : game_(game) {
engine_.open_libraries(
sol::lib::base,
sol::lib::coroutine,
sol::lib::math);
engine_.new_usertype<vec2i>(
"vec2i",
sol::constructors<vec2i(int, int)>(),
"x", [] (const vec2i& v) { return v.x(); },
"y", [] (const vec2i& v) { return v.y(); });
engine_.new_usertype<SpriteFrame>(
"spriteframe",
"center", &SpriteFrame::center,
"size", &SpriteFrame::size);
engine_.new_usertype<Sprite>(
"sprite",
"loc", &Sprite::loc,
"dir", &Sprite::dir,
"followers", &Sprite::followers,
"characterState", &Sprite::characterState,
"controllable", &Sprite::controllable,
"animFinished", &Sprite::animFinished,
"getCurrentFrame", [] (const Sprite& sprite) -> const SpriteFrame& {
return sprite.frames[sprite.animations[sprite.animationId].frameIndices[sprite.animationFrame]];
},
"persistent", &Sprite::persistent,
"paused", &Sprite::paused,
"clipping", &Sprite::clipping,
"cantCrouch", &Sprite::cantCrouch,
"bobsWhenNormal", &Sprite::bobsWhenNormal,
"animSlowdown", &Sprite::animSlowdown);
engine_.new_usertype<MessageSystem>(
"message",
"displayMessage", &MessageSystem::displayMessage,
"showChoice", &MessageSystem::showChoice,
"displayCutsceneBars", &MessageSystem::displayCutsceneBars,
"hideCutsceneBars", &MessageSystem::hideCutsceneBars,
"isMessageActive", sol::property(&MessageSystem::isMessageActive),
"getChoiceSelection", &MessageSystem::getChoiceSelection);
engine_.new_usertype<AnimationSystem>(
"animation",
"initSprite", &AnimationSystem::initSprite,
"setSpriteAnimation", &AnimationSystem::setSpriteAnimation,
"setSpriteDirection", &AnimationSystem::setSpriteDirection);
engine_.new_usertype<CharacterSystem>(
"character",
"addSpriteToParty", &CharacterSystem::addSpriteToParty,
"transplantParty", &CharacterSystem::transplantParty,
"breakUpParty", &CharacterSystem::breakUpParty,
"moveInDirection", &CharacterSystem::moveInDirection,
"stopDirecting", &CharacterSystem::stopDirecting,
"startRunning", &CharacterSystem::startRunning,
"halt", &CharacterSystem::halt);
engine_.new_usertype<TransformSystem>(
"transform",
"initSprite", [] (TransformSystem& transform, int spriteId, int x, int y, SpriteLayer layer) {
transform.initSprite(spriteId, vec2i{x, y}, layer);
},
"undoCollision", &TransformSystem::undoCollision,
"moveSprite", &TransformSystem::moveSprite);
engine_.new_usertype<EffectSystem>(
"effect",
"fadeScreen", &EffectSystem::fadeScreen,
"isScreenFadeComplete", &EffectSystem::isScreenFadeComplete,
"fadeMap", &EffectSystem::fadeMap,
"isMapFadeComplete", &EffectSystem::isMapFadeComplete,
"shakeCamera", &EffectSystem::shakeCamera,
"stopShakingCamera", &EffectSystem::stopShakingCamera);
engine_.new_usertype<CameraSystem>(
"camera",
"panToSprite", &CameraSystem::panToSprite,
"isPanning", &CameraSystem::isPanning,
"unlockCamera", &CameraSystem::unlockCamera,
"setFollowingSprite", &CameraSystem::setFollowingSprite);
engine_.new_usertype<Mixer>(
"mixer",
"playSound", &Mixer::playSound,
"loopSound", &Mixer::loopSound,
"stopChannel", &Mixer::stopChannel,
"playMusic", &Mixer::playMusic,
"fadeoutMusic", &Mixer::fadeoutMusic,
"isPlayingMusic", &Mixer::isPlayingMusic,
"getPlayingTrack", &Mixer::getPlayingTrack);
engine_.new_usertype<Map>(
"map",
"getWarpPoint", &Map::getWarpPoint,
"hasMusic", &Map::hasMusic,
"getMusic", &Map::getMusic);
engine_.set_function(
"message",
[&] () -> MessageSystem& {
return game_.getSystem<MessageSystem>();
});
engine_.set_function(
"animation",
[&] () -> AnimationSystem& {
return game_.getSystem<AnimationSystem>();
});
engine_.set_function(
"character",
[&] () -> CharacterSystem& {
return game_.getSystem<CharacterSystem>();
});
engine_.set_function(
"transform",
[&] () -> TransformSystem& {
return game_.getSystem<TransformSystem>();
});
engine_.set_function(
"effect",
[&] () -> EffectSystem& {
return game_.getSystem<EffectSystem>();
});
engine_.set_function(
"camera",
[&] () -> CameraSystem& {
return game_.getSystem<CameraSystem>();
});
engine_.set_function(
"mixer",
[&] () -> Mixer& {
return game_.getMixer();
});
engine_.set_function(
"emplaceSprite",
[&] (std::string alias) -> int {
return game_.emplaceSprite(alias);
});
engine_.set_function(
"destroySprite",
[&] (int spriteId) {
game_.destroySprite(spriteId);
});
engine_.set_function(
"getSpriteByAlias",
[&] (std::string alias) -> int {
return game_.getSpriteByAlias(alias);
});
engine_.set_function(
"getPlayerSprite",
[&] () -> int {
for (int id : game_.getSprites()) {
Sprite& sprite = game_.getSprite(id);
if (sprite.player) {
return id;
}
}
return -1;
});
engine_.set_function(
"getSprite",
[&] (int id) -> Sprite& {
return game_.getSprite(id);
});
engine_.set_function(
"getAllSprites",
[&] () -> const std::set<int>& {
return game_.getSprites();
});
engine_.set_function(
"loadMap",
[&] (std::string filename) {
game_.loadMap(filename);
});
engine_.set_function(
"getMap",
[&] () -> const Map& {
return game_.getMap();
});
engine_.set_function(
"randomChance",
[&] (double p) {
return std::bernoulli_distribution(p)(game_.getRng());
});
engine_.set_function(
"loadMapScripts",
[&] (std::string filename) {
loadMapScripts(filename);
});
engine_.script_file("../res/scripts/common.lua");
}
void ScriptSystem::tick(double dt) {
if (game_.isGameplayPaused()) return;
for (Script& script : scripts_) {
auto result = (*script.callable)(dt);
if (!result.valid()) {
sol::error e = result;
throw e;
}
}
scripts_.remove_if([] (const Script& script) {
return (!*script.callable);
});
}
void ScriptSystem::loadMapScripts(std::string mapName) {
if (!loadedScripts_.count(mapName)) {
engine_.script_file("../res/scripts/" + mapName + ".lua");
loadedScripts_.insert(mapName);
}
}
bool ScriptSystem::mapHasScript(std::string mapName, std::string scriptName) {
loadMapScripts(mapName);
return !!engine_.traverse_get<sol::function>(mapName, scriptName);
}
void ScriptSystem::runScript(std::string mapName, std::string scriptName) {
loadMapScripts(mapName);
Script newScript;
newScript.runner.reset(new sol::thread(sol::thread::create(engine_.lua_state())));
newScript.callable.reset(new sol::coroutine(newScript.runner->state().traverse_get<sol::function>(mapName, scriptName)));
if (!*newScript.callable) {
throw std::runtime_error("Error running script: " + mapName + "." + scriptName);
}
auto result = (*newScript.callable)();
if (!result.valid()) {
sol::error e = result;
throw e;
}
if (*newScript.callable) {
scripts_.push_back(std::move(newScript));
}
}
void ScriptSystem::runDebugScript(std::string script) {
Script newScript;
newScript.runner.reset(new sol::thread(sol::thread::create(engine_.lua_state())));
sol::load_result loaded_script = newScript.runner->state().load(script);
if (!loaded_script.valid()) {
std::cout << "Error running debug command: " << script << std::endl;
return;
}
newScript.callable.reset(new sol::coroutine(loaded_script));
if (!*newScript.callable) {
std::cout << "Error running debug command: " << script << std::endl;
return;
}
auto result = (*newScript.callable)();
if (!result.valid()) {
sol::error e = result;
std::cout << e.what() << std::endl;
return;
}
if (*newScript.callable) {
scripts_.push_back(std::move(newScript));
}
}