#include "script_system.h" #include #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 "behaviour_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", sol::constructors(), "x", [] (const vec2i& v) { return v.x(); }, "y", [] (const vec2i& v) { return v.y(); }); engine_.new_usertype( "zone", "ul", &Zone::ul, "dr", &Zone::dr); engine_.new_usertype( "spriteframe", "center", &SpriteFrame::center, "size", &SpriteFrame::size); engine_.new_usertype( "sprite", "alias", &Sprite::alias, "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, "enclosureZone", &Sprite::enclosureZone, "movementSpeed", &Sprite::movementSpeed, "solid", &Sprite::solid, "behaviourType", &Sprite::behaviourType, "followSpriteId", &Sprite::followSpriteId, "interactionScript", &Sprite::interactionScript, "opacity", &Sprite::opacity, "shouldBeFadedIn", &Sprite::shouldBeFadedIn); engine_.new_usertype( "message", "displayMessage", &MessageSystem::displayMessage, "showChoice", &MessageSystem::showChoice, "displayCutsceneBars", &MessageSystem::displayCutsceneBars, "hideCutsceneBars", &MessageSystem::hideCutsceneBars, "isMessageActive", sol::property(&MessageSystem::isMessageActive), "getChoiceSelection", &MessageSystem::getChoiceSelection); engine_.new_usertype( "animation", "initSprite", &AnimationSystem::initSprite, "setSpriteAnimation", &AnimationSystem::setSpriteAnimation, "setSpriteDirection", &AnimationSystem::setSpriteDirection); engine_.new_usertype( "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( "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( "effect", "fadeScreen", &EffectSystem::fadeScreen, "isScreenFadeComplete", &EffectSystem::isScreenFadeComplete, "fadeMap", &EffectSystem::fadeMap, "isMapFadeComplete", &EffectSystem::isMapFadeComplete, "shakeCamera", &EffectSystem::shakeCamera, "stopShakingCamera", &EffectSystem::stopShakingCamera, "circleTransition", &EffectSystem::circleTransition, "isCircleTransitionComplete", &EffectSystem::isCircleTransitionComplete); engine_.new_usertype( "camera", "panToSprite", &CameraSystem::panToSprite, "panToWarpPoint", &CameraSystem::panToWarpPoint, "isPanning", &CameraSystem::isPanning, "unlockCamera", &CameraSystem::unlockCamera, "setFollowingSprite", &CameraSystem::setFollowingSprite); engine_.new_usertype( "behaviour", "directSpriteToLocation", &BehaviourSystem::directSpriteToLocation, "isFollowingPath", &BehaviourSystem::isFollowingPath); engine_.new_usertype( "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", "getName", &Map::getName, "getWarpPoint", &Map::getWarpPoint, "hasMusic", &Map::hasMusic, "getMusic", &Map::getMusic, "getZone", &Map::getZone); engine_.set_function( "message", [&] () -> MessageSystem& { return game_.getSystem(); }); engine_.set_function( "animation", [&] () -> AnimationSystem& { return game_.getSystem(); }); engine_.set_function( "character", [&] () -> CharacterSystem& { return game_.getSystem(); }); engine_.set_function( "transform", [&] () -> TransformSystem& { return game_.getSystem(); }); engine_.set_function( "effect", [&] () -> EffectSystem& { return game_.getSystem(); }); engine_.set_function( "camera", [&] () -> CameraSystem& { return game_.getSystem(); }); engine_.set_function( "behaviour", [&] () -> BehaviourSystem& { return game_.getSystem(); }); 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& { 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_.set_function("directionFacingPoint", &directionFacingPoint); engine_.set_function("cardinalDirectionFacingPoint", &cardinalDirectionFacingPoint); 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::destroySprite(int spriteId) { scripts_.remove_if([spriteId] (const Script& script) { return (script.linkedSprite == spriteId); }); } 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(mapName, scriptName); } void ScriptSystem::runScript(std::string mapName, std::string scriptName, int linkedSprite) { 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(mapName, scriptName))); #ifdef TANETANE_DEBUG newScript.debugInfo = mapName + "." + scriptName; #endif newScript.linkedSprite = linkedSprite; 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)); newScript.debugInfo = 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)); } }