How do I tell Quest this?

  1. Pull up a list of all visible objects in reach of the player.
  2. Search for an object in the list with a specific alias that will have clones elsewhere.
  3. Apply a script to this specific clone and not anhy of the others.

The ScopeReachable function will do the first. Use FilterByAttribute to do the second, and loop over the result.

l1 = ScopeReachable()
l2 = FilterByAttribute (l1, "alias", "some alias")
foreach (obj, l2) {
  do (obj, "my script")
}

This will run the script "my script" for every object in reach that is called "some alias" (it assumes they all have the script).


What's with the L1, L2?


They are local variables, list one and list two. List one gets set to be a list of reachable objects. List two is that, but filtered so only those with the alias "some alias" are in the list. Then it iterates through each member of list two.


Well I'm not very good and screwing around by changing the script directly, so tell me if this makes any sense:

l1 = ScopeReachable()
l2 = FilterByAttribute (l1, "alias", "boar")
foreach (obj, l2) {
  do (obj, "if (Bow.arrows > 0) {    Bow.arrows = Bow.arrows - 1    if (RandomChance(Kill.chance))
    RemoveObject (l2) {    }  }  else {    msg ("You don't have any arrows.")  }  ")
}

K.V.

You'd probably need something like this:

//============================================================
//   Set the script up.
//============================================================
myScript => {
  if (Bow.arrows > 0) {
    Bow.arrows = Bow.arrows - 1    
    if (RandomChance(Kill.chance)) {
      RemoveObject (obj)
    }
  }
  else {
    msg ("You don't have any arrows.")  
  } 
}
//============================================================
//  Now that the script is set up, set up the lists.
//============================================================
l1 = ScopeReachable()
l2 = FilterByAttribute (l1, "alias", "boar")
//============================================================
// Now invoke the script for each object in the final list.
//============================================================
foreach (obj, l2) {
  invoke(myScript)
}

Your script for the boar should be in an attribute. Create an attribute under the original boar which you are making clones. Name it attack_boar or something you will recognize as an attack script. Then below the attributes box it will say "String", drop down in the box and select "script". Then add your script. when you attack you will use the "do (obj, attack_boar) part of your script in your verb.
This part goes in the attribute script.

l1 = ScopeReachable()
l2 = FilterByAttribute (l1, "alias", "boar")
foreach (obj, l2) {
 if (Bow.arrows > 0) {   
 Bow.arrows = Bow.arrows - 1 
}  
 if (RandomChance(Kill.chance)) {
    RemoveObject (obj) 
 }  
else {    
msg ("You don't have any arrows.")   
}

I'm not sure the script is legit, but the directions are.


Ha. KV beat me to it! Trust his script....


K.V can you just write out exactly how to write the script? I'm too dumb to understand all the //notes.

Forge er, what's a string?


K.V.

It's cool. Notes threw me off in the beginning, too.

That is a working script, though.

Quest ignores the notes. Each note is just to let you know what the next bit of code is doing.


K.V.

Forgewright is right about setting up an attack_boar script attribute on the original boar, by the way. That would simplify things.

...it seems like mrangel posted that code in some other thread concerning this, but I can't find it.


Yeah, there have been quite a few posts about this but they all confuse me. Gosh working with clones is so difficult!


A string: two things.

A function thing.
Any expression that has "" surrounding them.
That's all I got.


K.V.

STRING

myVariable = "1"

INTEGER

myVariable = 1

http://docs.textadventures.co.uk/quest/types/


K.V.

Here's an example game with a boar call you can blow to make a boar show up.

<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Cloning Basics">
    <gameid>f56df349-ddd0-491b-a047-4f4be87a5212</gameid>
    <version>1.0</version>
    <firstpublished>2017</firstpublished>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
      <object name="boar_call">
        <inherit name="editor_object" />
        <alias>pig whistle</alias>
        <look>A perfectly normal pig whistle (also known as a "boar call").</look>
        <feature_usegive />
        <usestandardverblist />
        <displayverbs type="stringlist">
          <value>Look at</value>
          <value>Take</value>
        </displayverbs>
        <use type="script">
          if (Got(this)) {
            msg ("You blow on the pig whistle, and a new boar immediately appears.")
            newBoar = CloneObjectAndMoveHere(boar)
            newBoar.prototype = boar
          }
          else {
            msg ("You need to be holding it to do that.")
          }
        </use>
        <blowon type="script">
          if (Got(this)) {
            msg ("You blow on the pig whistle, and a new boar immediately appears.")
            newBoar = CloneObjectAndMoveHere(boar)
            newBoar.prototype = boar
          }
          else {
            msg ("You need to be holding it to do that.")
          }
        </blowon>
        <inventoryverbs type="stringlist">
          <value>Look at</value>
          <value>Blow</value>
          <value>Drop</value>
        </inventoryverbs>
      </object>
    </object>
  </object>
  <object name="boar">
    <inherit name="editor_object" />
    <look>A wild boar.</look>
    <alias>boar</alias>
    <hit>You hit it, but it doesn't accomplish much (besides pissing the boar off).</hit>
    <takemsg>You try, but the boar tries to bite you, so you decide against it.</takemsg>
    <displayverbs type="stringlist">
      <value>Look at</value>
      <value>Kill</value>
    </displayverbs>
    <alt type="stringlist">
      <value>pig</value>
      <value>oinker</value>
      <value>hog</value>
    </alt>
    <usestandardverblist />
    <attack type="script"><![CDATA[
      msg ("You attack the boar.<br/><br/>It puts up a little fight, but, in the end, you kill it.")
      newDeadBoar = CloneObjectAndMoveHere(dead_boar)
      obj = this.name
      destroy (obj)
      game.lastobjects = NewObjectList()
      list add (game.lastobjects, newDeadBoar)
    ]]></attack>
    <kill type="script"><![CDATA[
      msg ("You attack the boar.<br/><br/>It puts up a little fight, but, in the end, you kill it.")
      newDeadBoar = CloneObjectAndMoveHere(dead_boar)
      obj = this.name
      destroy (obj)
      game.lastobjects = NewObjectList()
      list add (game.lastobjects, newDeadBoar)
    ]]></kill>
  </object>
  <verb>
    <property>attack</property>
    <pattern>attack</pattern>
    <defaultexpression>"You can't attack " + object.article + "."</defaultexpression>
  </verb>
  <object name="dead_boar">
    <inherit name="editor_object" />
    <inherit name="surface" />
    <alias>dead boar</alias>
    <look>Deader than a doornail.</look>
    <feature_container />
    <listchildren />
    <hidechildren />
    <displayverbs type="stringlist">
      <value>Look at</value>
    </displayverbs>
    <inventoryverbs type="stringlist">
      <value>Look at</value>
      <value>Drop</value>
    </inventoryverbs>
    <takemsg>It's a little too heavy to tote around.</takemsg>
    <object name="hide">
      <inherit name="editor_object" />
      <alias>hide</alias>
      <look>The hide of a downed boar.</look>
      <take />
      <ontake type="script">
        this.alias = "boar's hide"
      </ontake>
    </object>
    <object name="raw boar meat">
      <inherit name="editor_object" />
      <take />
      <alias>raw boar meat</alias>
      <look>The raw meat you acquired after killing a wild boar.</look>
      <usedefaultprefix type="boolean">false</usedefaultprefix>
      <prefix>some</prefix>
    </object>
  </object>
  <verb>
    <property>blowon</property>
    <pattern>blow on;blow</pattern>
    <defaultexpression>"You can't blow on;blow " + object.article + "."</defaultexpression>
  </verb>
</asl>

K.V.

NOTES


You could just clone the object like this:

CloneObject(boar)

...but then you'd have to move it here because it wouldn't actually exist in the game world unless the original object (which is sometimes referred to as the prototype) was already in the location. The boar is not in any room in this game, so moving the clone is a must.

You could move it here like this:

CloneObjectAndMove(boar, game.pov.parent)

...or you could use player.parent, as long as you can't switch the game's point of view to any other objects during play:

CloneObjectAndMove(boar, player.parent)

...but, with player.parent or game.pov.parent, you'd still be doing extra typing (and thinking).

The easiest way is to do it is like this:

CloneObjectAndMoveHere(boar)

Now, it gets a little more complicated.


If we didn't want to add or change any attributes which were set only on this clone, we'd be finished , but, the last time I saw your code, there was something checking to see if the boar was a clone (for some reason, which I can't recall).

I think that attribute's name was original_object.

If I'm remembering right, mrangel said he'd come across some code where The Pixie used an attribute named prototype to serve the same purpose. (My memory is fuzzy, though. I may have it backwards.)

ANYWAY, I used prototype in my example. You may need to replace prototype with original_object. (I'd try out prototype first. If that failed, I'd save a backup copy of the game (just in case), then flip to code view, enter CTRL+H, and replace "prototype" with "original_object".)

prototype is an object attribute, meaning you can set it's return value to an object (like boar).

So...

First, we want to know what clone we're dealing with as soon as we clone the boar, so instead of just putting this:

CloneObjectAndMoveHere(boar)

... we do it like this:

newBoar = CloneObjectAndMoveHere(boar)

This still does the same thing, as far as cloning the boar and moving it here is concerned, but it also lets us manipulate the newly created clone's attributes with the newBoar variable we just created.

So, now we can add a line of script which ties the clone to its original object (or prototype) like this:

newBoar.prototype = boar

Put it together, and what have we got?

newBoar = CloneObjectAndMoveHere(boar)
newBoar.prototype = boar

A fresh boar. ("Kill the pig! Slit its throat!!!")


Finally, if we want to know if the boar we're dealing with is a clone, we can do this:

if(HasAttribute(this,"prototype")){
  //NOTE: object has prototype attribute, so it is a clone
  if(this.prototype = boar){
    //NOTE: object was cloned from boar
    // Add some scripting here, if you want something to happen to clones of boar!
    // Here's example scripting, but it's just a (very) dumb example:
    msg("After a moment, the dead boar melts away, like a vinyl record in a Freddy Kreuger movie.  (It must have been a poorly engineered clone.)")
    destroy(this.name)
  }
}

Here's a similar script (which I tested as the KILL script), minus the notes:

if (HasAttribute(this,"prototype")) {
  if (this.prototype = boar) {
    msg ("You attack the boar.<br/><br/>It puts up a small fight, but, before long, you slit its throat with your machete.<br/><br/>After a moment, you poke the boar, just to make sure it's really dead, and a deafening whistling sound blares from inside of it.<br/><br/>You're not exactly sure what's going on here, but you're pretty sure that's Mama Boar you can now see approaching at a very unsettling pace, and man!  She looks pissed-off!")
    newBoar = CloneObjectAndMoveHere(boar)
    boar.mamaBoar = newBoar
    newBoar.alias = "Mama Boar"
    newBoar.look = "She's much bigger than the one you just killed.  (Lots of bacon to be harvested!)"
    newScript => {
      msg ("You attack Mama Boar, but it does no good. (She is extremely thick-skinned!)")
    }
    newBoar.kill = newScript
    newBoar.attack = newScript
    SetTimeout (30) {
      msg ("<br/>Mama Boar tires of your antics and wanders off.")
      destroy (boar.mamaBoar.name)
    }
  }
}

I learned most of this by reading posts by mrangel, The Pixie, and HK.

If something works for you, I stole it from one of those guys.

If something throws an error, that's probably me (and I apologize in advance).


This does not seem to be working, is it properly written?

l1 = ScopeReachable()
l2 = FilterByAttribute (l1, "alias", "boar")
foreach (obj, l2) {
  do (obj, "if (Bow.arrows > 0) {    Bow.arrows = Bow.arrows - 1    if (RandomChance(Kill.chance))          RemoveObject (l2) {    }  }  else {    msg ("You don't have any arrows.")  }  ")
}

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

Support

Forums