ASLEvent fires turn scripts

It looks like an ASLEvent calls a UIEvent, which passes the parameter through cef, which sends a sort of command through, which causes the turn scripts to fire. (I don't think it actually finishes the turn, but I'm not certain.)

My mission is to set attributes in the game from JS values without firing turn scripts.

Anyone have any ideas, suggestions, or know-how?


PS

Adding something to the source code is fine with me.

I could do it in vb.net or c# in the source code, or I'd also be happy just doing it in the game's code.


Someone reported this as a bug with regards to clicking on the map, which calls ASLEvent. I had a look at the code, and it is buried deep in C#, so next version of Quest just has an option to turnmap clicking on or off, which does not help this at all.


I thought about setting a boolean attribute, changing it to true when calling an ASLEvent, then having the turn scripts function not fire if that value is true, but I decided that sounded really dangerous.

The main reason I was fooling with this was to make the desktop player save a transcript as a text file, appending said .txt file each time something printed in the game (just like the INFOCOM games do).

I actually just found some code online that I think is working (as far as the transcript is concerned). (Check it out in your email, Pix. Should be the last one I sent.)


As far as the ASLEvent goes, I found the same thing as you: C#. I can sort of see where it is sort of ending a turn (kind of), but... C#...

I just can't hit that note quite yet.


As far as the ASLEvent goes, I found the same thing as you: C#. I can sort of see where it is sort of ending a turn (kind of), but... C#...

It looks like it may be using the same code that handles a command (as far as I can tell). and changing it could easily have undesirable side effects. One to put on the back-burner.


I think the only purpose of the ASLEvent was to send a command when it was birthed.

I came back here to say so, but you beat me to it, Pixie.

Pertex slid that one function right into the code to read an online file, so I'm thinking a separate function might be a possibility. If I can only find a way to pass a string from JS to something else (probably C#), I can get it. (It's like a personal thing at this point. It may lack purpose or mess something else up, but I'd be happy to remove it, once it does what I want it to. (I'm the master. The computer is the slave. You understand where I'm coming from; right?)


SUCCESS!!!

I went in Visual Studio and searched for ASLEvent, which led me to UIEvent, which led me to SendEvent.

I copied every SendEvent() function in every file, pasted just below it, and renamed the copied function SendAttribute().

Then I commented out the line that finished the turn (TryFinishTurn()):

        public void SendAttribute(string eventName, string param)
        {
            Element handler;
            m_elements.TryGetValue(ElementType.Function, eventName, out handler);

            if (handler == null)
            {
                Print(string.Format("Error - no handler for attribute '{0}'", eventName));
                return;
            }

            Parameters parameters = new Parameters();
            parameters.Add((string)handler.Fields[FieldDefinitions.ParamNames][0], param);

            RunProcedure(eventName, parameters, false);
            if (Version >= WorldModelVersion.v540)
            {
                //TryFinishTurn();
                if (State != GameState.Finished)
                {
                    UpdateLists();
                }
                // Might need to lose this next line, too. **KV
                SendNextTimerRequest();
            }
        }

It seems to work just fine, but I know that is...

I'm trying to break it right now.

...but all you need to do is use ASLAttribute in place of ASLEvent. Everything else is identical. It just doesn't try to finish the turn. (Whoo-hoo!)


It passes all the tests, too!

Yay!

image


Did you test the WebPlayer?

If so, make a pull request.


you may also want to research (find and study) the 'TryFinishTurn ()' Function too, and see where it is, what uses it, and what it does.

great work KV... let's hope it works in the webplayer... and you got a deep code contribution to quest, hehe. Maybe, Pixie and co, should have you join the quest development team, hehe. Get QuestKit working, winks, laughs.


I'm about to test it on the web player now. (I've never tried to run the web player before, so it may be a bit before I return. Reading Pixie's wiki page concerning this as soon as I click 'Post Reply'.)


It appears to work in the web editor, too.

All the JS functions react a little strangely when I enter a command that uses JS.eval to do anything (not just my new function), but opening up the Developer console and calling functions from there works perfectly.

I am assuming this is because I am hosting it locally, but I hate to assume anything...

Also, I can't make the web editor find the path to Play.aslx. Tried the actual path, then I tried file:///path/to/file, but nothing works.


I got it.

<?xml version="1.0" ?>

<!-- After entering settings, this file should be saved as WebEditorSettings.xml -->

<appSettings>
  <add key="PlayURL" value="http://localhost:52426/Play.aspx?id=1"/>
  <add key="PublishURL" value="http://path/to/publish/app/"/>
  <!-- To enable logging, uncomment this line, and create a log config XML (see WebPlayerSettings.default.xml for example) -->
  <!-- <add key="LogConfig" value="C:\Path\To\Config\File\logging.xml"/> -->

  <!-- PLUGINS -->

  <!-- Specify the type name of a class that implements IFileManager -->
  <!-- <add key="FileManagerType" value="SomeFileManager.FileManager, SomeFileManager"/> -->

  <!-- DEBUG PLUGINS -->

  <!-- OR, when debugging, use the Debug Plugins -->
  <add key="FileManagerType" value="WebEditor.Services.DebugEditorFileManager, WebEditor"/>
  <add key="DebugFileManagerFile" value="C:\Users\kv\Documents\Quest Games\The JS Return\The JS Return.aslx"/>

</appSettings>

Okay, it does the same thing with the current version of Quest. It must be something with the JS and the server running from a local host?

...but the web editor doesn't load half of the time because Visual Studio deletes CoreFunctions.aslx from "WebEditor\WebEditor\bin\Core" as soon as you press F5 to start everything up. (I don't know why it does this. I assume it's a bug with something in Visual Studio.) BUT, one in ten times, the file did not get deleted, and the editor loaded and worked. It even saved the changes to my game file on my hard drive. ...and it played when I clicked 'Play'.

Even in the standard version of Quest's build, with a newly created game which called ASLEvents, the events did not fire when playing the web player from Visual Studio. They DO fire from the desktop player, though.

I also get an error about KeepAlive.ashx, but this is most definitely something which needs to contact the actual server to return something. (I bet it is an attempt to keep the game from timing out.)


If it deletes anything (which is does 9 times out of 10), Visual Studio always deletes the same three files when starting up the web editor:

CoreFunctions
CoreEditorObjectWearable
CoreEditorAnnotation

...and this happens with every version of Quest, back to 571. Whether it's got some files I've modified or not.

I can copy those files into a different folder, then drop them back in once they're deleted, and the editor loads right up.

It may be my PC, or it may be VS, or it may be a security issue with JS...

...but it happens with things I haven't modified at all. I bet my nickel it's a security issue.

So, I'll be submitting the pull request soon.


Before I begin, the ASLAttribute function works perfectly in the desktop version which is built in this same project.

This is all about playing a game on the web player when it is being hosted on a local server via Visual Studio 2015.


To be thorough, I did this:

  • Cloned the quest repo on a totally different machine

  • Created a new test game. It only calls ASLEvents, and was made in Quest 572 on the desktop.

  • Ran the web player from Visual Studio (without changing anything at all; I only clicked 'Build', then switched to the WebPlayer, then pushed F5)

    • the ASLEvent misbehaves in the same exact way. It will only work one time.
  • Opened the HTML Developer thing in my browser.

  • Entered the JS ASLEvent function from the console, and it worked that way.


  • Added the new code into the newly cloned repo.

  • Cleaned then rebuilt Quest.

  • Added the ASLAttribute call to the game.

  • Ran the web player.

  • It is the same thing as before. I can call ASLEvent() or ASLAttribute from the developer console, but it will only run one ASL Event or Attribute which is called from the game at one time. It doesn't matter if it's an ASLEvent (which I did not modify) or an ASLAtrribute (which I just added). It also doesn't matter if it's a version of Quest I've added the new code to. One ASLEvent is all I get out of the web player when Visual Studio is hosting the game on a local server.


CONCLUSION

This works. the ASLEvent is just finicky when running the web player this way.

I am submitting the pull request now.


PS

If my conclusion is incorrect (or might be), that will not upset me, but I would wish to be enlightened as to the reason(s), just so I can learn stuff.


Here's the skinny on TryFinishTurn(), HK.

I don't want any of this to happen when I only need to retrieve a value from JS.

ASLEvent() calls this to finish the turn because (I think) it's sole purpose was always to click on something which executed a command, therefore a turn needed to roll.

ASLAttribute() is a copy of ASLEvent(), except the part of the script that calls TryFinishTurn() is commented out.

private void TryFinishTurn()
        {
            TryRunOnFinallyScripts();
            if (!m_callbacks.AnyOutstanding())
            {
                if (m_elements.ContainsKey(ElementType.Function, "FinishTurn"))
                {
                    try
                    {
                        RunProcedure("FinishTurn");
                    }
                    catch (Exception ex)
                    {
                        LogException(ex);
                    }
                }
            }
        }

        private void TryRunOnFinallyScripts()
        {
            if (m_callbacks.AnyOutstanding()) return;
            IEnumerable<Callback> onReadyScripts = m_callbacks.FlushOnReadyCallbacks();
            foreach (var callback in onReadyScripts)
            {
                RunScript(callback.Script, callback.Context);
            }
        }

Could we call it ASLMessage or something?


We certainly can.

I just picked ASLAttribute because I was only thinking of using it to set attributes.

How about ASLSet?

...or ASLMessage is perfectly fine, too.

...but I was only calling a function that simply printed a message to show it in action. I'd really use it to get return values from JS functions (like retrieving the actual time and date, and easily pulling the displayed text out of HTML).

As long as it doesn't finish the turn, we could call it ASLAntidisestablishmentarianism as far as I'm concerned. (I'd type it out!)


Seriously, though: Just say the word, and I'll change it to ASLMessage in the pull request.


I was thinking "message" in the object-orientated sense where calling a method (function) on an object is also called sending a message to it.If that is not clear, may not be such a good idea.

ASLCall maybe?


Oh.

Well, I learned something today!

ASLMessage or ASLCall...

Either sounds good to me. (ASLCall is easier to type.)


Duplicate post removed


I believe I've found a fix which doesn't involve tampering with the source code.


Here is the modified FinishTurn() function:

  <function name="FinishTurn">
    if (not HasAttribute(game,"aslcalling")) {
      game.aslcalling = false
    }
    if (not game.aslcalling) {
      RunTurnScripts
    }
    if (game.aslcalling) {
      game.aslcalling = false
    }
    UpdateStatusAttributes
    CheckDarkness
    UpdateObjectLinks
  </function>

...and here is the new AslCall() function:

  <function name="AslCall" parameters="data">
    game.aslcalling = true
    stuff = Split(data,"=")
    obj_attr = stuff[0]
    obj_attr = Split(obj_attr,".")
    obj = obj_attr[0]
    obj = GetObject(obj)
    attr = obj_attr[1]
    val = stuff[1]
    if (EndsWith(val,"_toInt")) {
      val = ToInt(Replace(val,"_toInt",""))
    }
    else if (EndsWith(val,"_toDouble")) {
      val = ToDouble(Replace(val,"_toDouble",""))
    }
    set (obj, attr, val)
  </function>

The example game:

http://textadventures.co.uk/games/view/ah1jc6dzt0osqapak9ulya/aslcalling

NOTE: When playing online, the . in a double is printed as a ,.

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="AslCalling">
    <gameid>e7a54f73-820c-4f97-97f8-e00327fe4ddf</gameid>
    <version>0.2</version>
    <firstpublished>2018</firstpublished>
    <description>Example game.</description>
    <attr name="autodescription_youarein" type="int">0</attr>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <description><![CDATA[{command:LOOK} or {command:WAIT} to finish a turn.  <br/><br/>The ASLEvents in this game's start script will not finish turns.  (This will work in scripts other than the starts script.  I'm just lazy.)<br/><br/><hr/><br/>After causing a single turn to pass, you might as well  quit.<br/><br/><hr/><br/>THANK YOU FOR PLAYING THIS EXAMPLE GAME!<br/><hr/>]]></description>
    <enter type="script">
      JS.eval ("ASLEvent('AslCall','player.aslcall_aka=KV||player.aslcall_int=42_toInt||player.aslcall_double=1.21_toDouble');")
    </enter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
  </object>
  <turnscript name="turnscript_msg">
    <enabled />
    <script><![CDATA[
      msg ("<br/>FIRING TURN SCRIPTS!<br/><br/>player.aslcall_aka = {player.aslcall_aka}<br/><br/>player.aslcall_int = {player.aslcall_int}<br/><br/>player.aslcall_double = {player.aslcall_double}")
    ]]></script>
  </turnscript>
  <function name="FinishTurn">
    if (not HasAttribute(game,"aslcalling")) {
      game.aslcalling = false
    }
    if (not game.aslcalling) {
      RunTurnScripts
    }
    if (game.aslcalling) {
      game.aslcalling = false
    }
    UpdateStatusAttributes
    CheckDarkness
    UpdateObjectLinks
  </function>
  <function name="AslCall" parameters="data">
    game.aslcalling = true
    data = Split(data,"||")
    foreach (bit, data) {
      stuff = Split(bit,"=")
      obj_attr = stuff[0]
      obj_attr = Split(obj_attr,".")
      obj = obj_attr[0]
      obj = GetObject(obj)
      attr = obj_attr[1]
      val = stuff[1]
      if (EndsWith(val,"_toInt")) {
        val = ToInt(Replace(val,"_toInt",""))
      }
      else if (EndsWith(val,"_toDouble")) {
        val = ToDouble(Replace(val,"_toDouble",""))
      }
      set (obj, attr, val)
    }
  </function>
</asl>

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

Support

Forums