Oxygen Tank

Greetings everyone! I have a space suit that I am working on and I would like to add some 'zazz' to the game by including an oxygen tank. My goal is once you add the tank to the suit the oxygen will deplete after "X" amount of turns and therefore the game is over because you cannot breathe. I have tried to set up various turn scripts, change scripts, if scripts, but to no avail. I currently have my suit set up as a wearable and a surface container, and the tank under the "Use/Give" tab as "Use this on (other object)". Am I on the right track or do I need to go a whole different direction?


Sounds like you've thought about what you're doing; seems a pretty sensible setup. I can't see a problem with it. Maybe you could share your code, and we might be able to see what's wrong?

I'd probably use a single turnscript to handle the suit and oxygen. Something like:

// Set up the initial oxygen level. Useful on the web editor; if you're on desktop you can just set it in the Attributes tab
if (not HasInt (oxygentank, "fullness")) {
  oxygentank.fullness = 42
}

// check if the player needs an oxygen tank
// I'm assuming a container called "space" which contains all space rooms
//   so it's easy to see where the space suit is needed

if (Contains (space, game.pov)) {
  // Now check if the player can breathe
  breathing = false
  if (not GetBoolean (spacesuit, "worn")) {
    OutputTextNoBr ("It's a very bad idea to go into space without wearing your {object:spacesuit}! ")
  }
  else if (not Contains (spacesuit, oxygentank)) {
    OutputTextNoBr ("You need to attach an {object:oxygentank} to your {object:spacesuit}. ")
  }
  else if (oxygentank.fullness = 0) {
    OutputTextNoBr ("Your {object:oxygentank} is empty! ")
  }
  else {
    // We can breathe!
    breathing = true
    oxygentank.fullness = oxygentank.fullness - 1
    if (oxygentank.fullness = 0) {
      msg ("Your suit's air circulator rattles to a stop. Your oxygen supply is depleted.")
      // The amount of air in a suit 
      this.suffocating = -3
    }
    else if (oxygentank.fullness < 6) {
      msg ("An alarm sounds in your helmet. Your oxygen supply is nearly depleted.")
    }
  }
}
else {
  breathing = true
}

// I'd probably give the player the ability to hold their breath for a few turns
// so a careless mistake isn't immediately fatal.
if (breathing) {
  this.suffocating = null
}
else {
  if (not HasInt (this, "suffocating")) this.suffocating = 0
  this.suffocating = this.suffocating + 1
  switch (this.suffocating) {
    case (-2,0) {
      msg ("The last bit of air in your suit is getting more stale by the second.")
    }
    case (1) {
      msg ("Your lungs are burning, and you know that you need to find air quickly.")
    }
    case (2) {
      msg ("You start to feel dizzy and light headed from lack of oxygen.")
    }
    case (3) {
      msg ("You try to take a breath but there is nothing there. You pass out and die.")
      finish()
    }
  }
}

Thank you for your reply mrangel! I was trying to use the example game code here https://docs.textadventures.co.uk/quest/guides/turn_based_events.html and then modify it for my purpose. I didn't have any luck with it as I have no idea what I am doing. Here is the game code I am currently using to test out all the ideas I would like to do with the suit. I have everything working except for the tank.

<!--Saved by Quest 5.8.6836.13983-->
<asl version="580">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Space Suit Test">
    <gameid>da9a73f7-e789-4e28-8658-d361f2e0b6df</gameid>
    <version>1.0</version>
    <firstpublished>2020</firstpublished>
    <feature_advancedwearables />
    <attr name="feature_advancedscripts" type="boolean">false</attr>
  </game>
  <object name="room1">
    <inherit name="editor_room" />
    <isroom />
    <attr name="print message" type="int">8</attr>
    <description type="script">
    </description>
    <enter type="script">
    </enter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <object name="spacesuit">
      <inherit name="editor_object" />
      <inherit name="wearable" />
      <inherit name="surface" />
      <feature_wearable />
      <alt type="stringlist">
        <value>suit</value>
      </alt>
      <feature_container />
      <onafterremove type="script">
        if (not IsSwitchedOn(switch)) {
          msg ("There's no oxygen!")
          finish
        }
      </onafterremove>
    </object>
    <object name="tank">
      <inherit name="editor_object" />
      <inherit name="surface" />
      <take />
      <attr name="feature_container" type="boolean">false</attr>
      <listchildren />
      <hidechildren />
      <feature_usegive />
    </object>
    <exit alias="south" to="room2">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="room2">
    <inherit name="editor_room" />
    <enter type="script">
      if (GetBoolean(spacesuit, "worn")) {
      }
      else {
        msg ("You're not wearing the suit!")
        finish
      }
    </enter>
    <exit alias="north" to="room1">
      <inherit name="northdirection" />
    </exit>
    <exit alias="south" to="room3">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="room3">
    <inherit name="editor_room" />
    <exit alias="north" to="room2">
      <inherit name="northdirection" />
    </exit>
    <exit alias="south" to="room1">
      <inherit name="southdirection" />
    </exit>
    <object name="switch">
      <inherit name="editor_object" />
      <inherit name="switchable" />
      <feature_switchable />
      <onswitchon type="script">
        msg ("Life support restored!")
      </onswitchon>
      <onswitchoff type="script">
        msg ("Main power grid offline")
      </onswitchoff>
    </object>
  </object>
</asl>

Seems a pretty straightforward way to implement this system.

I'm not sure what the benefit is to using that event system. It seems to be quite a complex way of maintaining a countdown system; just adding more complexity.

I'd suggest giving the tank an attribute to represent how much oxygen is in it, and make a turnscript which reduces that number by 1 every turn. I called the attribute fullness in the last example, but oxygen would probably be better.

You could have a turnscript which reduces the oxygen by 1 every turn, and kills the player when it runs out:

tank.oxygen = tank.oxygen - 1
if (tank.oxygen = 0) {
  msg ("You have run out of oxygen.")
  finish
}

Then you could modify the script when entering room 2 so that it checks for the tank:

      if (GetBoolean(spacesuit, "worn")) {
        if (Contains (spacesuit, tank)) {
          EnableTurnScript (oxygen)
        }
        else {
          msg ("Your spacesuit doesn't have an oxygen tank.")
          finish
        }
      }
      else {
        msg ("You're not wearing the suit!")
        finish
      }

And modify the script for removing the suit so that it stops the tank from emptying:

        if (IsSwitchedOn(switch)) {
          DisableTurnScript (oxygen)
        }
        else {
          msg ("There's no oxygen!")
          finish
        }

So the whole script would look like:


<!--Saved by Quest 5.8.6836.13983-->
<asl version="580">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Space Suit Test">
    <gameid>da9a73f7-e789-4e28-8658-d361f2e0b6df</gameid>
    <version>1.0</version>
    <firstpublished>2020</firstpublished>
    <feature_advancedwearables />
    <attr name="feature_advancedscripts" type="boolean">false</attr>
  </game>
  <turnscript name="oxygen">
    <script>
      tank.oxygen = tank.oxygen - 1
      if (tank.oxygen = 0) {
        msg ("You have run out of oxygen.")
        finish
      }
    </script>
  </turnscript>
  <object name="room1">
    <inherit name="editor_room" />
    <isroom />
    <attr name="print message" type="int">8</attr>
    <description type="script">
    </description>
    <enter type="script">
    </enter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <object name="spacesuit">
      <inherit name="editor_object" />
      <inherit name="wearable" />
      <inherit name="surface" />
      <feature_wearable />
      <alt type="stringlist">
        <value>suit</value>
      </alt>
      <feature_container />
      <onafterremove type="script">
        if (IsSwitchedOn(switch)) {
          DisableTurnScript (oxygen)
        }
        else {
          msg ("There's no oxygen!")
          finish
        }
      </onafterremove>
    </object>
    <object name="tank">
      <inherit name="editor_object" />
      <inherit name="surface" />
      <take />
      <oxygen type="int">9</oxygen>
      <listchildren />
      <hidechildren />
      <feature_usegive />
    </object>
    <exit alias="south" to="room2">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="room2">
    <inherit name="editor_room" />
    <enter type="script">
      if (GetBoolean(spacesuit, "worn")) {
        if (Contains (spacesuit, tank)) {
          EnableTurnScript (oxygen)
        }
        else {
          msg ("Your spacesuit doesn't have an oxygen tank.")
          finish
        }
      }
      else {
        msg ("You're not wearing the suit!")
        finish
      }
    </enter>
    <exit alias="north" to="room1">
      <inherit name="northdirection" />
    </exit>
    <exit alias="south" to="room3">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="room3">
    <inherit name="editor_room" />
    <exit alias="north" to="room2">
      <inherit name="northdirection" />
    </exit>
    <exit alias="south" to="room1">
      <inherit name="southdirection" />
    </exit>
    <object name="switch">
      <inherit name="editor_object" />
      <inherit name="switchable" />
      <feature_switchable />
      <onswitchon type="script">
        msg ("Life support restored!")
      </onswitchon>
      <onswitchoff type="script">
        msg ("Main power grid offline")
      </onswitchoff>
    </object>
  </object>
</asl>

As this stands, the player would need to "put tank on suit" - but you said you wanted the "use" command to work as well.
In that case, you'd want to make the "Use this on (other object)" script for the tank something like:

  this.parent = object

If you want, you could modify the turnscript so that the player is reminded how much oxygen remains:

tank.oxygen = tank.oxygen - 1
if (tank.oxygen = 0) {
  msg ("You have run out of oxygen.")
  finish
}
else {
  msg ("You have {tank.oxygen} turns of oxygen left.")
}

Or for a more realistic-sounding readout, you could make the number a percentage and reduce it by several points each turn. Maybe a random number (between 5% and 8% in this example) so it feels less mechanical:

tank.oxygen = tank.oxygen - GetRandomInt (5, 8)
if (tank.oxygen <= 0) {
  msg ("You have run out of oxygen.")
  finish
}
else {
  msg ("{tank.oxygen}% oxygen remaining.")
}

You could even vary it based on which command the player used this turn:

switch (game.pov.currentcommandpattern) {
  case (look, lookat, lie, wait, inventory) {
    tank.oxygen = tank.oxygen - GetRandomInt (2, 3)
  }
  case (jump, pull, push, use, useon) {
    tank.oxygen = tank.oxygen - GetRandomInt (9, 12)
  }
  case (oops, undo, xyzzy, help, save) {
    // nothing for these
  }
  default {
    tank.oxygen = tank.oxygen - GetRandomInt (5, 8)    
  }
}
if (tank.oxygen <= 0) {
  msg ("You have run out of oxygen.")
  finish
}
else {
  msg ("{tank.oxygen}% oxygen remaining.")
}

If you're using percentages, the player might find a reminder every turn to be annoying. So you could make it so that it only does it every time the reading passes a multiple of 10%, or when they're nearly out, by giving the tank a script attribute named changedoxygen containing something like:

if (this.oxygen < 0) {
  msg ("You have run out of oxygen.")
  finish
}
else if (this.oxygen < 15 or this.oxygen/10 < oldvalue/10) {
  msg ("{tank.oxygen}% oxygen remaining.")
}

In this case, the turnscript only needs to reduce the amount of oxygen in the tank.
Hoping that all makes sense.


Thank you very much for your help mrangel!


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

Support

Forums