Room Enter

Can I make multiple (universal) copies of 'Script when entering a room'? (So that I can...sort them...again...)


Not easily. But there's nothing to stop you making multiple script attributes, or multiple functions, and having the main roomenter script just run all of them.

But this time, I'm wondering why you would want more than one. A request like this makes me wonder what you're putting in there that's complex enough to need splitting up. In most of the cases that come to mind, there might be a simpler way to do it.


Was just searching for some alternative for universal scripts. I didn't end up needing them in the end.


Just noticed this thread recently, and it helped me solve a problem with my game -- I wanted to randomly select one of my game's many rooms, and then add to (rather than simply replace) that room's enter script. The problem was that many of my rooms already had their own customized enter scripts, while other rooms simply had an empty enter script. So just replacing the random room's enter script wouldn't work, as I would lose the original scripting, if any.

MrAngel's comment was enlightening:

But there's nothing to stop you making multiple script attributes, or multiple functions, and having the main roomenter script just run all of them.

The answer, then, was to first copy the room's enter script attribute to a new (backup) script attribute:

RandomRoom.EnterBackup = RandomRoom.enter

Then I replaced the room's enter script by setting that attribute to a new script, one that calls a function that I created:

RandomRoom.enter => {
  NewFunction
}

The function then runs the backup script attribute, plus whatever additional scripting that I wanted:

do (RandomRoom, "EnterBackup")
// additional scripting follows

So, in effect, the function runs the room's original enter script, plus my added scripting. The only wrinkle is that the new function has to check to see if the backup script attribute is null, and then only run it if it isn't null (otherwise Quest will print an error message if it is null):

if (RandomRoom.EnterBackup <> null) {
  do (RandomRoom, "EnterBackup")
}

Seems simple in hindsight, but I couldn't think of this solution at the time! Thank you again MrAngel!


That seems like quite a complex way to do it.

If there's only one script you're adding to a room in this way, you could just use a flag:

RandomRoom.RunNewFunctionOnEnter = true

And then in your game.roomenter script, put:

if (GetBoolean (game.pov.parent, "RunNewFunctionOnEnter")) {
  NewFunction ()
}

No need to change the enter script.

If you've got several functions that might be added, you can just add a separate flag for each; and you don't need to check if a EnterBackup already exists.

If you have multiple scripts that a random room could be set to, but you don't want it to run more than one, it's probably good adding a script attribute. But it seems simpler to just add a new ExtraEnter script and run it from roomenter, rather than changing the existing enter:

if (HasScript (game.pov.parent, "ExtraEnter")) {
  do (game.pov.parent, "ExtraEnter")
}

Although I have in the past used a method like this, which allows you to add multiple different scripts to a room, and control which order they run in, by making the room's enter attribute a list of scripts:

  1. To add a new function after the existing enter script:
enters = NewList ()
switch (TypeOf (RandomRoom, "enter")) {
  case ("list") {
    enters = RandomRoom.enter
  }
  case ("script") {
    list add (enters, RandomRoom.enter)
  }
}
newscript => {
  NewFunction ()
}
list add (enters, newscript)
RandomRoom.enter = enters
  1. To add a new function before the existing enter script:
enters = NewList ()
newscript => {
  NewFunction ()
}
list add (enters, newscript)
switch (TypeOf (RandomRoom, "enter")) {
  case ("list") {
    enters = ListCombine (enters, RandomRoom.enter)
  }
  case ("script") {
    list add (enters, RandomRoom.enter)
  }
}
RandomRoom.enter = enters
  1. The game.roomenter script to make it work:
if (TypeOf (game.pov.parent, "enter") = "list") {
  foreach (script, game.pov.parent.enter) {
    game.pov.parent.tempenter = script
    do (game.pov.parent, "tempenter")
  }
}

The reason I didn't use roomenter was because I did not want to add to the turn-by-turn "overhead" of my game. But it would be more straightforward to do it that way.

As for making an attribute a list of scripts, I didn't even know that could be done! I thought that lists had to be either string or object lists. Thanks for sharing something new (at least, to me)!


I do like efficient code; but I think that a singe HasScript call is simple enough to make little difference (especially compared to some of the code that's already in the core).

If you wanted to use the list method without checking for it every turn, you could have a separate attribute for a list of scripts. Something like:

newscript => {
  Whatever()
}
if (HasAttribute (room, "multienter")) {
  list add (room.multienter, newscript)
}
else if (HasScript (room, "enter")) {
  room.multienter = NewList()
  list add (room.multienter, room.enter)
  list add (room.multienter, newscript)
  room.enter => {
    foreach (script, this.multienter) {
      invoke (script, QuickParams ("this", this))
    }
  }
}
else {
  room.enter = newscript
}

This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums