Custom Status Pane not working

Hi,
I'm trying to make my custom Status pane work based off the following guide: http://docs.textadventures.co.uk/quest/custom_panes.html

But all I get is

Hit Points: ---

Then a full black bar.

What am I doing wrong here?

Also how do I go about pushing a refresh of the status bar once I've changed the HP of the player after a turn action inside a room object?

I would also like to have another panel or addition to this one where other player stats are listed, like Strength, Defence, etc while keeping this HP bar.

<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="TestCustomPane">
    <gameid>853d3220-63b6-4b84-a5e1-aa279b29d27f</gameid>
    <version>1.0</version>
    <firstpublished>2017</firstpublished>
    <commandpane type="boolean">false</commandpane>
    <customstatuspane />
    <attr name="feature_advancedwearables" type="boolean">false</attr>
    <feature_advancedscripts />
    <inituserinterface type="script"><![CDATA[
      s = "<table width=\"100%\"><tr>"
      s = s + "   <td style=\"text-align:right;\" width=\"50%\">Hit Points:</td>"
      s = s + "   <td style=\"text-align:left;\" width=\"50%\"><span id=\"hits-span\">---</span></td>"
      s = s + " </tr>"
      s = s + " <tr>"
      s = s + "   <td colspan=\"2\" style=\"border: thin solid;background:white;text-align:left;\">"
      s = s + "   <span id=\"hits-indicator\" style=\"background-color:black;padding-right:200px;\"></span>"
      s = s + "   </td>"
      s = s + " </tr>"
      s = s + "</table>"
      JS.setCustomStatus (s)
      if (HasScript(player, "changedhitpoints")) {
        do (player, "changedhitpoints")
      }
    ]]></inituserinterface>
    <start type="script"><![CDATA[
      player.changedhitpoints => {
        JS.eval ("$('#hits-span').html('" + player.HP + "/" + player.MaxHP + "');")
        JS.eval ("$('#hits-indicator').css('padding-right', '" + (200 * player.HP / player.MaxHP) + "px');")
      }
      player.MaxHP = 200
      player.HP = 100
    ]]></start>
  </game>
  <object name="Start">
    <inherit name="editor_room" />
    <beforeenter type="script">
    </beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
      <HP type="int">150</HP>
      <MaxHP type="int">200</MaxHP>
    </object>
  </object>
</asl>

image


Hello!

You had:

player.MaxHP = 200
player.HP = 100

I changed it to what Pixie has in the guide:

player.maxhitpoints = 200
player.hitpoints = 100

I then took the liberty of replacing every instance of each with what Pixie had in the guide. Here's the whole code:

Click here for the code.
<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="TestCustomPane">
    <gameid>853d3220-63b6-4b84-a5e1-aa279b29d27f</gameid>
    <version>1.0</version>
    <firstpublished>2017</firstpublished>
    <commandpane type="boolean">false</commandpane>
    <customstatuspane />
    <attr name="feature_advancedwearables" type="boolean">false</attr>
    <feature_advancedscripts />
    <inituserinterface type="script"><![CDATA[
      s = "<table width=\"100%\"><tr>"
      s = s + "   <td style=\"text-align:right;\" width=\"50%\">Hit Points:</td>"
      s = s + "   <td style=\"text-align:left;\" width=\"50%\"><span id=\"hits-span\">---</span></td>"
      s = s + " </tr>"
      s = s + " <tr>"
      s = s + "   <td colspan=\"2\" style=\"border: thin solid;background:white;text-align:left;\">"
      s = s + "   <span id=\"hits-indicator\" style=\"background-color:black;padding-right:200px;\"></span>"
      s = s + "   </td>"
      s = s + " </tr>"
      s = s + "</table>"
      JS.setCustomStatus (s)
      if (HasScript(player, "changedhitpoints")) {
        do (player, "changedhitpoints")
      }
    ]]></inituserinterface>
    <start type="script"><![CDATA[
      player.changedhitpoints => {
        JS.eval ("$('#hits-span').html('" + player.hitpoints + "/" + player.maxhitpoints + "');")
        JS.eval ("$('#hits-indicator').css('padding-right', '" + (200 * player.hitpoints / player.maxhitpoints) + "px');")
      }
      player.maxhitpoints = 200
      player.hitpoints = 100
    ]]></start>
  </game>
  <object name="Start">
    <inherit name="editor_room" />
    <beforeenter type="script">
    </beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
      <hitpoints type="int">150</hitpoints>
      <maxhitpoints type="int">200</maxhitpoints>
    </object>
  </object>
</asl>

I did a side by side comparison of the code I posted and the one you provided but other than the change in the attribute name (which should be inconsequential) there doesn't appear to be anything different, so what is it about that that works?

I even changed the attributes again on your code and it does work now so again no idea what is different.


I also did a side-by-side comparison using diff. The difference in the two scripts: you had the variable named "HP", but the script named "changedhitpoints". As you don't have an attribute called "hitpoints", that script is never called.


Gotta change these too (don't ask me why; maybe Pixie knows):

You have:

if (HasScript(player, "changedhitpoints")) {
        do (player, "changedhitpoints")
      }

This works:

if (HasScript(player, "changedHP")) {
        do (player, "changedHP")

You have:

player.changedhitpoints => {

This works:

player.changedHP => {

New code, with your HP and maxHP atts:

<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="TestCustomPane">
    <gameid>853d3220-63b6-4b84-a5e1-aa279b29d27f</gameid>
    <version>1.0</version>
    <firstpublished>2017</firstpublished>
    <commandpane type="boolean">false</commandpane>
    <customstatuspane />
    <attr name="feature_advancedwearables" type="boolean">false</attr>
    <feature_advancedscripts />
    <inituserinterface type="script"><![CDATA[
      s = "<table width=\"100%\"><tr>"
      s = s + "   <td style=\"text-align:right;\" width=\"50%\">Hit Points:</td>"
      s = s + "   <td style=\"text-align:left;\" width=\"50%\"><span id=\"hits-span\">---</span></td>"
      s = s + " </tr>"
      s = s + " <tr>"
      s = s + "   <td colspan=\"2\" style=\"border: thin solid;background:white;text-align:left;\">"
      s = s + "   <span id=\"hits-indicator\" style=\"background-color:black;padding-right:200px;\"></span>"
      s = s + "   </td>"
      s = s + " </tr>"
      s = s + "</table>"
      JS.setCustomStatus (s)
      if (HasScript(player, "changedHP")) {
        do (player, "changedHP")
      }
    ]]></inituserinterface>
    <start type="script"><![CDATA[
      player.changedHP => {
        JS.eval ("$('#hits-span').html('" + player.HP + "/" + player.maxHP + "');")
        JS.eval ("$('#hits-indicator').css('padding-right', '" + (200 * player.HP / player.maxHP) + "px');")
      }
      player.maxHP = 200
      player.HP = 100
    ]]></start>
  </game>
  <object name="Start">
    <inherit name="editor_room" />
    <beforeenter type="script">
    </beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
      <HP type="int">150</HP>
      <maxHP type="int">200</maxHP>
    </object>
  </object>
</asl>


mrangel beat me to it while I was bumbling around. (Ha-ha!)

(I tried the side-by-side using diff, but I just went cross-eyed doing that!)

(That means I was playing around with it and editing my post for more than 23 minutes, then... Whoa!)


I did diff and found the obvious ones that had changed.
Then a Perl one-liner:
perl -e 'while(<>) {s/maxhitpoints/MaxHP/g; s/hitpoints/HP/; print $_;}'
to change the working one to new variable names; and then diff that against the not-working version.

The reason you have to change the function names too is that whenever player.hitpoints changes, it looks for a script player.changedhitpoints and runs it if it exists. If the names don't match, that script won't run.

The segment:

if (HasScript(player, "changedhitpoints")) {
        do (player, "changedhitpoints")
}

is to draw the bar correctly when you load a saved game. On a new game, that script doesn't exist yet because inituserinterface runs before start. So the first time the bar is drawn is when the line player.HP = 100 automatically triggers the changedHP script.


mrangel,

A-ha!

Thanks! I would have asked about the stuff concerning the function and the bar, but I guess you foresaw that, huh?


See what my msys64 BASH! terminal looks like when I run diff -y?

Click to view screenshot

image


I'm pretty sure I need a new diff viewer. ...or maybe I should just log in to Arch Linux first next time. (Ha-ha!)

I used sed to replace the text. It seems that learning Perl would be worthwhile. It's similar to what I'm accustomed to, but a little 'neater' in appearance.

I looked at your potato problem, too, but the solution to that one is far beyond me, so I just kept 'quiet'.


Okay that explains it.
I wanted to change the status bar to be set to an attribute from a specific room instead of the player HP, now that I understand that issue.

I created 2 rooms with an attribute called AlertStatus and 1 room with no attribute, I added the script setup for each room individually in the game global Start script and the status panel setup in the Enter Room script with a HasAttribute check on the player.parent (current Room the player resides in) for the AlertStatus, check it out:

<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="TestRoomStatus">
    <gameid>0bae2a50-2560-4e7c-8016-02867de11bb8</gameid>
    <version>1.0</version>
    <firstpublished>2017</firstpublished>
    <feature_advancedscripts />
    <customstatuspane />
    <roomenter type="script"><![CDATA[
      oRoomObj = player.parent
      if (HasAttribute(oRoomObj,"AlertStatus")) {
        s = "<table width=\"100%\"><tr>"
        s = s + "   <td style=\"text-align:right;\" width=\"50%\">Alert Status:</td>"
        s = s + "   <td style=\"text-align:left;\" width=\"50%\"><span id=\"alert-span\">---</span></td>"
        s = s + " </tr>"
        s = s + " <tr>"
        s = s + "   <td colspan=\"2\" style=\"border: thin solid;background:white;text-align:left;\">"
        s = s + "   <span id=\"alert-indicator\" style=\"background-color:black;padding-right:200px;\"></span>"
        s = s + "   </td>"
        s = s + " </tr>"
        s = s + "</table>"
        JS.setCustomStatus (s)
        if (HasScript(oRoomObj, "changedAlertStatus")) {
          do (oRoomObj, "changedAlertStatus")
        }
      }
      else {
        JS.setCustomStatus ("Everything is fine!")
      }
    ]]></roomenter>
    <start type="script"><![CDATA[
      Room1.changedAlertStatus => {
        JS.eval ("$('#alert-span').html('" + Room1.AlertStatus + "/100');")
        JS.eval ("$('#alert-indicator').css('padding-right', '" + (200 * Room1.AlertStatus / 100) + "px');")
      }
      Room1.AlertStatus = 0
      Room2.changedAlertStatus => {
        JS.eval ("$('#alert-span').html('" + Room2.AlertStatus + "/100');")
        JS.eval ("$('#alert-indicator').css('padding-right', '" + (200 * Room2.AlertStatus / 100) + "px');")
      }
      Room2.AlertStatus = 0
    ]]></start>
  </game>
  <object name="Room1">
    <inherit name="editor_room" />
    <AlertStatus type="int">0</AlertStatus>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="south" to="Room2">
      <inherit name="southdirection" />
    </exit>
    <exit alias="east" to="Room3">
      <inherit name="eastdirection" />
    </exit>
  </object>
  <object name="Room2">
    <inherit name="editor_room" />
    <AlertStatus type="string"></AlertStatus>
    <exit alias="north" to="Room1">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="Room3">
    <inherit name="editor_room" />
    <exit alias="west" to="Room1">
      <inherit name="westdirection" />
    </exit>
  </object>
</asl>

Pretty neat. But a little inefficient; especially as you're going to have to add to your start script every time you add a new room with an AlertStatus.

Might be easier to make the start script something likeā€¦

foreach (room, AllObjects()) {
  if (HasAttribute (room, "AlertStatus")) {
    room.changedAlertStatus => {
      // When a room's alert status is changed, we change the status pane only if the player is in that room
      // Whether the if() line is necessary will depend on your gameplay, but it does no harm to include it
      if (Contains (this, game.pov)) {
        JS.eval ("$('#alert-span').html('" + this.AlertStatus + "/100');")
        JS.eval ("$('#alert-indicator').css('padding-right', '" + (200 * this.AlertStatus / 100) + "px');")
      }
    }
    // Not sure if the next line is necessary.
    // If you just set the attribute to 0 when you create a room, it's probably easier.
    // Especially if you might later want a room whose alert level doesn't start at 0
    room.AlertStatus = 0
  }
}

That loops over all objects, and gives them all the same script if they have an AlertLevel attribute.
It also only updates the status pane if you change the alert level of the room the player is in; I can envision situations where you might want to change the alert in another room (leaving a decoy maybe? Or reducing it if a guard is in the room and sees you're not there?), and in those cases you wouldn't want the pane to show the alert level of the room that most recently had it changed. If you're not doing that, the 'if' statement is just one line, so doesn't make that much difference.

If you want some rooms to have an alert level and have other scripts that trigger when you enter, I've got a script for that too, but am less confident that it would work without testing it.


Great stuff! How do I just display a static attribute status that won't change?


Why does inituserinterface run before start? I'm just wondering because in the full code view, start comes before inituserinterface. Thanks.


inituserinterface runs before anything on start and on a save load.

I think it's really just there to fix the display and GUI elements before anything else loads up on the screen.

http://docs.textadventures.co.uk/quest/advanced_game_script.html

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


If you have libraries that adjust the display and the GUI stuff, things will load in a ...strange manner.

I ended up putting a lot of testing messages in my start script, inituserinterface script, and the functions in my library that effected such things.

It was fun.


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

Support

Forums