Techniques for writing compatible scripts

Compatibility is important if you’re ever planning to use someone else’s scripts, even if you’re planning to write most of the scripts for your project.

Here is a list of things that I usually try to do when I’m writing scripts.
Feel free to add more or comment on the ones I’ve written.

Avoid overwriting

Overwriting is ok, until another script is overwriting the same thing.
Example:

Script 1:

def my_method
  return 1
end

Script 2:

def my_method
  return 2
end

Even for experienced scripters, this is very difficult to resolve. One script expects it to return 1, while another script expects it to return 2. How would you fix this without changing the scripts completely to point to a different method?

In general, if you find yourself overwriting code, then it’s a sign that your code (or the code you’re overwriting) is not designed very well in terms of compatibility.

Minimize logic in your methods

Or, in software design principles, Often times, coders are tempted to simply write everything inside a single method.
Why not? It works, it seems logical, and some may argue that it’s more efficient to avoid making too many method calls.

Example:

def calculate_damage(target, item)
  damage = item.eval_damage

  # apply guard modifier
  damage *= 2 if guarding?

  # apply element modifier
  damage *= 2 if self.weak_to_item_elements?(item)

  # apply the damage
  target.apply_damage(damage)
end

This is a very straightforward piece of code that calculates damage: you evaluate the base damage, apply some modifiers, and then apply it to the target.

But what happens if want to add an extra calculation?
Or you don’t want to consider elements?
Or you don’t want to apply the damage to the target?

You have to overwrite the method.

In RM scripting, it is much easier to add new logic using aliasing, and the more methods you break your logic into, the easier it is to extend without overwriting.

Consider an alternative

def calculate_damage(target, item)
  damage = get_base_damage(item)
  damage = apply_guard_modifier(damage, target, item)
  damage = apply_element_modifier(damage, target, item)
  return damage
end

Note that all of the logic has been separated into their own methods, and the method simply returns the final value (which you can then extend if necessary). The actual “apply damage” step is moved elsewhere, since it is not related to calculating damage.

Reduce overwritten code

Sometimes you are forced to overwrite code, but even if you do, there are ways to improve compatibility and make it easier for others to deal with it depending on what you actually need to add.

If possible, move all of the custom logic into a separate method, so that if someone’s scripts are incompatible with yours, you can just say “add this one line here” instead of saying “you’ll have to figure out how to mix the two together”

Preserve return values

If a method returns a number, and you want to extend it, make sure that it still returns a number. Other code that’s using that method likely expects it to return what they think it returns, and if you suddenly decide to return nil or a string, you’ll probably break all those other scripts since they weren’t expecting anything but a number.

Preserve method signatures

If a method expects you to pass in 2 arguments, don’t change those 2 arguments. The method that you are trying to extend may be used by other scripts, and if you change the arguments, other scripts that expect the method to take certain arguments will likely fail.

Pass all parameters to other methods

If your method accepts arguments and will call other methods, do everyone a favor and pass on those arguments. Consider the calculate_damage example: it takes a target and an item, and passes it on to other methods.

Even if you don’t need it, someone else might, and if you chose not to pass it in because you didn’t see any reason to, they’ll probably have to overwrite your method to accomplish what they want to do.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *