Torch Script

In this verb script for a torch, the line do (player.shield, "nobonus") gives the error

Error running script: Object reference not set to an instance of an object.

I am removing the equipped shield and replacing it with a torch. Or if the player chooses to remove the weapon then I am going to add that in as well.

How do I run the "nobonus" attribute in this case?

if (this.switchedon = true) {
  msg ("It is already lit.")
}
if (HasAttribute(torch.parent, "nolight")) {
  msg ("It is not yours to light.")
}
else if (player.shield <> null and player.onehanded <> null) {
  options = Split("Shield;Weapon", ";")
  game.temp = this
  ShowMenu ("Which will you unequip?", options, true) {
    this = game.temp
    switch (result) {
      case ("Shield") {
        msg ("You put away your shield and light your torch, holding it out to see.")
        player.shield.listalias = Replace(player.shield.listalias, " (equipped)", "")
        player.shield.equipped = False
        player.shield = this
      }
      case ("Weapon") {
        msg ("You put away your weapon and light your torch, holding it out to see.")
        player.onehanded.listalias = player.onehanded.orginalalias
        do (player.onehanded, "nobonus")
        player.onehanded.equipped = False
        player.onehanded = this
      }
    }
    on ready {
      this.switchedon = True
      list add (this.inventoryverbs, "Snuff")
      list remove (this.inventoryverbs, "Light")
      this.listalias = this.listalias + " (lit)"
      torch.burned = True
      ShouldMonstersAttack
      EnableTurnScript (torchturnscript)
    }
  }
}

Put a changedequipped on the torch so I don't need to do anything in this script!

if (this.equipped = False) {
  player.armour = player.armour - 1
}
if (this.equipped = True) {
  player.armour = player.armour + 1
}

Using changescripts probably makes an equipment system much easier :-p
I suspect that if you used both changedequipped scripts on each weapon and changedonehanded (etc) scripts on the player, you could cut your code in half; letting Quest's magic do a lot of the work for you.


I was working with the changescript and realized what you just posted. Came here to mention it and here you are. Now I'll have to spend a month discovering just how much it can do with them. Thanks Mrangel. Time to get another book. And watch a video. I too write but have yet to publish anything. I don't have the deep thought process of the characters that you have.

Allowed gratuitous and shameless plug: Mrangel's Amazon Books -To help a top answer poster on the forum. One of our own!


I would have started from something like changedonehanded:

newvalue = this.equipped
if (IsDefined ("oldvalue")) [{
  oldvalue.equipped = false
}
if (newvalue = this.equipped and not weapon = null) {
  this.onehanded.equipped = true
}

Then if a weapon's changedequipped adds or removes any necessary stat values, its equip verb could be as simple as:

if (this.equipped) {
  msg ("You're already holding your sword.")
}
else {
  player.onehanded = this
}

A previous weapon is unequipped automatically; and the code feels simpler because it's broken up into smaller bits. If there are special cases (like a sword that can be used in one hand or two, or a cursed sword that you can't unequip), they have slightly more complex scripts - but the complexity is limited to one item, rather than having huge trees of if statements in the main script.

Actually, I'd probably make changedequipped look like:

if (this.equipped) {
  list add (player.equipactions, "raise your " + this.alias)
  // adjust player's combat values if necessary
}
else {
  list add (player.equipactions, "put away your " + this.alias)
  // adjust player's combat values if necessary
}

and equip verb:

if (this.equipped) {
  msg ("You're already holding your " + this.alias + ".")
}
else {
  player.equipactions = NewStringList()
  player.onehanded = this
  msg ("You " + FormatList (player.equipactions, ", ", "and", "can't do that") + ".")
}

to get a response like "You unstring your bow, lower your shield, and grip the warhammer in both hands." without a ton of logic - you could give different weapons different messages depending on type, or even use {random, and they get put together afterwards.


If I add a verb "equip" to the weapon do I need to remove the global command "equip"?


Well, I'm a bit lost.
What am I missing in this example using the new scripts?
I don't know where to add the responses you reference here.

to get a response like "You unstring your bow, lower your shield, and grip the warhammer in both hands." without a ton of logic - you could give different weapons different messages depending on type, or even use {random, and they get put together afterwards.

EDITED:

<!--Saved by Quest 5.8.6836.13983-->
<asl version="580">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Equipping system">
    <gameid>250ece70-5ca1-437b-b317-46d4c28e5221</gameid>
    <version>1.0</version>
    <firstpublished>2020</firstpublished>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <isroom />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
      <changedonehanded type="script">
        newvalue = this.equipped
        if (IsDefined ("oldvalue")) {
          oldvalue.equipped = false
        }
        if (weapon = this.equipped and not weapon = null) {
          this.onehanded.equipped = true
        }
      </changedonehanded>
      <object name="small_sword">
        <inherit name="editor_object" />
        <equip type="script">
          if (this.equipped) {
            msg ("You're already holding your " + this.alias + ".")
          }
          else {
            player.equipactions = NewStringList()
            player.onehanded = this
            msg ("You " + FormatList (player.equipactions, ", ", "and", "can't do that") + ".")
          }
        </equip>
        <changedequipped type="script">
          if (this.equipped) {
            list add (player.equipactions, "raise your " + this.alias)
          }
          else {
            list add (player.equipactions, "put away your " + this.alias)
          }
        </changedequipped>
        <alias>sword</alias>
        <equipped type="boolean">false</equipped>
        <one_handed />
        <listalias>Sword</listalias>
        <price type="int">3</price>
        <volume type="int">2</volume>
        <damage>5d2</damage>
        <orignalalias>Sword</orignalalias>
      </object>
    </object>
  </object>
  <verb>
    <property>equip</property>
    <pattern>equip</pattern>
    <defaultexpression>"You can't equip " + object.article + "."</defaultexpression>
  </verb>
</asl>

I get this for a response.

equip sword
Error running script: Error compiling expression 'oldvalue': RootExpressionElement: Cannot convert type 'Object' to expression result of 'Element'
You can't do that.


If I add a verb "equip" to the weapon do I need to remove the global command "equip"?

I assumed you were using a verb. The same thing works just as well as a global command; would just presumably have an attribute on a weapon to tell the command which slot(s) it goes in.


What am I missing in this example using the new scripts?

I left an error in the script (hazards of writing on my phone); I got a couple of variable names confused. And when I was correcting it, I realised that I made the player's changescript more complex than it needs to be. It can just be:

        if (IsDefined ("oldvalue")) {
          if (not oldvalue = null) {
            oldvalue.equipped = false
          }
        }
        if (not this.onehanded = null) {
          this.onehanded.equipped = true
        }

I don't need to check if unequipping the previous weapon has failed - a cursed weapon that the player can't unequip can just set player.onehanded back to itself in its changedequipped script, and everything else will work sensibly.

I don't know where to add the responses you reference here.

to get a response like "You unstring your bow, lower your shield, and grip the warhammer in both hands." without a ton of logic - you could give different weapons different messages depending on type, or even use {random, and they get put together afterwards.

In the changedequipped script for each weapon.

          if (this.equipped) {
            list add (player.equipactions, "raise your " + this.alias)
          }
          else {
            list add (player.equipactions, "put away your " + this.alias)
          }

If this script is given to a type, you could either use generic messages, or get them from some attribute.

Does that make sense?

The "equip" command/verb changes player.onehanded (I'd probably name the attribute lefthand and righthand; but used the variable name you were using for the example).
changedonehanded then checks if there was an oldvalue (a previously equipped weapon) in that slot, and sets its equipped flag to false. And its changedequipped adds "unstring your bow" or "lower your sword" or whatever to the list player.equipactions.
changedonehanded then changes equipped to true for the newly equipped weapon, which fires its changedequipped script, and adds "draw your sword" or whatever to the equipactions list.

Then control returns to the equip command/varb, which prints out the list (using FormatList to add commas and the word "and" between items as necessary). Basically giving a one-sentence description of all each item that was unequipped or equipped.

In the case of a two-handed weapon (like the warhammer in my example), the equip verb might look more like:

          if (this.equipped) {
            msg ("You're already holding your " + this.alias + ".")
          }
          else {
            player.equipactions = NewStringList()
            // This line is optional; it just makes the output a little nicer
            player.shield = null
            player.onehanded = this
            player.shield = this
            msg ("You " + FormatList (player.equipactions, ", ", "and", "can't do that") + ".")
          }

and the changedequipped would have a little extra logic to make sure it's unequipped from both slots (so that if it's automatically removed by equipping a one-hand sword, the shield slot is now free as well):

          if (this.equipped) {
            list add (player.equipactions, "shoulder your " + this.alias)
          }
          else {
            if (player.onehanded = this) player.onehanded = null
            if (player.shield = this) player.shield = null
            list add (player.equipactions, "grip your " + this.alias + " in both hands")
          }

I get this for a response.

Not sure what to make of that… possibly oldvalue is null? (I've not checked that). Added a check to the script earlier in this post.


No matter whether the sword is equipped (true or false) the response is
EDIT: I took out the scripts and reloaded them. I may have it working now. I will respond later.

equip sword
You shoulder your sword.

Where my example script is now.
EDITED
newest one

<!--Saved by Quest 5.8.6836.13983-->
<asl version="580">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Equipping system">
    <gameid>250ece70-5ca1-437b-b317-46d4c28e5221</gameid>
    <version>1.0</version>
    <firstpublished>2020</firstpublished>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <isroom />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
      <changedonehanded type="script">
        if (IsDefined ("oldvalue")) {
          if (not oldvalue = null) {
            oldvalue.equipped = false
          }
        }
        if (not this.onehanded = null) {
          this.onehanded.equipped = true
        }
      </changedonehanded>
      <equipactions type="stringlist" />
      <object name="small_sword">
        <inherit name="editor_object" />
        <equip type="script">
          if (this.equipped) {
            msg ("You're already holding your " + this.alias + ".")
          }
          else {
            player.equipactions = NewStringList()
            player.onehanded = this
            msg ("You " + FormatList (player.equipactions, ", ", "and", "can't do that") + ".")
          }
        </equip>
        <changedequipped type="script">
          if (this.equipped) {
            list add (player.equipactions, "raise your " + this.alias)
            // adjust player's combat values if necessary
          }
          else {
            list add (player.equipactions, "put away your " + this.alias)
            // adjust player's combat values if necessary
          }
        </changedequipped>
        <alias>sword</alias>
        <equipped type="boolean">false</equipped>
        <one_handed />
        <listalias>Sword</listalias>
        <price type="int">3</price>
        <volume type="int">2</volume>
        <damage>5d2</damage>
        <orignalalias>Sword</orignalalias>
        <take />
      </object>
    </object>
  </object>
  <verb>
    <property>equip</property>
    <pattern>equip</pattern>
    <defaultexpression>"You can't equip " + object.article + "."</defaultexpression>
  </verb>
</asl>

I should be working, but my brain's stuck in code mode :-S

Now thinking of a way to make it work for equipment that an NPC can equip… changing player to object.parent in a lot of cases. You'd have something like:

<function name="PrintEquipLine" parameters="character">
  if (EndsWith (TypeOf (character, "equipactions"), "list")) {
    if (ListCount (character.equipactions) > 0) {
      msg (CapFirst (GetDisplayAlias (character) + " " +ProcessText (FormatList (character.equipactions, ", ", ", and ", ""), QuickParams ("owner", character)) + ".")
    }
    character.equipactions = NewStringList()
  }
</function>

<turnscript name="equip_actions">
  <enabled />
  <script>
    scope = ScopeVisible()
    foreach (character, AllObjects()) {
      if (EndsWith (TypeOf (character, "equipactions"), "list")) {
        if (ListCount (character.equipactions) > 0) {
          if (ListContains (scope, character)) {
            PrintEquipLine (character)
          }
          else {
            character.equipactions = NewStringList()
          }
        }
      }
    }
  </script>
</turnscript>

(so the string for equipping an item could be, for example, "{conjugate:owner:draw} {either owner=game.pov:your:a} shiny revolver", "{conjugate:owner:cock} it" … and any characters who equip/unequip items will be printed out at the end of the turn even if whatever script caused them to drop stuff doesn't do it directly)

Oh… I've used "conjugate" there.
From my start script:

conj => {
  args = Tsplit (section)
  obj = ObjectForTextProcessor (ListItem (args, 1))
  if (obj = null) {
    obj = eval (ListItem (args, 1), ParamsForTextProcessor())
  }
  if (obj = null) {
    game.textprocessorcommandresult = "@@@open@@@" + ProcessTextSection (section, data) + "@@@close@@@"
  }
  else {
    game.textprocessorcommandresult = Conjugate (obj, ListItem (args, 2))
  }
}
game.textprocessorcommands = game.textprocessorcommands
dictionart add (game.textprocessorcommands, "conjugate:", conj)

(so you can use {conjugate:objectname:draw} to get "draw" or "draws" depending on the object)

Yeah… I'm looking at a system that started out as a nice idea because it's simpler, and started adding little bits of complexity so it can do nice things.

And then I'm looking at a way to automate the "Would you like to unequip your sword, or your shield?" thing for the torch.
The way I'm thinking about it, the "light" verb would then look like:

TryEquipObject (player, this, true) {
  this.switchedon = true
  this.burned = true
  EnableTurnScript (torchturnscript)
}

(because I'd be putting stuff like changing inventoryverbs and listalias into the torch's changedswitchedon script)

My brain wants to type out the workings of TryEquipObject while it's in my mind… but I know I really need to get back to the soul-destroying slog of marketing.


Instead of using switchedon = true or false, I have been recently using lightsource = true or false. Is it not the direct route to what causes a room to be seen? I have not tested it yet.

You are leagues ahead of me and have no near future thoughts that I could implement such scripts successfully. It is the reason I can not use many libraries. When a small change is needed to be made I can not follow the chain of scripts back up the line to ensure the success of that change. I steal small pieces that I do understand and make such wonderfully clunky coded scripts. I do, however, still gain the rush when something finally works.


I have been recently using lightsource = true or false

That makes the code simpler :) One less thing to change.
I did notice in your code that you often seem to have a few different ways of storing the same information. So cutting down on them might make the code more manageable.

And where it's useful to have the same info in multiple places (like player.shield and someShieldObject.equipped), it can be a lot simpler to use changescripts so that changing either of them changes the other. Then your other scripts can just worry about whichever is easiest for them :)


In some cases, I need several ways to store the same information. As an example, Using the "originalalias". When an item such as a torch that is not a weapon but can be equipped in the same attribute as weapons and does not have the same (equipped) tag after it in the inventory pane, but (lit)(unlit)(dimmer)(dimming)(burned out). I have given these items an "orignalalias" to refer to when I what to go back to adjust the alias, while using the same EquipFuction as a shield or weapon. It is a process I built and will/may change but at the time I was only trying to build a workable script. I can go back and tweak later.

Let's call it a necessity of ignorance...If I wanted to discuss a dog with a German but was ignorant of the German language I may, instead of referring its breed for a clearer understanding, just call it a "hund". Weak metaphor but I hope you get my drift.

There are so many steps I have to look up here on the forums, I have to finagle a few steps to get some kind of structure.


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

Support

Forums