Script Commands Bug Fixes
#1
Bug Fix for RMXP's Interpreter's Script Command

Introduction

For ages we've known very well that the RMXP Interpreter class had an issue with command_355 aka the script event command. It has to evaluate the result of a script pasted as mere text in a very small window. The problem was that certain non truthy values, anything that doesn't return true as end result, might get ignored by the game engine. This part and its related solution are nothing new in the XP community and I just "copied & pasted" that centuries old solution here.

Nonetheless, that's not all this scriptlet has to offer. I was discussing some issues with XP in a VX ACE channel when I noticed there was another Bug bug that usually got ignored in RMXP. It was the script condition in the conditional branch event command! Shocked

The issue is very simple. You open the conditional branch and choose the script condition and type something there that's supposed to return a boolean value. (No if conditional reserved term is required there.) Now you'd expect me to tell you that it had the same issue the script command has... but nope, that's not the case here.

Both a truthy (true) and a falsey (false) value are fine and work just as intended. Yet, here comes the dreadful nil value into play!

Whenever your call returns a nil, your check becomes invalid and the engine simply skips it. Who Knows? Just like that, guys! Happy with a sweat

Don't Worried worry pals! The scriptlet below has come to Save-Point to solve that issue! Winking

The Up-to-date Script

Please Book read the next posts to learn why I had to replace my previous script as soon as possible. They are ordered in chronological order for a very good reason!

Version 5
If it looks an awful lot like Version 1, you're probably right about it! The main difference is the final outcome: there's no visual glitch involved!
Code:
# * Bug Fixes for Both of RMXP's Interpreter's Script Commands * #
#   2025-02-27 - The Infamous Version 5
#   It is the pretty much the same as Version 1 but it lets you prevent
#   the message window visual glitch from ever transpiring.

class Interpreter
  # * Conditional Branch * #
  # Altered the Script Condition at the very end of this command
  def command_111
    # Initialize local variable: result
    result = false
    case @parameters[0]
    when 0  # switch
      result = ($game_switches[@parameters[1]] == (@parameters[2] == 0))
    when 1  # variable
      value1 = $game_variables[@parameters[1]]
      if @parameters[2] == 0
        value2 = @parameters[3]
      else
        value2 = $game_variables[@parameters[3]]
      end
      case @parameters[4]
      when 0  # value1 is equal to value2
        result = (value1 == value2)
      when 1  # value1 is greater than or equal to value2
        result = (value1 >= value2)
      when 2  # value1 is less than or equal to value2
        result = (value1 <= value2)
      when 3  # value1 is greater than value2
        result = (value1 > value2)
      when 4  # value1 is less than value2
        result = (value1 < value2)
      when 5  # value1 is not equal to value2
        result = (value1 != value2)
      end
    when 2  # self switch
      if @event_id > 0
        key = [$game_map.map_id, @event_id, @parameters[1]]
        if @parameters[2] == 0
          result = ($game_self_switches[key] == true)
        else
          result = ($game_self_switches[key] != true)
        end
      end
    when 3  # timer
      if $game_system.timer_working
        sec = $game_system.timer / Graphics.frame_rate
        if @parameters[2] == 0
          result = (sec >= @parameters[1])
        else
          result = (sec <= @parameters[1])
        end
      end
    when 4  # actor
      actor = $game_actors[@parameters[1]]
      if actor != nil
        case @parameters[2]
        when 0  # in party
          result = ($game_party.actors.include?(actor))
        when 1  # name
          result = (actor.name == @parameters[3])
        when 2  # skill
          result = (actor.skill_learn?(@parameters[3]))
        when 3  # weapon
          result = (actor.weapon_id == @parameters[3])
        when 4  # armor
          result = (actor.armor1_id == @parameters[3] or
                    actor.armor2_id == @parameters[3] or
                    actor.armor3_id == @parameters[3] or
                    actor.armor4_id == @parameters[3])
        when 5  # state
          result = (actor.state?(@parameters[3]))
        end
      end
    when 5  # enemy
      enemy = $game_troop.enemies[@parameters[1]]
      if enemy != nil
        case @parameters[2]
        when 0  # appear
          result = (enemy.exist?)
        when 1  # state
          result = (enemy.state?(@parameters[3]))
        end
      end
    when 6  # character
      character = get_character(@parameters[1])
      if character != nil
        result = (character.direction == @parameters[2])
      end
    when 7  # gold
      if @parameters[2] == 0
        result = ($game_party.gold >= @parameters[1])
      else
        result = ($game_party.gold <= @parameters[1])
      end
    when 8  # item
      result = ($game_party.item_number(@parameters[1]) > 0)
    when 9  # weapon
      result = ($game_party.weapon_number(@parameters[1]) > 0)
    when 10  # armor
      result = ($game_party.armor_number(@parameters[1]) > 0)
    when 11  # button
      result = (Input.press?(@parameters[1]))
    when 12  # script
      result = eval(@parameters[1])
    end
    # Store determinant results in hash
    # Added pos variable for the sake of convenience
    pos = @list[@index].indent
    # Bug Fix - Turn any nil value into false by default
    @branch[pos] = !!result
    # If determinant results are true
    if @branch[pos]
      # Delete branch data
      @branch.delete(pos)
      # Continue
      return true
    end
    # If it doesn't meet the conditions: command skip
    return command_skip
  end
  # * Script Event Command * #
  # Just a small variant of a very old bug fix published by several people
  def command_355
    # Set first line to script
    script = @list[@index].parameters[0] + "\n"
    # Loop
    loop do
      # If next event command is second line of script or after
      if @list[@index+1].code == 655
        # Add second line or after to script
        script += @list[@index+1].parameters[0] + "\n"
      # If event command is not second line or after
      else
        # Abort loop
        break
      end
      # Advance index
      @index += 1
    end
    # Evaluation
    result = eval(script)
    # Removed Several Lines Here Before Continue
    return true
  end
end

The code below does work indeed, but as "Abe" Zeriab noted in the discussion thread it causes a minimal visual glitch that makes the message window disappear whenever the result is false. I suspect that shouldn't happen if the return value is nil based on my comments on how the Interpreter#update method works. Now you've been warned!

Version 4
Code:
# * Bug Fixes for Both of RMXP's Interpreter's Script Commands * #
#  2025-02-26

class Interpreter
  # * Conditional Branch * #
  # Altered the Script Condition at the very end of this command
  def command_111
    # Initialize local variable: result
    result = false
    case @parameters[0]
    when 0  # switch
      result = ($game_switches[@parameters[1]] == (@parameters[2] == 0))
    when 1  # variable
      value1 = $game_variables[@parameters[1]]
      if @parameters[2] == 0
        value2 = @parameters[3]
      else
        value2 = $game_variables[@parameters[3]]
      end
      case @parameters[4]
      when 0  # value1 is equal to value2
        result = (value1 == value2)
      when 1  # value1 is greater than or equal to value2
        result = (value1 >= value2)
      when 2  # value1 is less than or equal to value2
        result = (value1 <= value2)
      when 3  # value1 is greater than value2
        result = (value1 > value2)
      when 4  # value1 is less than value2
        result = (value1 < value2)
      when 5  # value1 is not equal to value2
        result = (value1 != value2)
      end
    when 2  # self switch
      if @event_id > 0
        key = [$game_map.map_id, @event_id, @parameters[1]]
        if @parameters[2] == 0
          result = ($game_self_switches[key] == true)
        else
          result = ($game_self_switches[key] != true)
        end
      end
    when 3  # timer
      if $game_system.timer_working
        sec = $game_system.timer / Graphics.frame_rate
        if @parameters[2] == 0
          result = (sec >= @parameters[1])
        else
          result = (sec <= @parameters[1])
        end
      end
    when 4  # actor
      actor = $game_actors[@parameters[1]]
      if actor != nil
        case @parameters[2]
        when 0  # in party
          result = ($game_party.actors.include?(actor))
        when 1  # name
          result = (actor.name == @parameters[3])
        when 2  # skill
          result = (actor.skill_learn?(@parameters[3]))
        when 3  # weapon
          result = (actor.weapon_id == @parameters[3])
        when 4  # armor
          result = (actor.armor1_id == @parameters[3] or
                    actor.armor2_id == @parameters[3] or
                    actor.armor3_id == @parameters[3] or
                    actor.armor4_id == @parameters[3])
        when 5  # state
          result = (actor.state?(@parameters[3]))
        end
      end
    when 5  # enemy
      enemy = $game_troop.enemies[@parameters[1]]
      if enemy != nil
        case @parameters[2]
        when 0  # appear
          result = (enemy.exist?)
        when 1  # state
          result = (enemy.state?(@parameters[3]))
        end
      end
    when 6  # character
      character = get_character(@parameters[1])
      if character != nil
        result = (character.direction == @parameters[2])
      end
    when 7  # gold
      if @parameters[2] == 0
        result = ($game_party.gold >= @parameters[1])
      else
        result = ($game_party.gold <= @parameters[1])
      end
    when 8  # item
      result = ($game_party.item_number(@parameters[1]) > 0)
    when 9  # weapon
      result = ($game_party.weapon_number(@parameters[1]) > 0)
    when 10  # armor
      result = ($game_party.armor_number(@parameters[1]) > 0)
    when 11  # button
      result = (Input.press?(@parameters[1]))
    when 12  # script
      result = eval(@parameters[1])
    end
    # Store determinant results in hash
    # Added pos variable for the sake of convenience
    pos = @list[@index].indent
    # Bug Fix - Turn any nil value into false by default
    @branch[pos] = !!result
    # If determinant results are true
    if @branch[pos]
      # Delete branch data
      @branch.delete(pos)
      # Continue
      return true
    end
    # If it doesn't meet the conditions: command skip
    return command_skip
  end
  # * Script Event Command * #
  # Just a small variant of a very old bug fix published by several people
  def command_355
    # Set first line to script
    script = @list[@index].parameters[0] + "\n"
    # Loop
    loop do
      # If next event command is second line of script or after
      if @list[@index+1].code == 655
        # Add second line or after to script
        script += @list[@index+1].parameters[0] + "\n"
      # If event command is not second line or after
      else
        # Abort loop
        break
      end
      # Advance index
      @index += 1
    end
    # Evaluation
    result = eval(script)
    # NEW: Single Line Script Call Bug Fix Inspired on the Original Condition
    # If return value is false OR nil
    unless result
      # Increase value of @index to prevent RMXP from getting stuck
      @index += 1
      # End
      return false
    end
    return true
  end
end

Obsolete Versions

Infrequently Asked Questions

Q: Has anybody else posted anything like this before?
A: Who knows? Who Knows? In any case I preferred to leave the script here just in case anybody fiddling with RMXP ever needs it.

Terms of Use

You can do whatever you want with it, I just built something upon somebody else's work and that's it.
[/spoiler]
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#2
Why I Had to Update The Script

Ever since RMXP came out, scripters had to deal with the dreadful Interpreter#command_355 aka script call method bug that made the maker get frozen if there was a single line call that ever returned a false value, not a falsey value like nil as Zeriab reminded us in another thread, but a pure false value (FalseClass object).

For about 2 decades all scripters including your servitor had been dealing with the symptoms but NEVER the actual illness this bug was causing. To better understand the issue, I'll explain it here from the very beginning.

Several bug fixes dealt with the result variable's false value that would freeze the script call event command by changing the if statement or by making it irrelevant aka non existing at all like it was the case in my now old solution. And there was Zeriab's own answer to the issue that relied on a wait command of sorts to get out of that horrible loop.

So far they seemed to work as intended, even if some people claimed that some solutions didn't consider all possible caveats for any given reason.

You see guys, THAT was the ACTUAL PROBLEM! Shocked Nobody was truly reading that piece of code properly! And when I say nobody, I truly mean it and I'm 100% certain that was the case here. Yeap, that nobody also included me, yours truly... until NOW!

This new version released on February 26th, 2025 finally dealt with the issue the way it should have been from the very beginning! Grinning

The problem was NEVER the if result == false conditional statement itself whenever you let it evaluate a single line of code.
Nope guys, that was the distraction that pesky Bug bug had prepared for us to survive another year! Angry Nasty little insect!

The actual issue was a lot simpler than that! Shocked

The command_355 method interrupted the @indes += 1 update the loop included if there was no other line of code included after the first one, that curiously has a different event command code that additional script call commands. THIS WAS THE REAL ISSUE! Incredible


Now my bug fix adds a @index += 1 fix under 1 single condition: to never find a secondary script call command right after the initial one (with a different event command code).

This means the following: RMXP no longer gets stuck there interpreting the same old script call event command forever and ever! Two Thumbs Up! 

Confused "Why not?", people like Melana might ask at this point.

It's very simple indeed! Grinning Now it can properly read the next event command, whatever that might be, because it successfully stopped testing the previous script call AS IT SHOULD HAVE BEEN the case from the very beginning. Winking It can't read a command that's already behind the current position due to the way the Interpreter was designed by the RM developers.

SPECIAL THANKS

I want to thank Zeriab Two Thumbs Up! not for giving us just an old way to "fix" the bug (that also worked fine), because ALL of OUR OLD solutions were nothing but WORKAROUNDS as I have exposed that here, but mainly because of his persistance in dealing with the Ruby interpreter, not to be confused with RGSS Interpreter at all. Happy with a sweat Well yeah, we have extensively talked about the Interpreter class here for sure.

EDIT

I had to update the latest version of my bug fixes because the command_355 fix actually introduced a new Bug bug. This means that I didn't notice that I misnamed the old_pos variable as old_post... Confused I guess I got pranked by the fact I was talking about old posts or the autocorrection feature did it again and I failed to realize it in time. Yet, Dog Wulfo already let me know about that bug and I gladly smashed it to smithereens already.
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }
#3
Why I Had to Update The Script Once Again

After receiving some Bug bug reports by someone Dog I won't mention here, I noticed something ELSE. Yes, that was NOT the end of the story, guys. Incredible
Fine, Melana. Boring Start complaining now Laughing because you gotta keep Book reading to find out what else has transpired in the maker world since my previous post.

What I told you before was half the truth of what had occurred to RMXP's Interpreter class.

SUMMARY
  • The issue that made the RMXP engine get stuck after a script call event command was a real pain you know where. Tongue sticking out
    Both false and nil results, both considered falsey values, were the worst nightmare Freddy Kruger RMXP Interpreter class had ever experienced.
  • if result == false conditional statement was not the true culprit.
    That was nothing but a goon, but the actual mastermind was in another castle, Mario! Laughing
    It just was a symptom of a bigger issue we had not detected before or preferred to ignore it altogether for undisclosed reasons.
  • @index += 1 addition was mandatory for sure.
    Yet, the condition that made it relevant according to my previous post was WRONG. Thus, it had to be replaced by another one.
  • The need for preparing the event for processing the next event command was real.
    Again, what was terribly wrong was the condition that would apply the fix where it was relevant.
  • I had introduced another Bug bug because of ignoring the second point indeed.

THE ROOT CAUSE

It was located in the Interpreter class for sure but it was in the script section known as Interpreter 1. There you can find a method called update which is very important, especially true if you're an eventer. Yes, eventers depend on it 100% or else they'd lose control of the map forever and ever Happy with a sweat or till they finally Killer kill the application.
There returning a false or nil value as the end result of execute_command event command became a terrible issue!
Yes, I know that this part of the explanation sounds rather old, yet, that's on purpose even if that's not the end of the story. Shocked

Why is it important?

You would understand the issue if you focus on this section of the update method:

Code:
if execute_command == false
  return
end

What you can read there created the issue, even if it was not supposed to. You see, there are other methods that return a false value on purpose! Feeling sick What a mess!

After analyzing those other methods, I came up with 1 out of 2 simple conclusions.

1. They had something in common: they were disruptive by nature! Shocked

If you called another type of scene or a gameover or anything the like, the engine was supposed to halt the execution of the update command ASAP.

2. Script Call event command was ALSO supposed to be just as disruptive as the calls to other scenes if the end result was false.

Here I guess that the Script Call command was intended to be used as some sort of multi-line condition and not really as an evaluation of a whole script or an internal or external method call. The only "official" way to prevent this from ever happening was to return true at the end of our call.

Where did I get that?

If I had only purchased RMXP, I'd probably still ignore the real issue. Nonetheless, having legal access to RMVX and RMVX ACE widened my perspective quite a bit. IIRC, you won't find the exact same issue there, especially in VX ACE. For some reason I haven't studied so far, VX does have a problem with either false or nil values, but only one of them is a pain...

VX ACE actually changed the way the methods are executed, by not testing the result of evaluating the script, to prevent it from changing the event processing based on its interpretation of that old event command over and over again, freezing the maker permanently. OR ignoring the event commands that come after a script call with false or nil as its return values.

The Real Fix

This is the most excentric part of the whole story. It's a mix of the good old "change the value of the result local variable" approach PLUS my @index += 1 increase without ignoring the issues caused by nil. The thing is that I had to properly find the best place to change the @index without altering any other event commands. That perfect place is inside the very same condition that started it all: if result == false itself! Laughing
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply }


Possibly Related Threads…
Thread Author Replies Views Last Post
   The Steal and Peep Script DerVVulfman 12 758 02-19-2025, 07:20 AM
Last Post: Ace_V
   Text Scroll Script - Enhanced DerVVulfman 23 36,129 02-18-2021, 04:16 AM
Last Post: DerVVulfman
   Cursor Script Selwyn 7 16,257 09-28-2019, 02:13 PM
Last Post: DerVVulfman
   ACBS FIX SCRIPT #2: Advanced Cry Correction DerVVulfman 1 5,056 08-09-2019, 03:42 PM
Last Post: aeliath
   ACBS FIX SCRIPT #1: Victory Cries Patch DerVVulfman 1 5,159 08-08-2019, 02:53 PM
Last Post: aeliath
   Spritesheet Generator Conversion Script DerVVulfman 0 4,577 11-21-2018, 04:48 AM
Last Post: DerVVulfman
   Event Spawner Fixes DerVVulfman 8 17,796 01-02-2018, 05:48 AM
Last Post: DerVVulfman
   Neo Mode 7 Script by MGCaladtogel MGC 59 130,178 09-29-2017, 03:48 AM
Last Post: DerVVulfman
   Longer Script Calls LiTTleDRAgo 0 5,196 05-17-2017, 12:36 AM
Last Post: LiTTleDRAgo
   SLOLS: Snake Look-alike on Load Script Zeriab 3 11,859 05-14-2017, 06:25 PM
Last Post: LiTTleDRAgo



Users browsing this thread: 2 Guest(s)