Code for Printing an Image instead of a Standard Map Room? [mostly mostly FINITO]

When the map displays a new room, how do you display a picture instead of the 1x1 room? Something to do with "img src"...


K.V.

I can't figure it out.

This is the best I've come up with (displays an image INSTEAD OF THE MAP while in another room):

EDITED

<!--Saved by Quest 5.7.6596.21854_KVMod-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Map Test">
    <gameid>22dff91e-f9d0-4446-b6a5-000c32b50197</gameid>
    <version>1.0</version>
    <firstpublished>2018</firstpublished>
    <gridmap />
    <start type="script"><![CDATA[
      JS.eval ("addText(\"<img id='map-image-pic1' style='display:none;margin-left:auto;margin-right:auto;margin-top:20px' src='https://i.imgur.com/d9UrZ6lb.jpg' />\");")
    ]]></start>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="north" to="another room">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="another room">
    <inherit name="editor_room" />
    <beforeenter type="script">
      JS.eval ("$('#map-image-pic1').insertBefore($('#gridCanvas')).css('display','block');$('#gridCanvas').hide();")
    </beforeenter>
    <onexit type="script">
      JS.eval ("$('#gridCanvas').show();$('#map-image-pic1').hide();")
    </onexit>
    <exit alias="south" to="room">
      <inherit name="southdirection" />
    </exit>
    <exit alias="north" to="third">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="third">
    <inherit name="editor_room" />
    <exit alias="south" to="another room">
      <inherit name="southdirection" />
    </exit>
  </object>
</asl>

I think I can work out how to do this using JS; would take a fair bit of experimenting though, and I've got 3000 words still to write in a little over 3 hours.
I'll see if I can get it working when I have a little more time, if I remember.


Thanks guys. I thought this was a simple thing, but apparently not.


My first guess is that you want a function like this:

  <function name="Grid_DrawRoom" parameters="room, redraw, playerobject">
    <![CDATA[
    if (room.grid_render) {
      if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {

        if (room.parent <> null) {
          Grid_DrawRoom (room.parent, redraw, playerobject)
        }

        gridx = Grid_GetGridCoordinateForPlayer(game.pov, room, "x")#
        gridy = Grid_GetGridCoordinateForPlayer(game.pov, room, "y")
        JS.Grid_DrawBox(gridx, gridy, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
        if (HasString(room, "grid_image")) {

          // FIXME - Grid_DrawImage takes an "id" parameter; I have no idea what this is supposed to be.
          // There needs to be a line here to set the "imageid" variable to something reasonable. Maybe the name of the room?

          Grid_DrawImage (imageid, GetFileURL(room.grid_image), gridx, gridy, room.grid_width, room.grid_length)
        }

        if (LengthOf(room.grid_label) > 0) {
          label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
          label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
          JS.Grid_DrawLabel(label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label)
        }

        foreach (exit, AllExits()) {
          if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
            Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
          }
        }

        Grid_SetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn", true)
      }
    }
    ]]>
  </function>

Not yet tested, but I suspect someone who isn't panicking would be better at doing the experiments to make it work.
The function is designed to override the default one in the grid/map library; drawing an image for the room if it has a grid_image attribute containing the name of an image.


K.V.

I will test that out in a few hours.

It looks like a good learning experience, if nothing else.


I have not panicked yet and will test this out too...

What does the "redraw" parameter do?


K.V.

I'm usually fairly decent at adding debugging messages to get parameter values, but I'm getting nowhere fast with this. (Still playing with it, though.)


As far as I can tell, 'redraw' causes the room to be drawn even if it's already been visited. The function I posted is the one that the existing map system uses; I just added the few lines to call DrawImage after DrawBox. If it works, then you could use this function to override the provided one.

Looking at grid.js, I think this should mostly work. imageid is just an identifier for the image, so that you can replace one image with another. So maybe replace the imageid in my code with room.name (meaning that changing the grid_image attribute will cause a new image to replace the old one the next time the image is redrawn). I've not played with Paper before, and there's a lot of code I haven't looked at, but I think this might work.


K.V.

Ha!

Got it (thanks to MrAngel)!

<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Map Image Test">
    <gameid>22dff91e-f9d0-4446-b6a5-000c32b50197</gameid>
    <version>0.0.1</version>
    <firstpublished>2018</firstpublished>
    <gridmap />
    <debugging />
    <start type="script">
    </start>
  </game>
  <object name="room one">
    <inherit name="editor_room" />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="north" to="room two">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="room two">
    <inherit name="editor_room" />
    <attr name="grid_image">qu.png</attr>
    <attr name="grid_borderwidth" type="int">0</attr>
    <beforefirstenter type="script">
    </beforefirstenter>
    <attr name="grid_width" type="int">3</attr>
    <attr name="grid_length" type="int">3</attr>
    <exit alias="south" to="room one">
      <inherit name="southdirection" />
    </exit>
    <exit alias="north" to="room three">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="room three">
    <inherit name="editor_room" />
    <attr name="grid_image">https://i.imgur.com/mBf7TBeb.png</attr>
    <exit alias="south" to="room two">
      <inherit name="southdirection" />
    </exit>
  </object>
  <command name="debug_cmd">
    <pattern>debug</pattern>
    <script>
      if (not HasAttribute(game,"debugging")) {
        game.debugging = false
      }
      if (game.debugging) {
        game.debugging = false
      }
      else {
        game.debugging = true
      }
      msg ("Debugging has been turned {either game.debugging:ON|OFF}.")
    </script>
  </command>
  <function name="Grid_DrawRoom" parameters="room, redraw, playerobject"><![CDATA[
    if (room.grid_render) {
      if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {
        if (room.parent <> null) {
          Grid_DrawRoom (room.parent, redraw, playerobject)
        }
        gridx = Grid_GetGridCoordinateForPlayer(game.pov, room, "x")
        gridy = Grid_GetGridCoordinateForPlayer(game.pov, room, "y")
        JS.Grid_DrawBox (gridx, gridy, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
        if (HasString(room, "grid_image")) {
          imgfile = false
          imgexts = Split(".png;.jpeg;.gif;.jpg;svg",";")
          foreach (ext, imgexts) {
            if (EndsWith(room.grid_image,ext)) {
              imgfile = true
            }
            if (StartsWith(room.grid_image,"http")) {
              imgfile = false
            }
          }
          if (imgfile) {
            room.imageid = room.name+"-grid-image"
            room.imageurl = GetFileURL (room.grid_image)
            Grid_DrawImage (room.imageid, room.imageurl, gridx, gridy, room.grid_width, room.grid_length)
          }
          else {
            if (HasBoolean(game,"debugging")) {
              if (game.debugging) {
                msg ("<hr/><b>Error running script:<br/>[  Grid_DrawRoom script ERROR:  The attribute <code>'"+room.name+".grid_image'</code> must be set to a string containing the name of an image file in the game's directory. ]</center></b><hr/>")
              }
            }
            return (false)
          }
        }
        if (LengthOf(room.grid_label) > 0) {
          label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
          label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
          JS.Grid_DrawLabel (label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label)
        }
        foreach (exit, AllExits()) {
          if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
            Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
          }
        }
        Grid_SetRoomBooleanForPlayer (playerobject, room, "grid_isdrawn", true)
      }
    }
  ]]></function>
</asl>

http://docs.textadventures.co.uk/quest/functions/corelibrary/grid_drawimage.html


K.V.

I tried to figure out how to see if GetFileURL() was returning a value without it messing everything up, but if(GetFileURL(input) <> null){} was never successful, even when I knew that GetFileURL() was returning the proper url.

Currently, if you don't have a valid image file name as that value, it messes up the map functionality in a different, seemingly random way each time you first enter that room. After that, the map is upset, and it doesn't want to play with me anymore.


I also tried to figure out how to feed it an ACTUAL url, but I didn't dig very deeply because this code is deep, man. It's far out!

...and I was just thinking I was getting the hang of things...

I need cookies and juice, then I'll see what else I can tear up in this here grid. (Mm-hmm. I reckon cookies and juice is good fer ya'. Mm.)


K.V.

Oh yeah...

gridApi.drawCustomLayerImage = function(id, url, x, y, width, height) {
    var existing = customLayerImages[id];
ar raster = existing ? existing : new Raster(url);
    var resizeRaster = function() {
        raster.scale(gridX.x * width / raster.bounds.width, gridY.y * height / raster.bounds.height);
        raster.position = gridPoint(x, y) + raster.bounds.size / 2;
    };
    if (existing) {
        resizeRaster();
    } else {
        raster.onLoad = resizeRaster;
        addPathToCurrentLayerList(raster);
        customLayerImages[id] = raster;
    }    
}

I also need to research Raster. (Never heard of it.)


I don't think you should need to play with anything that deep.

If the grid_image attribute is the name of an image in the game, it should work fine. Unfortunately, GetFileURL will happily convert a filename that doesn't exist into a URL that doesn't exist. Does GetFileData return null if it doesn't exist, or cause an error?

If you're using an external URL, just pass it to Grid_DrawImage. Or use JS to check it exists, and then use the JS version of Grid_DrawImage.


K.V.

Well...

It looks like Raster is doing what GetFileURL() normally does, but that's only a theory. (I still haven't looked into this one any further.)

The problem is that it doesn't throw an error when the grid_image attribute is wrong. It messes the map up. Usually the dot that represents the player disappears, but sometimes other things go haywire (like the game freezes, or the map just stops updating).

I was trying to make it bypass the script if the url was incorrect.


No, Raster takes a URL and transforms it into an array of pixel colours. If it's an image within the game file, you need to call GetFileURL first.

If you pass it an invalid URL, it seems to fail every time it tries to render the canvas; which means that part of the map disappears (the layers above the invalid image)

If you're using files within the game, then calling GetFileData(room.grid_image) first will cause an error, preventing the non-existing image from being added to the map (so it doesn't break anything later). Using an external URL is harder, because there doesn't seem to be any way to check that in Quest. We'll have to go to JS.

Can't test this (can't override functions on web version, so I'm working from my mental model of the scripts), but fingers crossed :)

[Note: I think this might fail to remove the image again when the map is cleared. I'll look at it when I'm less panicked over my amazon Sales Rank]

  <function name="Grid_DrawRoom" parameters="room, redraw, playerobject">
    <![CDATA[
    if (room.grid_render) {
      if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {

        if (room.parent <> null) {
          Grid_DrawRoom (room.parent, redraw, playerobject)
        }

        gridx = Grid_GetGridCoordinateForPlayer(game.pov, room, "x")#
        gridy = Grid_GetGridCoordinateForPlayer(game.pov, room, "y")
        JS.Grid_DrawBox(gridx, gridy, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
        if (HasString(room, "grid_image")) {
          imgurl = room.grid_image
          if (Instr(imgurl, ":") = 0) {
            // Not 100% sure, but I think a URL that returns an object always contains ":"
            // So we don't call GetFileURL if it starts with http://, or ftp://, or gopher: or something
            imgurl = GetFileURL(imgurl)
          }
          JS.eval("var testimg = new Image();testimg.onload = function() { gridApi.drawCustomLayerImage('"+room.name+"-grid-image', '"+imgurl+"', "+gridx+", "+gridy+", "+room.grid_width+", "+room.grid_height+"); };testimg.onerror = function() { addText('Could not load map image!'); };testimg.src = '"+imgurl+"';")
        }

        if (LengthOf(room.grid_label) > 0) {
          label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
          label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
          JS.Grid_DrawLabel(label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label)
        }

        foreach (exit, AllExits()) {
          if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
            Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
          }
        }

        Grid_SetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn", true)
      }
    }
    ]]>
  </function>

I copied mrangel's code (the last posting) and put it in a new game. I created 2 connected rooms and game them both a "grid_image" string attribute with the value of a .png file that I put in the game folder. I created a global turn script that calls mrangel's function with 3 arguments -- game.pov.parent, True, game.pov. Also called mrangel's function from the room's "enter" and "beforeenter" script attributes with the same 3 arguments.

The map works normally but the image doesn't display when the player moves back and forth between the 2 rooms. Only the regular mapped room displays and the yellow player icon disappears. Did I miss anything? Thanks.


Unfortunately I can't test it on the online version, and haven't got around to setting up the desktop version yet. I'll see if I can fix the issues when I've got a bit more free time.

I created a global turn script that calls mrangel's function with 3 arguments -- game.pov.parent, True, game.pov. Also called mrangel's function from the room's "enter" and "beforeenter" script attributes with the same 3 arguments.

You shouldn't need to do this. The function Grid_DrawRoom is automatically called by the existing map system; you don't need to call it yourself


... I'm trying to work out why the image might not appear.

Could you add a debugging statement to test if it's trying to draw the image? Change the JS line to

JS.eval("var testimg = new Image();testimg.onload = function() { alert('URL '+testimg.src+' exists, displaying map image');gridApi.drawCustomLayerImage('"+room.name+"-grid-image', testimg.src, "+gridx+", "+gridy+", "+room.grid_width+", "+room.grid_height+"); };testimg.onerror = function() { addText('Could not load map image!'); };testimg.src = '"+imgurl+"';")


I replaced the old JS line with the new one. Quest does NOT print the error message "Could not load map image!" when you move back and forth between the two rooms.

Don't know if this helps, but I added a print message line directly before your new JS line, and my message does print. So at least we know Quest does reach your JS line.


Does it display the message to say that the URL exists? (I should probably have used addText rather than alert)

I can't tell if I'm misunderstanding how the grid map works, or if there's an error in my image-validating code


Slightly more elegant jQuery-ish way of doing that line. If the above doesn't generate a message, maybe try this?

JS.eval("$.ajax({url: '"+imgurl+"',type:'HEAD',success:function() {addText('Map image loading');gridApi.drawCustomLayerImage('"+room.name+"-grid-image', '"+imgurl+"', "+gridx+", "+gridy+", "+room.grid_width+", "+room.grid_height+"); }, error: function() {addText('Could not load map image!'); }});")


K.V.

I'll test it out.

--
Does this not work?

http://textadventures.co.uk/forum/quest/topic/yn_iueiaokmshfcpkyahga/code-for-printing-an-image-instead-of-a-standard-map-room#8c57e24e-1d44-49de-a327-30d3717f58da

It works for me, as long as you put the correct file name. (I was having problems setting up a catch to throw an error if the file name was incorrect or not in the game folder, but the image displayed correctly (I think).)


K.V.

This works flawlessly for me (but I may be missing what we're trying to accomplish):

javascript.js (UPDATED - now brings in image from url beginning with "http" or "ftp")

getFileUrlJS = function(filename){
  var bool = filename.indexOf("http") === 0;
  if (!bool){bool = filename.indexOf("ftp") === 0;}
  if(!bool){
    filename = encodeURIComponent(filename);
    return "quest://local/" + filename;
  }else{
    return filename;
  }
};

var imagesToCheck = [];

function checkImages(){
  imagesToCheck.forEach(function(img){
    isFileGood(img)
  });
};

var failedImgs = [];

function imgFail(){
  failedImgs.push(imgFile);
};

function isFileGood(url){
  imgFile = getFileUrlJS(url);
  addText("<img style='display:none' onload='addToMap()' onerror='imgFail()' src='"+imgFile+"'/>");

};

customDrawImage = function(url){
 var imgFile = getFileUrlJS(url);
 var failnumber = failedImgs.indexOf(imgFile);
 if(failnumber === -1){gridApi.drawCustomLayerImage(roomImageId, imgFile, parseInt(gridX), parseInt(gridY), parseInt(roomGridWidth), parseInt(roomGridHeight));}
};

    <start type="script">
      foreach (room, AllObjects()) {
        if (HasAttribute(room,"grid_image")) {
          JS.eval ("imagesToCheck.push('"+room.grid_image+"');")
        }
      }
      JS.checkImages ()
    </start>
  </game>

<function name="Grid_DrawRoom" parameters="room, redraw, playerobject"><![CDATA[
    if (room.grid_render) {
      if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {
        if (room.parent <> null) {
          Grid_DrawRoom (room.parent, redraw, playerobject)
        }
        gridx = Grid_GetGridCoordinateForPlayer(game.pov, room, "x")
        gridy = Grid_GetGridCoordinateForPlayer(game.pov, room, "y")
        JS.Grid_DrawBox (gridx, gridy, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
        if (HasString(room, "grid_image")) {
          imgfile = false
          imgexts = Split(".png;.jpeg;.gif;.jpg;svg",";")
          room.imageid = room.name+"-grid-image"
          JS.eval ("var roomImageId = '"+room.imageid+"';var gridX = '"+gridx+"';var gridY = '"+gridy+"';var roomGridWidth = '"+room.grid_width+"';var roomGridHeight = '"+room.grid_length+"';customDrawImage('"+room.grid_image+"');")
        }
        if (LengthOf(room.grid_label) > 0) {
          label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
          label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
          JS.Grid_DrawLabel (label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label)
        }
        foreach (exit, AllExits()) {
          if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
            Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
          }
        }
        Grid_SetRoomBooleanForPlayer (playerobject, room, "grid_isdrawn", true)
      }
    }
  ]]></function>

Example game code:

<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Map Image Test">
    <gameid>22dff91e-f9d0-4446-b6a5-000c32b50197</gameid>
    <version>0.0.1</version>
    <firstpublished>2018</firstpublished>
    <gridmap />
    <debugging />
    <start type="script">
      foreach (room, AllObjects()) {
        if (HasAttribute(room,"grid_image")) {
          JS.eval ("imagesToCheck.push('"+room.grid_image+"');")
        }
      }
      JS.checkImages ()
    </start>
  </game>
  <object name="room one">
    <inherit name="editor_room" />
    <beforeenter type="script">
    </beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="north" to="room two">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="room two">
    <inherit name="editor_room" />
    <attr name="grid_image">qu.png</attr>
    <attr name="grid_borderwidth" type="int">0</attr>
    <attr name="grid_width" type="int">3</attr>
    <attr name="grid_length" type="int">3</attr>
    <beforefirstenter type="script">
    </beforefirstenter>
    <exit alias="south" to="room one">
      <inherit name="southdirection" />
    </exit>
    <exit alias="north" to="room three">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="room three">
    <inherit name="editor_room" />
    <attr name="grid_image">https://i.imgur.com/mBf7TBeb.png</attr>
    <exit alias="south" to="room two">
      <inherit name="southdirection" />
    </exit>
  </object>
  <command name="debug_cmd">
    <pattern>debug</pattern>
    <script>
      if (not HasAttribute(game,"debugging")) {
        game.debugging = false
      }
      if (game.debugging) {
        game.debugging = false
      }
      else {
        game.debugging = true
      }
      msg ("Debugging has been turned {either game.debugging:ON|OFF}.")
    </script>
  </command>
  <function name="Grid_DrawRoom" parameters="room, redraw, playerobject"><![CDATA[
    if (room.grid_render) {
      if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {
        if (room.parent <> null) {
          Grid_DrawRoom (room.parent, redraw, playerobject)
        }
        gridx = Grid_GetGridCoordinateForPlayer(game.pov, room, "x")
        gridy = Grid_GetGridCoordinateForPlayer(game.pov, room, "y")
        JS.Grid_DrawBox (gridx, gridy, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
        if (HasString(room, "grid_image")) {
          imgfile = false
          imgexts = Split(".png;.jpeg;.gif;.jpg;svg",";")
          room.imageid = room.name+"-grid-image"
          JS.eval ("var roomImageId = '"+room.imageid+"';var gridX = '"+gridx+"';var gridY = '"+gridy+"';var roomGridWidth = '"+room.grid_width+"';var roomGridHeight = '"+room.grid_length+"';customDrawImage('"+room.grid_image+"');")
        }
        if (LengthOf(room.grid_label) > 0) {
          label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
          label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
          JS.Grid_DrawLabel (label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label)
        }
        foreach (exit, AllExits()) {
          if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
            Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
          }
        }
        Grid_SetRoomBooleanForPlayer (playerobject, room, "grid_isdrawn", true)
      }
    }
  ]]></function>
  <javascript src="javascript.js" />
</asl>

image

https://drive.google.com/file/d/1ld4xZ8wI-uhLK6y_hTBUotwwLMHHOsaK/view?usp=sharing


The image for room three previously threw an error. Now, it does not.


Video of this in action (very short):

image


@KV - I was trying to display a local image, not one from imgur. Can you modify your code to do that?

@mrangel - I tried your latest code. It does the same thing -- no image, no error message, just the regular map display. Let me see if KV can modify his code.


K.V.

I was trying to display a local image, not one from imgur. Can you modify your code to do that?

Maybe? I'm fairly certain it will...

(I'll go check.)


K.V.

@Dcoder

Do you like apples?

<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Images">
    <gameid>6bee0a7d-3023-4b48-8b17-7417a148659a</gameid>
    <version>1.0</version>
    <firstpublished>2018</firstpublished>
    <feature_pictureframe />
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</description>
    
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <object name="avatar">
      <inherit name="editor_object" />
      <listalias><![CDATA[<hr/><img onerror='$(this).hide();console.log("Image failed to load!");' width='33%' src='quest://local/qu-shrunk.png'/><br/>Avatar<hr/>]]></listalias>
    </object>
  </object>
</asl>

image removed


You have to start it with quest://local/.

Like: src='quest://local/filename.png.


With a bad url, it hides the image element and saves an entry to the console.log:

image removed


You can open the HTML tools, then click 'Console', to see the log I entered if it failed:

image removed


How about them apples?


I hope you don't like apples.
...because I thought apples were oranges while writing this post! (I was thinking of a different thread (and game). Sorry!)


@KV

Umm, just to be sure that we're on the same page, this is what I was trying to do -- I wanted to use the regular mapping function, but I wanted to replace the drawing of a standard room with a local image from the Quest game folder (or wherever on my local hard disk).

So I copied your "example game code" (the one with "details", above) into a new game. I changed the "grid_image" attribute of "room two" to:

quest://local/green-gray-forest-hi.png (the name of the image file in the same folder as the game file) -- that doesn't work.

I also tried this pathname:

C://Users/DH/Documents/Quest Games/KV TEST Map/green-gray-forest-hi.png (exact pathname to the image file) -- also doesn't work. What's wrong here?


I think KV got confused :p
There's two threads open at present about adding an image; one in the map and one in the inventory.


K.V.

Sorry!

I'm offering oranges and telling you they're apples...

I was deliriously tired and got example games crossed up! (mrangel hit the nail on the head!)


That's the first thing I got working, though. It was the online images that gave me the problem for a short whilel


OLD CODE (that loaded local images, but not online images):
http://textadventures.co.uk/forum/quest/topic/yn_iueiaokmshfcpkyahga/code-for-printing-an-image-instead-of-a-standard-map-room#8c57e24e-1d44-49de-a327-30d3717f58da

http://textadventures.co.uk/forum/quest/topic/yn_iueiaokmshfcpkyahga/code-for-printing-an-image-instead-of-a-standard-map-room#a515f07c-836c-47b8-893e-e749d1fcb3f1


NEW CODE THAT DISPLAYS ONLINE OR LOCAL IMAGES IN THE ROOM ON THE MAP:

This is an example game with a local file and an online image being displayed:

<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Map Image Test">
    <gameid>22dff91e-f9d0-4446-b6a5-000c32b50197</gameid>
    <version>0.0.1</version>
    <firstpublished>2018</firstpublished>
    <gridmap />
    <debugging />
    <start type="script">
      foreach (room, AllObjects()) {
        if (HasAttribute(room,"grid_image")) {
          JS.eval ("imagesToCheck.push('"+room.grid_image+"');")
        }
      }
      JS.checkImages ()
    </start>
  </game>
  <object name="room one">
    <inherit name="editor_room" />
    <beforeenter type="script">
    </beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="north" to="room two">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="room two">
    <inherit name="editor_room" />
    <attr name="grid_image">qu.png</attr>
    <attr name="grid_borderwidth" type="int">0</attr>
    <attr name="grid_width" type="int">3</attr>
    <attr name="grid_length" type="int">3</attr>
    <beforefirstenter type="script">
    </beforefirstenter>
    <exit alias="south" to="room one">
      <inherit name="southdirection" />
    </exit>
    <exit alias="north" to="room three">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="room three">
    <inherit name="editor_room" />
    <attr name="grid_image">https://i.imgur.com/mBf7TBeb.png</attr>
    <exit alias="south" to="room two">
      <inherit name="southdirection" />
    </exit>
  </object>
  <command name="debug_cmd">
    <pattern>debug</pattern>
    <script>
      if (not HasAttribute(game,"debugging")) {
        game.debugging = false
      }
      if (game.debugging) {
        game.debugging = false
      }
      else {
        game.debugging = true
      }
      msg ("Debugging has been turned {either game.debugging:ON|OFF}.")
    </script>
  </command>
  <function name="Grid_DrawRoom" parameters="room, redraw, playerobject"><![CDATA[
    if (room.grid_render) {
      if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {
        if (room.parent <> null) {
          Grid_DrawRoom (room.parent, redraw, playerobject)
        }
        gridx = Grid_GetGridCoordinateForPlayer(game.pov, room, "x")
        gridy = Grid_GetGridCoordinateForPlayer(game.pov, room, "y")
        JS.Grid_DrawBox (gridx, gridy, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
        if (HasString(room, "grid_image")) {
          imgfile = false
          imgexts = Split(".png;.jpeg;.gif;.jpg;svg",";")
          room.imageid = room.name+"-grid-image"
          JS.eval ("var roomImageId = '"+room.imageid+"';var gridX = '"+gridx+"';var gridY = '"+gridy+"';var roomGridWidth = '"+room.grid_width+"';var roomGridHeight = '"+room.grid_length+"';customDrawImage('"+room.grid_image+"');")
        }
        if (LengthOf(room.grid_label) > 0) {
          label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
          label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
          JS.Grid_DrawLabel (label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label)
        }
        foreach (exit, AllExits()) {
          if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
            Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
          }
        }
        Grid_SetRoomBooleanForPlayer (playerobject, room, "grid_isdrawn", true)
      }
    }
  ]]></function>
  <javascript src="javascript.js" />
</asl>

javascript.js

getFileUrlJS = function(filename){
  var bool = filename.indexOf("http") === 0;
  if (!bool){bool = filename.indexOf("ftp") === 0;}
  if(!bool){
    filename = encodeURIComponent(filename);
    return "quest://local/" + filename;
  }else{
    return filename;
  }
};

var imagesToCheck = [];

function checkImages(){
  imagesToCheck.forEach(function(img){
    isFileGood(img)
  });
};

var failedImgs = [];

function imgFail(){
  failedImgs.push(imgFile);
};

function isFileGood(url){
  imgFile = getFileUrlJS(url);
  addText("<img style='display:none' onload='addToMap()' onerror='imgFail()' src='"+imgFile+"'/>");

};

customDrawImage = function(url){
 var imgFile = getFileUrlJS(url);
 var failnumber = failedImgs.indexOf(imgFile);
 if(failnumber === -1){gridApi.drawCustomLayerImage(roomImageId, imgFile, parseInt(gridX), parseInt(gridY), parseInt(roomGridWidth), parseInt(roomGridHeight));}
};

K.V.
  <object name="room two">
    <inherit name="editor_room" />
    <attr name="grid_image">qu.png</attr>
  <object name="room three">
    <inherit name="editor_room" />
    <attr name="grid_image">https://i.imgur.com/mBf7TBeb.png</attr>


No problem guys : ) Those were delicious orange-apples or whatever the heck they were, KV!

@KV
I'm copying your code "NEW CODE THAT DISPLAYS ONLINE OR LOCAL IMAGES IN THE ROOM ON THE MAP". The part I don't understand is the "javascript.js" part (I've never worked with that before). Where do I put that code? Sorry to be such a JS newbie, haha.


K.V.

You have to create the file javascript.js, and make sure it's in the game folder.

Then, that second to last line in full code view will include it in the game.

  <javascript src="javascript.js" />
</asl>

K.V.

...or....


Now, it looks like you can't do anything here, but you can enter text (or paste it in), and Quest automatically saves your changes to the JS file in the game folder.


K.V.

PS

You can also click "Browse" instead of "New" and select a JS file from your PC. Quest will copy it into the game folder, just like it would an image or audio file when you add them via GUI.


Yay! It works! Hooray! Thank you for the hand-holding!

I am making an outdoor map generator. When I make some more progress, I will share it online. Thanks again KV and mrangel.


K.V.

(golf clap)


... I might need that when I get further along in my game XD


Ok, I've got the demo finished and working when I play it on my desktop. I've published it to a .quest file, and that works perfectly too on my desktop.

However, after I've successfully uploaded it to the Quest website and play it online, a couple of things don't work -- no images show (these replaced the regular rooms), and the map does not work; i.e., only the starting room shows but other rooms don't show after you've moved into them (through teleport). Movement from room to room otherwise seems to work, though (the text panel shows the correct room name and exits). It seems that the room images display offline but not online, due to something about the modified "grid_DrawRoom" function and/or the added "javascript.js" function? This is the demo:

http://textadventures.co.uk/games/view/mctudqh-00mot77wz2zigg/map-rpg-demo

I can show you my code on request.


K.V.

Wow.

Okay...

When I play online, the URL of my image become this:

<img src="https://textadventures.blob.core.windows.net/gameresources/22dff91e-f9d0-4446-b6a5-000c32b50197/qu.png" width="22%">

When I play on the desktop, the URL is this:

<img width="22%" src="quest://local/qu.png?c=192514460">

The number following ?c= is the time since 1/1/2012.

 filename += "?c=" + (Convert.ToInt32((DateTime.Now - (New DateTime(2012, 1, 1))).TotalSeconds)).ToString()

All of this can be left off in the desktop version. You only need to prefix the filename with quest://local/ to make it work.

(I think the suffix has to do with cookies.)


src="https://textadventures.blob.core.windows.net/gameresources/22dff91e-f9d0-4446-b6a5-000c32b50197/qu.png"

I have no idea where that id comes from.

Be back shortly.


K.V.

This appears to be what you need:

https://textadventures.blob.core.windows.net/gameresources/73ae1f35-2c11-41ce-8cb5-97bfb1392ce1/

Give me one more minute or two...


K.V.

Try this.

getFileUrlJS = function(filename){
  var bool = filename.indexOf("http") === 0;
  if (!bool){bool = filename.indexOf("ftp") === 0;}
  if(!bool){
    filename = encodeURIComponent(filename);
    if(!webPlayer){return "quest://local/" + filename;}
	else {return"https://textadventures.blob.core.windows.net/gameresources/73ae1f35-2c11-41ce-8cb5-97bfb1392ce1/"+filename;}
  }else{
    return filename;
  }
};

K.V.

That id will probably be different for every game, but I'm not sure about that.

I did update my example with the new code (using the ID from my game).

BEFORE:


AFTER:


...and it still works in the desktop player, too.


K.V.

I bet a nickel that works for this game for you.

Here's the code to directly display the grass (I'm only shrinking the width in the actual image's code to save space on this page):

<img src='https://textadventures.blob.core.windows.net/gameresources/73ae1f35-2c11-41ce-8cb5-97bfb1392ce1/Demo%20GrasslandB.jpg'/>

K.V.

The ID is different for each game.

It appears you'll have to upload your game, then play online once to get the ID, then change your getFileUrlJS() script, then re-submit your game.


To get around this, you can upload your images to an external site and use that link for both versions, desktop and online.


I don't know why the onerror thing doesn't keep it from messing everything up when playing online, either.

paper.js is the script an incorrect URL in the map's code breaks online.

I've perused paper.js a few times, but it's still Greek to me!

Anyway, I thought I had it whipped...

Sorry about all that!


Thanks KV. So it sounds like I would need to get the ID for each image (don't even know where to find that). It also sounds easier to just upload the images to imgur, so I'll probably go that route. I'll re-post when I'm done...


K.V.

You only need an ID for each game.

You can just replace your function with the one I posted.

http://textadventures.co.uk/forum/quest/topic/yn_iueiaokmshfcpkyahga/code-for-printing-an-image-instead-of-a-standard-map-room-mostly-finito#ac531aeb-d6fa-46be-9847-7f3488405408

It has your game's ID on it already.

...and it checks for the web player. If you're online, it goes to the online image. If on the desktop, it loads the local image.

It should work for every image in your game, too.

So, you wouldn't need to upload the files or change all that code. You can just paste over that one function to fix the whole game. (I think. It definitely worked in my example game.)


It appears you'll have to upload your game, then play online once to get the ID, then change your getFileUrlJS() script, then re-submit your game.

(from memory, sorry if I got the function name wrong)

Quest's GetFileURL() will prepend the ID to whatever string you pass it; without checking if the file exists, is a valid filename, or is already a URL. So you could easily call it once to generate the ID, and pass this to the JS. I think that calling GetFileURL("") might be an easy way to get https://textadventures.blob.core.windows.net/gameresources/73ae1f35-2c11-41ce-8cb5-97bfb1392ce1/ or quest://local/ as appropriate.

Maybe just cache it so your javascript can use it. In your UI initialisation script:

JS.setImagePath(GetFileUrl(":FILENAME:"))

and then the JS:

setImagePath = function(path) {
  window.questImagePath = path;
};

getFileUrlJS = function(filename){
  if(filename.indexOf("://") > 0) {
    return (filename);
  } else {
    return (window.questImagePath.replace(":FILENAME:", filename));
  }
};

(On a slight tangent; this might be an easy way to test if you're playing online or not without the need for JS callbacks. By checking if the value returned by GetFileUrl("fnord") starts with quest or http)


@KV -
So I replaced your original javascript.js function:

getFileUrlJS = function(filename){
  var bool = filename.indexOf("http") === 0;
  if (!bool){bool = filename.indexOf("ftp") === 0;}
  if(!bool){
    filename = encodeURIComponent(filename);
    return "quest://local/" + filename;
  }else{
    return filename;
  }
};

var imagesToCheck = [];

function checkImages(){
  imagesToCheck.forEach(function(img){
    isFileGood(img)
  });
};

var failedImgs = [];

function imgFail(){
  failedImgs.push(imgFile);
};

function isFileGood(url){
  imgFile = getFileUrlJS(url);
  addText("<img style='display:none' onload='addToMap()' onerror='imgFail()' src='"+imgFile+"'/>");

};

customDrawImage = function(url){
 var imgFile = getFileUrlJS(url);
 var failnumber = failedImgs.indexOf(imgFile);
 if(failnumber === -1){gridApi.drawCustomLayerImage(roomImageId, imgFile, parseInt(gridX), parseInt(gridY), parseInt(roomGridWidth), parseInt(roomGridHeight));}
};

with your new js code:

getFileUrlJS = function(filename){
  var bool = filename.indexOf("http") === 0;
  if (!bool){bool = filename.indexOf("ftp") === 0;}
  if(!bool){
    filename = encodeURIComponent(filename);
    if(!webPlayer){return "quest://local/" + filename;}
	else {return"https://textadventures.blob.core.windows.net/gameresources/73ae1f35-2c11-41ce-8cb5-97bfb1392ce1"+filename;}
  }else{
    return filename;
  }
};

...but the room images won't even display when I play the demo in the offline editor (just blank white rooms). Or I should substitute the filename "Map RPG Demo.quest" wherever the js code says "filename"?


@mrangel -
I replaced the javascript.js function with your code:

setImagePath = function(path) {
  window.questImagePath = path;
};

getFileUrlJS = function(filename){
  if(filename.indexOf("://") > 0) {
    return (filename);
  } else {
    return (window.questImagePath.replace(":Map RPG Demo.quest:", filename));
  }
};

And under the UI tab added:

JS.setImagePath(GetFileUrl(":Map RPG Demo.quest:"))

but same as KV's code, the map shows blank white rooms without the images. Uploaded to Quest website with same results. Obviously I don't know what I'm doing...


K.V.

I've got that code in your game, and it works for me:


Maybe you're missing a function or something.

It doesn't look like you are, but all I changed was this one function in the JS and it works for me...

Here's the entire JS file (I changed was getFileUrlJs()):

getFileUrlJS = function(filename){
  var bool = filename.indexOf("http") === 0;
  if (!bool){bool = filename.indexOf("ftp") === 0;}
  if(!bool){
    filename = encodeURIComponent(filename);
    if(!webPlayer){return "quest://local/" + filename;}
	else {return"https://textadventures.blob.core.windows.net/gameresources/22dff91e-f9d0-4446-b6a5-000c32b50197/"+filename;}
  }else{
    return filename;
  }
};

var imagesToCheck = [];

function checkImages(){
  imagesToCheck.forEach(function(img){
    isFileGood(img)
  });
};

var failedImgs = [];

function imgFail(){
  failedImgs.push(imgFile);
};

function isFileGood(url){
  imgFile = getFileUrlJS(url);
  addText("<img style='display:none' onload='addToMap()' onerror='imgFail()' src='"+imgFile+"'/>");

};

customDrawImage = function(url){
 var imgFile = getFileUrlJS(url);
 var failnumber = failedImgs.indexOf(imgFile);
 if(failnumber === -1){gridApi.drawCustomLayerImage(roomImageId, imgFile, parseFloat(gridX), parseFloat(gridY), parseInt(roomGridWidth), parseInt(roomGridHeight));}
};

The modded Grid_DrawRoom (Quest function):

<function name="Grid_DrawRoom" parameters="room, redraw, playerobject"><![CDATA[
    if (room.grid_render) {
      if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {
        if (room.parent <> null) {
          Grid_DrawRoom (room.parent, redraw, playerobject)
        }
        gridx = Grid_GetGridCoordinateForPlayer(game.pov, room, "x")
        gridy = Grid_GetGridCoordinateForPlayer(game.pov, room, "y")
        JS.Grid_DrawBox (gridx, gridy, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
        if (HasString(room, "grid_image")) {
          imgfile = false
          imgexts = Split(".png;.jpeg;.gif;.jpg;svg",";")
          room.imageid = room.name+"-grid-image"
          JS.eval ("var roomImageId = '"+room.imageid+"';var gridX = '"+gridx+"';var gridY = '"+gridy+"';var roomGridWidth = '"+room.grid_width+"';var roomGridHeight = '"+room.grid_length+"';customDrawImage('"+room.grid_image+"');")
        }
        if (LengthOf(room.grid_label) > 0) {
          label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
          label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
          JS.Grid_DrawLabel (label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label)
        }
        foreach (exit, AllExits()) {
          if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
            Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
          }
        }
        Grid_SetRoomBooleanForPlayer (playerobject, room, "grid_isdrawn", true)
      }
    }
  ]]></function>

should substitute the filename "Map RPG Demo.quest" wherever the js code says "filename"?

You shouldn't need to change anything.

The Quest function should send the filename, so you shouldn't be having to deal with filenames at all.

As long as the room has a grid_image attribute, the game will automatically send the filename to getFileUrlJs().

In fact, getFileUrlJs()runs at the start of the game. If the file doesn't return a good URL (or file path), getFileUrlJs() throws it into a 'failed to load' array (or list), and it is ignored by the map.

The purpose: if the map tries to load a bad url, the map breaks.

isFileGood() is pre-loading the images. Each image has an onerror() script, which adds any image which doesn't load to the blacklist.


K.V.

I combined some of my code with some of mrangel's.

It now works online or offline, with included local files or with online images.


Try this:

1. Create a new game.

2. Include this library:
https://github.com/KVonGit/QuestStuff/blob/master/libraries/GridImageLib/GridImageLib.zip?raw=true

3. Make sure you have at least 2 or 3 rooms to move through (just to test things out).

4. Enable the map and add SetupGridImages to your User Interface Initialisation script.

5. Select a room in the editor, and you will see a new "Grid Image" tab. Click on that.

6. Use the dropdown to select and import a local image (as you normally would), OR check the box to enter a URL (to use an online image).

7. That's it. Give it a test run! Let me know if it works!


http://textadventures.co.uk/games/view/cl4g-hnzikujwr2rofu68a/gridimglib-tester




The Example Game

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <include ref="GridImageLib.aslx" />
  <game name="Image Map">
    <gameid>f127803f-b2dd-4ced-b58c-bd9202fe0284</gameid>
    <version>2.3</version>
    <firstpublished>2018</firstpublished>
    <gridmap />
    <respondtogridclicks />
    <feature_advancedscripts />
    <inituserinterface type="script"><![CDATA[
      SetupGridImages
    ]]></inituserinterface>
    <commandpane type="boolean">false</commandpane>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <gridimg_custompath />
    <attr name="grid_image">https://i.imgur.com/mBf7TBeb.png</attr>
    <enter type="script">
      Grid_SetGridCoordinateForPlayer (game.pov, attic, "z", Grid_GetGridCoordinateForPlayer(game.pov, this, "z")+1)
    </enter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
      <changedparent type="script">
        if (game.pov = this) {
          if (IsDefined("oldvalue")) {
            OnEnterRoom (oldvalue)
            this.lastparent = oldvalue
          }
          else {
            OnEnterRoom (null)
          }
          if (game.gridmap) {
            MergePOVCoordinates
          }
        }
        this.hasbeenmoved = true
      </changedparent>
    </object>
    <exit alias="north" to="second room">
      <inherit name="northdirection" />
    </exit>
    <exit alias="up" to="attic">
      <inherit name="updirection" />
    </exit>
  </object>
  <object name="second room">
    <inherit name="editor_room" />
    <attr name="grid_image">http://cdn3.everyjoe.com/wp-content/gallery/kate-upton-zero-gravity/kate-upton-zero-gravity-1.jpg</attr>
    <gridimg_custompath />
    <exit alias="south" to="room">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="attic">
    <inherit name="editor_room" />
    <attr name="grid_image">http://cdn3.everyjoe.com/wp-content/gallery/kate-upton-zero-gravity/kate-upton-zero-gravity-2.jpg</attr>
    <enter type="script">
      Grid_SetGridCoordinateForPlayer (game.pov, this, "z", Grid_GetGridCoordinateForPlayer(game.pov, room, "z")+1)
    </enter>
    <exit alias="down" to="room">
      <inherit name="downdirection" />
    </exit>
  </object>
  <function name="GridSquareClick" parameters="x, y"><![CDATA[
    z = Grid_GetGridCoordinateForPlayer(game.pov, game.pov.parent, "z")
    d = Grid_GetPlayerCoordinateDictionary(player)
    foreach (key, d) {
      d2 = DictionaryItem(d, key)
      if (DictionaryContains(d2, "grid_isdrawn")) {
        r = GetObject(key)
        if (InGridRoom(r, d2, x, y, z)) {
          if (not game.pov.parent = r) {
            msg ("<br/>>map_click-goto: "+GetDisplayName(r)+"<br/>")
            MoveObject (game.pov, r)
            JS.scrollToEnd ()
          }
          else {
            msg ("<br/>>map_click-look<br/>")
            ShowRoomDescription
            JS.scrollToEnd ()
          }
        }
      }
    }
  ]]></function>
  <function name="InGridRoom" parameters="room, dict, x, y, z" type="boolean"><![CDATA[
    flag = DictionaryItem(dict, "grid_isdrawn")
    if (not flag) {
      return (false)
    }
    z1 = DictionaryItem(dict, "z")
    if (not z = z1) {
      return (false)
    }
    n = DictionaryItem(dict, "x")
    x1 = n - room.grid_width / 2.0
    x2 = x1 + room.grid_width
    n = DictionaryItem(dict, "y")
    y1 = n - room.grid_length / 2.0
    y2 = y1 + room.grid_length
    if (x < x1 or x > x2) {
      return (false)
    }
    if (y < y1 or y > y2) {
      return (false)
    }
    return (true)
  ]]></function>
</asl>

Thanks Dcoder, mrangel, and Pixie!

This was fun, and I'd never have done this if you all had not shared your thoughts and wisdom!


No luck. There is a space at the top for the map but no map....
Duh. Had to add exits...
Works!

I used png images to get this in maps:

I thought this added a new level to it!


K.V.

Very nice!!!


Wow guys!

Sorry I was busy the last couple of days. When I come back, I see that this whole topic has been moved to Libraries and Code Samples (where it belongs). Let me try your new library KV, and if I can get things working, I will repost my outdoor map demo. Thanks everyone! Be back soon!


I'm getting an error when using grid clicks to move on the map. I haven't set any coordinates for the rooms as the tutorial just shows it as needed for changing levels (upper and lower).
If I need to add coordinates, I'll figure that out...

Error running script: Error compiling expression 'InGridRoom(r, d 2, x, y, z)': Value cannot be null. Parameter name: key


K.V.

Uh oh...

I haven't messed with grid clicks yet.

I assume it works in the same game when not using the images for the rooms?


K.V.

It works for me after following these instructions (under VERTICAL MOVEMENT):
http://docs.textadventures.co.uk/quest/showing_a_map.html


You can only click on rooms on the same level, though, as far as I can tell.

Example game:

UPDATED

<<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <include ref="GridImageLib.aslx" />
  <game name="Image Map">
    <gameid>f127803f-b2dd-4ced-b58c-bd9202fe0284</gameid>
    <version>1.1</version>
    <firstpublished>2018</firstpublished>
    <gridmap />
    <respondtogridclicks />
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <gridimg_custompath />
    <attr name="grid_image">https://i.imgur.com/mBf7TBeb.png</attr>
    <enter type="script">
      Grid_SetGridCoordinateForPlayer (game.pov, attic, "z", Grid_GetGridCoordinateForPlayer(game.pov, this, "z")+1)
    </enter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="north" to="second room">
      <inherit name="northdirection" />
    </exit>
    <exit alias="up" to="attic">
      <inherit name="updirection" />
    </exit>
  </object>
  <object name="second room">
    <inherit name="editor_room" />
    <attr name="grid_image">http://cdn3.everyjoe.com/wp-content/gallery/kate-upton-zero-gravity/kate-upton-zero-gravity-1.jpg</attr>
    <exit alias="south" to="room">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="attic">
    <inherit name="editor_room" />
    <attr name="grid_image">http://cdn3.everyjoe.com/wp-content/gallery/kate-upton-zero-gravity/kate-upton-zero-gravity-2.jpg</attr>
    <enter type="script">
      Grid_SetGridCoordinateForPlayer (game.pov, this, "z", Grid_GetGridCoordinateForPlayer(game.pov, room, "z")+1)
    </enter>
    <exit alias="down" to="room">
      <inherit name="downdirection" />
    </exit>
  </object>
  <function name="GridSquareClick" parameters="x, y"><![CDATA[
    z = Grid_GetGridCoordinateForPlayer(game.pov, game.pov.parent, "z")
    d = Grid_GetPlayerCoordinateDictionary(player)
    foreach (key, d) {
      d2 = DictionaryItem(d, key)
      if (DictionaryContains(d2, "grid_isdrawn")) {
        r = GetObject(key)
        if (InGridRoom(r, d2, x, y, z)) {
          if(not game.pov.parent = r){
            msg("<br/>>map_click-goto: "+GetDisplayName(r)+"<br/>")
            MoveObject(game.pov,r)
            JS.scrollToEnd()
          }
          else {
            msg("<br/>>map_click-look<br/>")
            ShowRoomDescription
            JS.scrollToEnd()
          }
        }
      }
    }
  ]]></function>
  <function name="InGridRoom" parameters="room, dict, x, y, z" type="boolean"><![CDATA[
    flag = DictionaryItem(dict, "grid_isdrawn")
    if (not flag) {
      return (false)
    }
    z1 = DictionaryItem(dict, "z")
    if (not z = z1) {
      return (false)
    }
    n = DictionaryItem(dict, "x")
    x1 = n - room.grid_width / 2.0
    x2 = x1 + room.grid_width
    n = DictionaryItem(dict, "y")
    y1 = n - room.grid_length / 2.0
    y2 = y1 + room.grid_length
    if (x < x1 or x > x2) {
      return (false)
    }
    if (y < y1 or y > y2) {
      return (false)
    }
    return (true)
  ]]></function>
</asl>

K.V.

Here's a version of the same thing with the map in the dialog window (just in case that's what FW is doing):

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <include ref="GridImageLib.aslx" />
  <game name="Image Map">
    <gameid>f127803f-b2dd-4ced-b58c-bd9202fe0284</gameid>
    <version>1.0</version>
    <firstpublished>2018</firstpublished>
    <gridmap />
    <respondtogridclicks />
    <start type="script"><![CDATA[
      JS.eval ("$('#gamePanelSpacer').height(0);")
      msg ("<div id='mapHolder' style='display:none;'></div>")
      JS.eval ("$('#gridPanel').appendTo($('#mapHolder')).css({'left':'63%','position':'absolute'});var mh = $('#mapHolder');mh.dialog({height: 400, width: 700,close: function(){mh.dialog('close');}});mh.dialog('option', 'title', 'Map');mh.dialog('open');$('.ui-dialog').css('position', 'fixed');openMap = function(){mh.dialog('open');};")
    ]]></start>
    <inituserinterface type="script">
      JS.setCommands ("SHOW MAP")
    </inituserinterface>
  </game>
  <command name="view_map_command">
    <pattern>view map;open map;map;show map</pattern>
    <script>
      JS.openMap ()
      game.notarealturn = true
    </script>
  </command>
  <object name="room">
    <inherit name="editor_room" />
    <gridimg_custompath />
    <attr name="grid_image">https://i.imgur.com/mBf7TBeb.png</attr>
    <enter type="script">
      Grid_SetGridCoordinateForPlayer (game.pov, attic, "z", Grid_GetGridCoordinateForPlayer(game.pov, this, "z")+1)
    </enter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="north" to="second room">
      <inherit name="northdirection" />
    </exit>
    <exit alias="up" to="attic">
      <inherit name="updirection" />
    </exit>
  </object>
  <object name="second room">
    <inherit name="editor_room" />
    <attr name="grid_image">http://cdn3.everyjoe.com/wp-content/gallery/kate-upton-zero-gravity/kate-upton-zero-gravity-1.jpg</attr>
    <exit alias="south" to="room">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="attic">
    <inherit name="editor_room" />
    <attr name="grid_image">http://cdn3.everyjoe.com/wp-content/gallery/kate-upton-zero-gravity/kate-upton-zero-gravity-2.jpg</attr>
    <enter type="script">
      Grid_SetGridCoordinateForPlayer (game.pov, this, "z", Grid_GetGridCoordinateForPlayer(game.pov, room, "z")+1)
    </enter>
    <exit alias="down" to="room">
      <inherit name="downdirection" />
    </exit>
  </object>
  <function name="GridSquareClick" parameters="x, y"><![CDATA[
    z = Grid_GetGridCoordinateForPlayer(game.pov, game.pov.parent, "z")
    d = Grid_GetPlayerCoordinateDictionary(player)
    foreach (key, d) {
      d2 = DictionaryItem(d, key)
      if (DictionaryContains(d2, "grid_isdrawn")) {
        r = GetObject(key)
        if (InGridRoom(r, d2, x, y, z)) {
          if(not game.pov.parent = r){
            msg("<br/>>map_click-goto: "+GetDisplayName(r)+"<br/>")
            MoveObject(game.pov,r)
            JS.scrollToEnd()
          }
          else {
            msg("<br/>>map_click-look<br/>")
            ShowRoomDescription
            JS.scrollToEnd()
          }
        }
      }
    }
  ]]></function>
  <function name="InGridRoom" parameters="room, dict, x, y, z" type="boolean"><![CDATA[
    flag = DictionaryItem(dict, "grid_isdrawn")
    if (not flag) {
      return (false)
    }
    z1 = DictionaryItem(dict, "z")
    if (not z = z1) {
      return (false)
    }
    n = DictionaryItem(dict, "x")
    x1 = n - room.grid_width / 2.0
    x2 = x1 + room.grid_width
    n = DictionaryItem(dict, "y")
    y1 = n - room.grid_length / 2.0
    y2 = y1 + room.grid_length
    if (x < x1 or x > x2) {
      return (false)
    }
    if (y < y1 or y > y2) {
      return (false)
    }
    return (true)
  ]]></function>
</asl>

Crap. I had forgotten to make the type boolean. It works fine.

Mister HurryPants.com here...


We've entered a new level in map-making! Outdoor Map-Generator Demo:

http://textadventures.co.uk/games/view/mctudqh-00mot77wz2zigg/map-rpg-demo

Please DOWNLOAD the game, INSTEAD of playing it online! (It will work much better)


K.V.

Up-to-date version of GridImageLib.aslx:

https://github.com/KVonGit/QuestStuff/blob/master/libraries/GridImageLib/GridImageLib.zip?raw=true


K.V.

Hello.

Anyone have any ideas as to why this reloads the online images but not the local images when loading a saved game?

GridImageLib.aslx

<?xml version="1.0"?>
	<!--
	
	IMPORTANT:
	You must add the following line to you User Interface Initialisation script:
	
	SetupGridImages
	
	-->
<!--
		GridImgLib 
		
		by KV
		
		Special Guest Coders:  MrAngel & Dcoder
		
		VERSION 2.0
		
		This will allow you to set a picture to display in place of a room's 
		standard map image.  
		
		All you need to do is include this library along (make sure its js file is in the folder as well!), make sure the map is enabled,
		then go to the new "Grid Image" tab on the room object.  From there, you
		can use the file browser to import an image file, or you can enter a URL
		to use an online image.  
		
		(You can NOT enter the path to the file!  If using a local image,
		the file MUST be in the game's main folder!!!)
		
		===
		
		IMPORTANT NOTE:
		
		If you want to switch back to using the standard map image, you must completely
		remove the "grid_image" attribute from the room!!!
		
		===
		
		Designed for Quest 5.7.1
		Year of publication: 2018

-->
	<!--
	
	IMPORTANT:
	You must add the following line to you User Interface Initialisation script:
	
	SetupGridImages
	
	-->
  <library>
  
	<function name="SetGridImgPath" parameters="filename">
		JS.setImagePath (GetFileUrl("_FILENAME_"))
	</function>
  
	<function name="Grid_DrawRoom" parameters="room, redraw, playerobject"><![CDATA[
		if (room.grid_render) {
		  if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {
			if (room.parent <> null) {
			  Grid_DrawRoom (room.parent, redraw, playerobject)
			}
			gridx = Grid_GetGridCoordinateForPlayer(game.pov, room, "x")
			gridy = Grid_GetGridCoordinateForPlayer(game.pov, room, "y")
			JS.Grid_DrawBox (gridx, gridy, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
			if (HasString(room, "grid_image")) {
			  imgfile = false
			  imgexts = Split(".png;.jpeg;.gif;.jpg;svg",";")
			  room.imageid = room.name+"-grid-image"
			  JS.eval ("var roomImageId = '"+room.imageid+"';var gridX = '"+gridx+"';var gridY = '"+gridy+"';var roomGridWidth = '"+room.grid_width+"';var roomGridHeight = '"+room.grid_length+"';customDrawImage('"+room.grid_image+"');")
			}
			if (LengthOf(room.grid_label) > 0) {
			  label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
			  label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
			  JS.Grid_DrawLabel (label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label)
			}
			foreach (exit, AllExits()) {
			  if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
				Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
			  }
			}
			Grid_SetRoomBooleanForPlayer (playerobject, room, "grid_isdrawn", true)
		  }
		}
	]]></function>
    

	
	<function name="SetupGridImages"><![CDATA[
	  SetGridImgPath("")
	  foreach (room, AllObjects()) {
		if (HasAttribute(room,"grid_image")) {
		  JS.eval ("imagesToCheck.push('"+room.grid_image+"');checkImages();")
		}
	  }
	]]></function>
  

	<!--
	Add a tab to the editor.
	-->

	<tab>
		<parent>_ObjectEditor</parent>
		<onlydisplayif>game.gridmap</onlydisplayif>
		<caption>Grid Image(optional)</caption>
		<title>Select an image to display in the map</title>
		<mustnotinherit>editor_object</mustnotinherit>
		<control>
		  <controltype>checkbox</controltype>
		  <caption>Enter a URL (or file name) instead of loading a local image</caption>
		  <attribute>gridimg_custompath</attribute>
		</control>
		<control>
			<caption>Grid Image</caption>
			<controltype>file</controltype>
			<attribute>grid_image</attribute>
			<source>[EditorImageFormats]</source>
			<filefiltername>Picture Files</filefiltername>
			<onlydisplayif>not HasAttribute(this,"gridimg_custompath")</onlydisplayif>
			<preview/>
		</control>
		<control>
			<caption>Grid Image</caption>
			<controltype>file</controltype>
			<attribute>grid_image</attribute>
			<source>[EditorImageFormats]</source>
			<filefiltername>Picture Files</filefiltername>
			<onlydisplayif>not this.gridimg_custompath</onlydisplayif>
			<preview/>
		</control>
		<control>
			  <controltype>label</controltype>
			  <onlydisplayif>not this.gridimg_custompath</onlydisplayif>
			  <caption>THIS FILE WILL BE IMPORTED BY QUEST</caption>
			</control>
		<control>
		  <caption>Enter the URL or file name</caption>
		  <attribute>grid_image</attribute>
		  <controltype>textbox</controltype>
		  <onlydisplayif>this.gridimg_custompath</onlydisplayif>
		</control>
		<control>
		  <controltype>label</controltype>
		  <onlydisplayif>this.gridimg_custompath</onlydisplayif>
		  <caption>IF ENTERING A FILE NAME, BE SURE THE FILE IS IN THE GAME'S FOLDER!!!</caption>
		</control>
	</tab>
  <javascript src="GridImageLib.js" />
  
  </library>

GridImageLib.js

var questImagePath = "";

setImagePath = function(path) {
  questImagePath = path;
};

getFileUrlJS = function(filename){
  if(filename.indexOf("://") > 0) {
	return (filename);
  } else {
	return questImagePath.replace("_FILENAME_", filename);
  }
};
var imagesToCheck = [];

function checkImages(){
	imagesToCheck.forEach(function(img){
		isFileGood(img)
	});
};

var failedImgs = [];

function imgFail(imgFailed){
	failedImgs.push(imgFailed.src);
};

function isFileGood(url){
	imgFile = getFileUrlJS(url);
	addText("<img style='display:none' /*onload='addToMap()'*/ onerror='imgFail(this)' src='"+imgFile+"'/>");
};

customDrawImage = function(url){
	var imgFile = getFileUrlJS(url);
	var failnumber = failedImgs.indexOf(imgFile);
	if(failnumber === -1){
		gridApi.drawCustomLayerImage(roomImageId, imgFile, parseFloat(gridX), parseFloat(gridY), parseInt(roomGridWidth), parseInt(roomGridHeight));
	}
};

Yes, as KV stated, I created a barebones desktop game (in Q5.7.2) with KV's "GridImageLib.aslx" installed (which also contains "GridImageLib.js"). This overlays the standard map room shape with a custom image.

The problem is when you reload a saved game -- the rooms that were previously entered won't show the custom image, even after reentering the rooms. Newly entered rooms, however, will show the custom image properly. Also, this issue ONLY arises if the custom images are stored in the local game folder, not if they are stored online.

Thoughts?


Thoughts since last time I looked at this:

The url parameter of gridApi.drawCustomLayerImage( doesn't have to be a URL. It can also be the id of an <img> element that already exists.
As you're creating a load of <img> elements for testing, you could give them an id attribute, (id="grid_image_'+room.name+'"'?) and then if it loads successfully, you can pass the id instead of a URL to drawCustomLayerImage, allowing it to use the data already received.

so you could do something like…

        <function name="SetupGridImages"><![CDATA[
	  SetGridImgPath("")
	  foreach (room, AllObjects()) {
            if (HasAttribute(room,"grid_image")) {
              JS.CheckImage(room.name, room.grid_image)
            }
	  }
	]]></function>

and

CheckImage = function (name, url) {
  name = name.replace(/\s/, "");
  if (!$("#grid_image_"+name).length) {
    imgFile = getFileUrlJS(url);
    $('<img id="grid_image_'+name+'" style="display:none" onload="$(this).addClass(\'grid-image-loaded\');" src="'+GetFileUrlJS(url)+'" onerror="imgFail(this)" />').appendTo("#divOutput");
  }
};

DrawRoomImage = function(name, gridX, gridY, gridWidth, gridHeight) {
  name = name.replace(/\s/, "");
  var id = 'grid_image_'+name;
  var img = $("#"+id);
  if (img.length > 0) {
    if (img[0].complete) {  // test if the browser is still waiting for a response
      if (img.is(".grid-image-loaded")) {
        gridApi.drawCustomLayerImage(id, id, parseFloat(gridX), parseFloat(gridY), parseInt(roomGridWidth), parseInt(roomGridHeight));
      }
    } else {
      // keep on trying ever half-second until the image loads
      SetTimeout(function () { DrawRoomImage(name, gridX, gridY, gridWidth, gridHeight);}, 500);
    }
  }
};

K.V.

This (mrangel's new code) still works (perhaps more efficiently), but the local images still don't load in a saved game.

I have this as one room's image "https://i.imgur.com/mBf7TBeb.png", and another room is a local image. The local image does not appear in the grid on the map when loading a saved game, but the url is still there.


The only thing I can think of is some kind of race condition on startup. Try putting JS breadcrumbs to track all calls to CheckImage, DrawRoomImage, and the onload/onerror handlers for the image. See if we can figure out if those functions are being hit in a different order for local vs external images.


K.V.

Gotcha.


K.V.

I added all the debugging log entries I could think of. Here's the library, the JS file, the game, the log from a normal game, and the log from a saved game:

GridImageLib.aslx

<?xml version="1.0"?>
	<!--
	
	IMPORTANT:
	You must add the following line to you User Interface Initialisation script:
	
	SetupGridImages
	
	-->
<!--
		GridImgLib 
		
		by KV
		
		Special Guest Coders:  MrAngel & Dcoder
		
		VERSION 2.0
		
		This will allow you to set a picture to display in place of a room's 
		standard map image.  
		
		All you need to do is include this library along (make sure its js file is in the folder as well!), make sure the map is enabled,
		then go to the new "Grid Image" tab on the room object.  From there, you
		can use the file browser to import an image file, or you can enter a URL
		to use an online image.  
		
		(You can NOT enter the path to the file!  If using a local image,
		the file MUST be in the game's main folder!!!)
		
		===
		
		IMPORTANT NOTE:
		
		If you want to switch back to using the standard map image, you must completely
		remove the "grid_image" attribute from the room!!!
		
		===
		
		Designed for Quest 5.7.1
		Year of publication: 2018

-->
	<!--
	
	IMPORTANT:
	You must add the following line to you User Interface Initialisation script:
	
	SetupGridImages
	
	-->
  <library>
  
	<function name="SetGridImgPath" parameters="filename">
		JS.setImagePath (GetFileUrl("_FILENAME_"))
	</function>
  
	<function name="Grid_DrawRoom" parameters="room, redraw, playerobject"><![CDATA[
		if (room.grid_render) {
		  if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {
			if (room.parent <> null) {
			  Grid_DrawRoom (room.parent, redraw, playerobject)
			}
			gridx = Grid_GetGridCoordinateForPlayer(game.pov, room, "x")
			gridy = Grid_GetGridCoordinateForPlayer(game.pov, room, "y")
			JS.Grid_DrawBox (gridx, gridy, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
			if (HasString(room, "grid_image")) {
			  imgfile = false
			  imgexts = Split(".png;.jpeg;.gif;.jpg;svg",";")
			  room.imageid = room.name+"-grid-image"
			  JS.eval ("var roomImageId = '"+room.imageid+"';var gridX = '"+gridx+"';var gridY = '"+gridy+"';var roomGridWidth = '"+room.grid_width+"';var roomGridHeight = '"+room.grid_length+"';customDrawImage('"+room.grid_image+"');")
			}
			if (LengthOf(room.grid_label) > 0) {
			  label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
			  label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
			  JS.Grid_DrawLabel (label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label)
			}
			foreach (exit, AllExits()) {
			  if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
				Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
			  }
			}
			Grid_SetRoomBooleanForPlayer (playerobject, room, "grid_isdrawn", true)
		  }
		}
	]]></function>
    

	
    <function name="SetupGridImages"><![CDATA[
	  SetGridImgPath("")
	  foreach (room, AllObjects()) {
            if (HasAttribute(room,"grid_image")) {
              JS.CheckImage(room.name, room.grid_image)
            }
	  }
	]]></function>
  

	<!--
	Add a tab to the editor.
	-->

	<tab>
		<parent>_ObjectEditor</parent>
		<onlydisplayif>game.gridmap</onlydisplayif>
		<caption>Grid Image(optional)</caption>
		<title>Select an image to display in the map</title>
		<mustnotinherit>editor_object</mustnotinherit>
		<control>
		  <controltype>checkbox</controltype>
		  <caption>Enter a URL (or file name) instead of loading a local image</caption>
		  <attribute>gridimg_custompath</attribute>
		</control>
		<control>
			<caption>Grid Image</caption>
			<controltype>file</controltype>
			<attribute>grid_image</attribute>
			<source>[EditorImageFormats]</source>
			<filefiltername>Picture Files</filefiltername>
			<onlydisplayif>not HasAttribute(this,"gridimg_custompath")</onlydisplayif>
			<preview/>
		</control>
		<control>
			<caption>Grid Image</caption>
			<controltype>file</controltype>
			<attribute>grid_image</attribute>
			<source>[EditorImageFormats]</source>
			<filefiltername>Picture Files</filefiltername>
			<onlydisplayif>not this.gridimg_custompath</onlydisplayif>
			<preview/>
		</control>
		<control>
			  <controltype>label</controltype>
			  <onlydisplayif>not this.gridimg_custompath</onlydisplayif>
			  <caption>THIS FILE WILL BE IMPORTED BY QUEST</caption>
			</control>
		<control>
		  <caption>Enter the URL or file name</caption>
		  <attribute>grid_image</attribute>
		  <controltype>textbox</controltype>
		  <onlydisplayif>this.gridimg_custompath</onlydisplayif>
		</control>
		<control>
		  <controltype>label</controltype>
		  <onlydisplayif>this.gridimg_custompath</onlydisplayif>
		  <caption>IF ENTERING A FILE NAME, BE SURE THE FILE IS IN THE GAME'S FOLDER!!!</caption>
		</control>
	</tab>
  <javascript src="GridImageLib.js" />
  
  </library>

GridImageLib.js

var questImagePath = "";

setImagePath = function(path) {
	console.log("");
	console.log("setImagePath");
	console.log(path);
  questImagePath = path;
};

getFileUrlJS = function(filename){
	console.log("");
	console.log("getFileUrlJS");
	console.log(filename);
  if(filename.indexOf("://") > 0) {
	  console.log(filename);
	return (filename);
  } else {
	  console.log(questImagePath.replace("_FILENAME_", filename));
	return questImagePath.replace("_FILENAME_", filename);
  }
};
var imagesToCheck = [];

function checkImages(){
	console.log("");
	console.log("checkImages");
	imagesToCheck.forEach(function(img){
		isFileGood(img)
	});
};

var failedImgs = [];

function imgFail(imgFailed){
	console.log("");
	console.log("imgFail");
	console.log(imgFailed);
	failedImgs.push(imgFailed.src);
};

function isFileGood(url){
	console.log("");
	console.log("isFileGood");
	console.log(url);
	imgFile = getFileUrlJS(url);
	console.log(imgFile);
	addText("<img style='display:none' /*onload='addToMap()'*/ onerror='imgFail(this)' src='"+imgFile+"'/>");
};

customDrawImage = function(url){
	console.log("");
	console.log("customDrawImage");
	console.log(url);
	var imgFile = getFileUrlJS(url);
	var failnumber = failedImgs.indexOf(imgFile);
	if(failnumber === -1){
		console.log("drawing custom layer");
		console.log(imgFile);
		gridApi.drawCustomLayerImage(roomImageId, imgFile, parseFloat(gridX), parseFloat(gridY), parseInt(roomGridWidth), parseInt(roomGridHeight));
	}
};

CheckImage = function (name, url) {
	console.log("");
	console.log("CheckImage");
	console.log(name);
	console.log(url);
  name = name.replace(/\s/, "");
  if (!$("#grid_image_"+name).length) {
    imgFile = getFileUrlJS(url);
	console.log(imgFile);
    $('<img id="grid_image_'+name+'" style="display:none" onload="$(this).addClass(\'grid-image-loaded\');" src="'+getFileUrlJS(url)+'" onerror="imgFail(this)" />').appendTo("#divOutput");
  }
};

DrawRoomImage = function(name, gridX, gridY, gridWidth, gridHeight) {
	console.log("");
	console.log("DrawRoomImage");
	console.log(name);
  name = name.replace(/\s/, "");
  var id = 'grid_image_'+name;
  var img = $("#"+id);
  if (img.length > 0) {
    if (img[0].complete) {  // test if the browser is still waiting for a response
      if (img.is(".grid-image-loaded")) {
		  console.log("drawing img");
		  console.log(name);
        gridApi.drawCustomLayerImage(id, id, parseFloat(gridX), parseFloat(gridY), parseInt(roomGridWidth), parseInt(roomGridHeight));
      }
    } else {
      // keep on trying ever half-second until the image loads
	  console.log("setting timeout to retry drawing img");
	  console.log(name);
      SetTimeout(function () { DrawRoomImage(name, gridX, gridY, gridWidth, gridHeight);}, 500);
    }
  }
};

game file

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <include ref="GridImageLib.aslx" />
  <game name="TESTMAP2">
    <gameid>f63f6998-9c91-461a-b7ac-f4c97644ad0d</gameid>
    <version>1.0</version>
    <firstpublished>2018</firstpublished>
    <feature_advancedscripts />
    <gridmap />
    <inituserinterface type="script">
      SetupGridImages
    </inituserinterface>
    <start type="script">
    </start>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <attr name="grid_image">https://i.imgur.com/mBf7TBeb.png</attr>
    <gridimg_custompath />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="south" to="room2">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="room2">
    <inherit name="editor_room" />
    <attr name="grid_image">SunflowersD.jpg</attr>
    <exit alias="north" to="room">
      <inherit name="northdirection" />
    </exit>
    <exit alias="south" to="room3">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="room3">
    <inherit name="editor_room" />
    <attr name="grid_image">GrasslandB.png</attr>
    <exit alias="north" to="room2">
      <inherit name="northdirection" />
    </exit>
  </object>
</asl>

normal game console log

 
GridImageLib.js?c=197805992:5 setImagePath
GridImageLib.js?c=197805992:6 quest://local/_FILENAME_?c=197805992
GridImageLib.js?c=197805992:64 
GridImageLib.js?c=197805992:65 CheckImage
GridImageLib.js?c=197805992:66 room
GridImageLib.js?c=197805992:67 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197805992:11 
GridImageLib.js?c=197805992:12 getFileUrlJS
GridImageLib.js?c=197805992:13 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197805992:15 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197805992:71 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197805992:11 
GridImageLib.js?c=197805992:12 getFileUrlJS
GridImageLib.js?c=197805992:13 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197805992:15 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197805992:64 
GridImageLib.js?c=197805992:65 CheckImage
GridImageLib.js?c=197805992:66 room2
GridImageLib.js?c=197805992:67 SunflowersD.jpg
GridImageLib.js?c=197805992:11 
GridImageLib.js?c=197805992:12 getFileUrlJS
GridImageLib.js?c=197805992:13 SunflowersD.jpg
GridImageLib.js?c=197805992:18 quest://local/SunflowersD.jpg?c=197805992
GridImageLib.js?c=197805992:71 quest://local/SunflowersD.jpg?c=197805992
GridImageLib.js?c=197805992:11 
GridImageLib.js?c=197805992:12 getFileUrlJS
GridImageLib.js?c=197805992:13 SunflowersD.jpg
GridImageLib.js?c=197805992:18 quest://local/SunflowersD.jpg?c=197805992
GridImageLib.js?c=197805992:64 
GridImageLib.js?c=197805992:65 CheckImage
GridImageLib.js?c=197805992:66 room3
GridImageLib.js?c=197805992:67 GrasslandB.png
GridImageLib.js?c=197805992:11 
GridImageLib.js:12 getFileUrlJS
GridImageLib.js:13 GrasslandB.png
GridImageLib.js:18 quest://local/GrasslandB.png?c=197805992
GridImageLib.js:71 quest://local/GrasslandB.png?c=197805992
GridImageLib.js:11 
GridImageLib.js:12 getFileUrlJS
GridImageLib.js:13 GrasslandB.png
GridImageLib.js:18 quest://local/GrasslandB.png?c=197805992
GridImageLib.js:51 
GridImageLib.js:52 customDrawImage
GridImageLib.js:53 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js:11 
GridImageLib.js:12 getFileUrlJS
GridImageLib.js:13 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js:15 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js:57 drawing custom layer
GridImageLib.js:58 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js:51 
GridImageLib.js:52 customDrawImage
GridImageLib.js:53 SunflowersD.jpg
GridImageLib.js:11 
GridImageLib.js:12 getFileUrlJS
GridImageLib.js:13 SunflowersD.jpg
GridImageLib.js:18 quest://local/SunflowersD.jpg?c=197805992
GridImageLib.js:57 drawing custom layer
GridImageLib.js:58 quest://local/SunflowersD.jpg?c=197805992

save game console log

 
GridImageLib.js?c=197806018:52 customDrawImage
GridImageLib.js?c=197806018:53 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197806018:11 
GridImageLib.js?c=197806018:12 getFileUrlJS
GridImageLib.js?c=197806018:13 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197806018:15 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197806018:57 drawing custom layer
GridImageLib.js?c=197806018:58 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197806018:51 
GridImageLib.js?c=197806018:52 customDrawImage
GridImageLib.js?c=197806018:53 SunflowersD.jpg
GridImageLib.js?c=197806018:11 
GridImageLib.js?c=197806018:12 getFileUrlJS
GridImageLib.js?c=197806018:13 SunflowersD.jpg
GridImageLib.js?c=197806018:18 
GridImageLib.js?c=197806018:57 drawing custom layer
GridImageLib.js?c=197806018:58 
GridImageLib.js?c=197806018:4 
GridImageLib.js?c=197806018:5 setImagePath
GridImageLib.js?c=197806018:6 quest://local/_FILENAME_?c=197806020
GridImageLib.js?c=197806018:64 
GridImageLib.js?c=197806018:65 CheckImage
GridImageLib.js?c=197806018:66 room
GridImageLib.js?c=197806018:67 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197806018:11 
GridImageLib.js?c=197806018:12 getFileUrlJS
GridImageLib.js?c=197806018:13 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197806018:15 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197806018:71 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197806018:11 
GridImageLib.js?c=197806018:12 getFileUrlJS
GridImageLib.js?c=197806018:13 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197806018:15 https://i.imgur.com/mBf7TBeb.png
GridImageLib.js?c=197806018:64 
GridImageLib.js?c=197806018:65 CheckImage
GridImageLib.js?c=197806018:66 room2
GridImageLib.js?c=197806018:67 SunflowersD.jpg
GridImageLib.js?c=197806018:11 
GridImageLib.js?c=197806018:12 getFileUrlJS
GridImageLib.js?c=197806018:13 SunflowersD.jpg
GridImageLib.js?c=197806018:18 quest://local/SunflowersD.jpg?c=197806020
GridImageLib.js?c=197806018:71 quest://local/SunflowersD.jpg?c=197806020
GridImageLib.js?c=197806018:11 
GridImageLib.js?c=197806018:12 getFileUrlJS
GridImageLib.js?c=197806018:13 SunflowersD.jpg
GridImageLib.js?c=197806018:18 quest://local/SunflowersD.jpg?c=197806020
GridImageLib.js?c=197806018:64 
GridImageLib.js?c=197806018:65 CheckImage
GridImageLib.js?c=197806018:66 room3
GridImageLib.js?c=197806018:67 GrasslandB.png
GridImageLib.js?c=197806018:11 
GridImageLib.js?c=197806018:12 getFileUrlJS
GridImageLib.js?c=197806018:13 GrasslandB.png
GridImageLib.js?c=197806018:18 quest://local/GrasslandB.png?c=197806020
GridImageLib.js?c=197806018:71 quest://local/GrasslandB.png?c=197806020
GridImageLib.js?c=197806018:11 
GridImageLib.js?c=197806018:12 getFileUrlJS
GridImageLib.js?c=197806018:13 GrasslandB.png
GridImageLib.js?c=197806018:18 quest://local/GrasslandB.png?c=197806020

K.V.

Fixed!

I change the grid_image attribute to the result of getFileUrlJs() during the initial setup. The saved game will load from that url. (Works in the desktop player and online.)

customDrawImage = function(url){
	var imgFile = getFileUrlJS(url);
	var failnumber = failedImgs.indexOf(imgFile);
	if(failnumber === -1){
		ASLEvent('AslSet', roomImageId.replace("-",".").replace("grid-image","grid_image")+"="+imgFile);
		gridApi.drawCustomLayerImage(roomImageId, imgFile, parseFloat(gridX), parseFloat(gridY), parseInt(roomGridWidth), parseInt(roomGridHeight));
	}
};

That's kind of what I expected in the logs; in the saved game, it's drawing the image before you make the call to checkImages, because the grid is restored to its previous state before UI initialisation. This means that as it stands, a URL that fails to load will remain in the save file, and will be passed to Raster (I believe someone said that messed up the map) when the save is restored because failedImgs hasn't been populated yet.

The DrawRoomImage function in the last example was intended to be a replacement for your customDrawImage; drawing the image from the existing <img> rather than going back to the URL.


K.V.

The DrawRoomImage function in the last example was intended to be a replacement for your customDrawImage

Oh. (I should have noticed that. It didn't even add an entry showing DrawRoomImage being called in the console log, and I didn't notice that, either. Doh!)

It's working now, though.

Thanks mrangel and Dcoder!


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

Support

Forums