Is there an easier way to do this? (set_withut_changedscript() function)

Hey;
Just found myself wanting to move the player without calling any OnExit or OnBeforeEnter scripts. Then I realised there's a few cases where I might want to ignore things that are triggered by a changedscript. So I threw this together.

Is there an easier way to do it?

<function name="set_without_changedscript" parameters="object, attribute, value">
  if( HasScript(object, "changed"+attribute)) {
    changedscript = GetAttribute(object, "changed"+attribute)
    set_without_changedscript (object, "changed"+attribute) {
      // do nothing
    }
    set (object, attribute, value)
    set_without_changedscript (object, "changed"+attribute, changedscript)
  }
  else {
    set (object, attribute, value)
  }
</function>

And have I messed something up there, or has the server just gone down again?


This is how I teleport.

Make an object. Name it "Teleport 1."
Check the take feature.
Edit the use command. (It seems simpler to me.)
Run script.
Type this;

MoveObject (player, Battle Room)

It moves player to the battle room.
I also have a teleport system from hegemankhan that works like this. Link. Scoll down to 3/4 way. http://textadventures.co.uk/forum/samples/topic/vg6jtjrayesr4e5kqqytig/simple-combat-code-update-working-on-a-new-system

I don't know anything about changed scripts.


Update: It appears this works for other attributes, but not for parent. I don't know why not.

jmnevil54: Does using MoveObject() not trigger the OnExit script for the room you're currently in? Looking at the code I'd expect it to, but I haven't actually tried it in this case.


I don't use OnExit, but I assume it works like the after leaving the room script. The script still works. Everything works fine.

Correct me if I'm wrong, though.


On further investigation, I can add the following ugly bodge:

<function name="set_without_changedscript" parameters="object, attribute, value">
  if ( object = game.pov and attribute = "parent") {
    // Yes, I know that the game.changedpov script will assign 'this' a load of irrelevant attributes,
    // but as far as I can tell that won't break anything, or matter in future
    game.pov = this
    object.parent = value
    game.pov = object
  }
  else if( HasScript(object, "changed"+attribute)) {
    changedscript = GetAttribute(object, "changed"+attribute)
    set_without_changedscript (object, "changed"+attribute) {
      // do nothing
    }
    set (object, attribute, value)
    set_without_changedscript (object, "changed"+attribute, changedscript)
  }
  else {
    set (object, attribute, value)
  }
</function>

jmnevil54
OnExit IS the after-leaving-room script.

I specifically said in the first post, I want to move the player without triggering the on-leave or on-enter scripts for the rooms they're moving between.

If the script "works fine", I assume that means that it's not a good way to stop that script from being called.


The containment heirarchy is actually controlled by the built-in 'parent' Object (reference/pointer) Attribute:

player.parent = room
// or
set (player, "parent", room)
// or
MoveObject (player, room) // this is just a helper Function, which just does: player.parent = room // or: set (player, "parent", room)
//
// are the same as this:

<object name="room">
  // not shown by default (due its parent being the 'asl' GAME OBJECT, which is expressed as 'null'): <attr name="parent" type="object">null</attr>
  <object name="player">
    // not shown by default (due to being nested), but this is what it is: <attr name="parent" type="object">room</attr>
  </object>
</object>

// or:

<object name="room">
  // not shown by default (due its parent being the 'asl' GAME OBJECT, which is expressed as 'null'): <attr name="parent" type="object">null</attr>
</object>

<object name="player">
  <attr name="parent" type="object">room</attr>
</object>

but, I do believe that all of these methods activate the various other scripts... as they're all ultimate controlled by the 'parent' Object (reference/pointer) Attribute, which is likely programmed to handle all of those other scripts


thus, you'd need to edit the built-in code for handling the 'parent' Object (reference/pointer) Attribute, to add in code that controls whether those other scripts are fired/activated/run/executed or not.


@hegemonkhan

The containment heirarchy is actually controlled by the built-in 'parent' Object (reference/pointer) Attribute:
MoveObject (player, room) // this is just a helper Function, which just does: player.parent = room

Yes; I know.
This is why in the first post, I was moving the player by changing game.pov.parent

but, I do believe that all of these methods activate the various other scripts

Yes.
When you change player.parent, it automatically runs the script player.changedparent, which calls all the other scripts (including the OnExit, BeforeEnter, ShowRoomDescription, OnEnter, and changing the grid/map for your new location.

This is why in the first post I have a function which removes the script named "changed"+attribute, changes the attribute, and then puts that script back where it was.

Unfortunately, this doesn't seem to work for parent. It seems that this one attribute is special somehow. Still trying to figure out why. Currently trying to pull myself out of a panic attack, so my reasoning may not be quite sound right now, or I might have missed something.

Might try again in the morning.
Still, at least I have a workaround. Just temporarily change which object is the player object, to one that won't be moving and doesn't have a changedparent script for another reason. Making the player temporarily be a function seems to work fine.


I'm sure somewhere in the built-in (user-level) code (or the underlying source code), you can modify this behavior of the 'parent' Object (reference/pointer) Attribute.... but... you got to find (dig for) it... of course... lol:

built-in code:

GUI/Editor: (lower left corner) Filter -> Show Library Elements -> (toggle it on / check in the box) -> light-grey text in the "tree of stuff" above) -> Copy (right side) -> modify the code to what you want it as

or, just go into the 'quest 5' folder and its sub folders (mainly the 'core' sub folder), and right click on the files, opening them with a text editor software (notepad, wordpad, Apple: text editor, notepad++, etc)

underlying source code:

https://github.com/textadventures/quest
^^^^^^^^^^^^^^^^
https://github.com/textadventures/


Is this because you are using it in the start script? Quest calls OnEnterRoom after running the start script, just like the change script does.

I have just been trying this out, and it looks like your original function works, it just looks like it doesn't if used in game.start!


Weird…
I thought it should work, I can walk through the code in the Core functions manually.

In the end I had a different solution to this particular problem; realising that the exit scripts I was having trouble blocking weren't actually necessary.

Now the thing that's confusing me is room descriptions. I've got a BeforeEnter script that prints a message and bounces the player to a random room.

So my BeforeEnter script is:

msg ("You get lost")
msg ("DEBUG: Redirecting to room "+this.targetroom.name)
set_without_changedscripts (game.pov, "parent", this.targetroom)
msg ("DEBUG: The enter/exit scripts shouldn't have fired?")

Now that I've removed the offending exit script, the output is simply:

You get lost
DEBUG: Redirecting to room woods_C1
You are in a woods_C1.
You can go east, south or north.
DEBUG: The enter/exit scripts shouldn't have fired?

You are in a woods_C1.
You can go north, east or south.

I've also tried using game.pov.parent = this.targetroom bracketed by temporarily setting game.showdescriptiononenter to false and restoring it afterwards, which I'm absolutely sure should work, but it doesn't. I must be missing something really obvious.
Or there's a typo somewhere that I completely missed. Or I'm misunderstanding the flow of control that gets to ShowRoomDescription. Or there's a difference between the Core scripts I've downloaded and the ones used by the online editor. Or the online editor manages to cache some bits of the script, so when I hit 'play' I get a bizarre mix of old and new code… I really hope that's not the case.

Now my brain's back on form (I hope), I might go back to playing with this. Or work on actual code.

Oh… an aside. In the course of poking through the code I came across something that looks like it might be a gotcha for some game creators. (Unless I'm misreading it) In Core.aslx, line 356:

      if (game.showhealth) {
        newPOV.health = 100
        newPOV.changedhealth => {
          ... etc ...

This means that if you're using the default health system, a playable object's health attribute will be set to 100 the first time it is used as the player object. A designer who wants to have the player start with less than full health (whether it's your normal player object, or having a flashback to being a legendary hero in the middle of a battle so you can learn firsthand about the game world's history) ... they might try setting the 'health' attribute for a player object in the editor, and then be surprised that it doesn't work. I can imagine that would be really confusing for someone to debug.

I would suggest that these lines should be guarded by if (not HasInt (newPOV, "health")) { and if (not HasScript (newPOV, "changedhealth")) { respectively; allowing the user to override them in the same way they can most attributes.

(I was previously working on a game where a part of the gameplay was the ability to possess NPCs, and different people could get into different places. I would have been rather confused if I added the ability to possess an enemy during a battle, only to find that doing so mysteriously heals any damage they've taken, but only if it's a person you haven't been before)


If you move the player in the enter script of a room...

When you enter the first room, Quest will run OnEnterRoom, which will invoke the script that moves the player to the second room, and then will run the OnEnterRoom script for the new room, which will print the description of the current room. Then Quest goes back to the first `OnEnterRoom, which will print the description of the current room.

So you end up with the description of the second room twice, and no description from the first.


Pixie: Yep, that was my interpretation.
But why does my set_without_changedscript function not prevent OnExit, ShowRoomDescription, OnEnter for the second move?

I would think that it should run the before-enter script for the room in the middle, which moves you to the new one but doesn't invoke changedparent. Then control returns to the changedparent script that was run by the initial move, which calls the OnEnter and ShowDescription scripts 9but not BeforeEnter, because it's already done that) for the new room.

Wait ... is it a problem with assigning a new value to a script object that's currently running?

Have previously used (in different circumstances): a script which when run, changes itself to a different script. The script that's running carries on running to the end, but any subsequent calls to the same script will execute the new one. This is exactly what I'd expect to happen.

But this time, I'm doing: a script which, when run, replaces the script attribute with a different script, then calls that script. And appears to still call the previous version.

Am I running into some code-cache issues? Like… if I call set_without_changedscripts(obj, att, value) from within the changedatt script, will Quest use the same changedatt script again and not notice that it's been removed?
Trying to think of a simple testcase for that is making my brain hurt.


OK, got it.
It's recursion that's the problem. The function shown in my first post works, unless you are calling from within the changedscript for the same attribute. This means that you can use this function to change player.parent, and doing so suppresses the OnExit, OnEnter, ShowDescription, etc... but it fails if you use it within one of those scripts.

That's a weird behaviour.

Edit: No, something weird is going on. The editor game me "an internal error has occurred" and reloaded itself three times in a row; and then my original code suddenly works as intended.
(very, very confused)


(there's a couple of rooms that were having this issue. While testing different theories I just kept changing one of them. Can confirm that they all now seem to work. So... when I was testing last night and earlier this morning, it was just the editor being weird at me?)


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

Support

Forums