display_name: "The Lively" worldport_entrance { room: "Puzzle Room" name: "BETWEEN" } alternate' title='Atom feed' href='https://code.fourisland.com/tanetane/atom/src/script_system.cpp?h=main' type='application/atom+xml'/>
summary refs log blame commit diff stats
path: root/src/script_system.cpp
blob: 7f9f9082a8802b376d4a7c549ae3e7feaaae67d8 (plain) (tree)
1
2
3
4
5
6
7
8
9



                           
                             
                             
                             
                          
                          
                   






                                                      

                              
                                         


                                                




                                    

                               
                        
                        
                                    
                                              
                                          


                                                                                                      
      
                                      
                              
                                  
                                      

                                              
 


                                                     
                                             
                                                               
                                                         

                                                                      
 

                                        
                                               

                                                                
 

                                        
                                                           
                                                         


                                                         

                                                   
 



                                                                                                  
      

                                                     
 




                                                                


                                                           
 






                                                             



                                   










                                                
 





                                              






                                                





                                                





                                                





                                             





                                             





                              











                                        




                                           
                       
                      


                                             
                            












                                 





                                    
              




                                


                            

       





                                                            





                                



                                                   

                                       

                                         

                            
              
     
   



                                                

 
                                                        


                                                              
   









                                                                              
 

                                                                                    
                                                                                                                           
 
                             
                                                                                    

   
                                        

                          
            

   

                                             

   

                                                       

                                                                                    
 
                                                                          




                                                                        
                                                              
 
                             



                                                                        
                                        


                                       


           

                                             

   
#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));
  }
}