Easy Device Integration for Games. EDI FunSSR1 V2.0 + Preview Device [03/2025]

Most of these “outfits” you mentioned can be ignored. You just need to filter out the specifc animation part you want to call a script for.
In the game Milking Farm I filtered for specific strings, based on what the animations are named and am intercepting sprite animations, as well as CG Images. So you can check that plugin as reference.

Live2D animations can be a bit tricky. You can again ignore most variables (shapes, sizes, outfit) that are called alongside them and just focus on the model animation.
I’m still new to this myself, so there might be a better way, but I found that it’s possible to listen to certain events and then detect what Live2D animation is playing based on that.
For the game The Evil Guards of the Merchant City, this could look something like this:

(simple base example)
  // Hook into common event execution
  var _Game_Interpreter_setup = Game_Interpreter.prototype.setup;
  Game_Interpreter.prototype.setup = function(list, eventId) {
     _Game_Interpreter_setup.call(this, list, eventId);
     this._eventId = eventId; // Store the current event ID
     if (this.isOnCurrentMap()) {
        for (var i = 0; i < list.length; i++) {
        var command = list[i];
           if (command.code === 117) { // Call Common Event
              var commonEventId = command.parameters[0];
              var commonEvent = $dataCommonEvents[commonEventId];
              if (commonEvent) {
                 var eventName = commonEvent.name;
                 if (eventName.startsWith("※") || eventName.endsWith("✔")) {
                     logToFile('Event Name:' + eventName);  //replace with your function
                 }
              }
           }
        }
     }
  };

  // Hook into sub events
  var old_Game_Interpreter_prototype_pluginCommand = Game_Interpreter.prototype.pluginCommand;
  Game_Interpreter.prototype.pluginCommand = function(command, args) {
     old_Game_Interpreter_prototype_pluginCommand.call(this, command, args);
     var eventId = this._eventId; // Get the current event ID
     var event = $gameMap.event(eventId); // Get the event object
	 //strings to filter for (might need to be adjusted); "CG" to check Live2D Model group
	 var regex = /^(CG|BJ|DS|NP|SA|\$v120|TJ|BS|Again).*$/;
     if (event) {
        if (regex.test(args[1]) || (/^FR$/.test(args))){
          logToFile('Info:' + args);  //replace with your function
        }  
     }
  };

Which is then able to detect what Live2D animation is playing, as well as the sub-scene/stage:

Where “SA” and similar variables indicate the stage
(in most cases it looks like 1=init, 2=SpeedNormal, 3=SpeedFast, 4=SpeedFastest, 5=Finish).

The annoying part in this case, is that you need to assign these names to the right animation.
I would suggest going into the unlocked in-game gallery, see what name is detected for each animation and then saving the script with the same name.


This one is actually simpler, since it uses video files in the “www\movies” folder.
Most of them can be filtered out / redirected, since they’re duplicates and would be using the same script.
You can just script these videos directly and then intercept them like this:

(code example)
  player = new Player();

  var MoviePicture_loadVideo = Sprite_Picture.prototype.loadVideo;
  Sprite_Picture.prototype.loadVideo = function () {
      MoviePicture_loadVideo.apply(this, arguments);
  
      this._scriptName = this._pictureName
          //.replace() Custom string adjustment
      this._scriptRunning = true;
      this._seeked = false;
  
      this.bitmap._video.addEventListener(
          'seeked',
          function () {
              if (this._scriptRunning) { //add custom name filter here as well
                  logToFile('start: ' + this._scriptName); //replace with your function
                  this._seeked = true;
              }
          }.bind(this))
  }
  
  const MoviePicture_updateVideo = Sprite_Picture.prototype.updateVideo;
  Sprite_Picture.prototype.updateVideo = function () {
      if (!this.isVideoPicture()) {
          if (this._scriptRunning) {
              this._scriptRunning = false;
              logToFile('stop'); //replace with your function
          }
      }
      MoviePicture_updateVideo.apply(this, arguments);
  }
  
 player.refresh(); 

To detect the video names played:

2 Likes