Multiple Objects / Numbered Description

In my adventure, I want the player to enter a location. In that location he finds 4 metal balls. The player has then, to move the metal balls one by one(they are too heavy to move altogether), to another location.

This is where I'm struggling. I want the location to read;
You can see 4 balls.
rather than;
You can see a ball, a ball, a ball and a ball.
I also want the 'Places and Objects' pane to reflect this as well '4 balls'
When the player picks up a ball, I want the number in the location to go down accordingly eg, 3 balls, 2 balls, a ball
(I think a ball, looks better than 1 ball.)
Then when I move the balls to another location, I want the number to increase back up.

I'm guessing 'CloneandMove' would come into this, but not sure how to program (I mean code (showing my age)) it.
Would changing the objects 'listalias' also play a part for use in the 'Places and Objects' pane. Again not sure how to code that.

Hope someone out there can help.


My solution would be to have a "pile of balls" object, with 4 balls inside it. The pile's "take" script checks if the player is already carrying a ball, and if not moves one to the inventory, then changes the pile's alias to "4 balls", "3 balls" or "2 balls". If there's only one ball left, remove it from the pile and make the pile invisible.

The ball's "drop" script (or maybe its changedparent) checks if there's a ball in the destination room. If so, clone the pile. Or if there's a pile in the destination room, add the dropped ball to the pile and rename the pile for the changed number.

Does that make sense?


Not sure if I fully understand it.
Could you post some code or a sample/test game.


OK… off the top of my head. Rearranged a little for maximum simplicity.

Two objects, pile_of_balls and heavy_ball. I'd put the ball somewhere inaccessible, to be cloned in when you need it. The pile could either be left outside player space and cloned when needed, or placed where you need it. If the player can access the original pile, give it an attribute prototype pointing to itself. The pile should also have a count attribute specifying the number of balls in it.

The pile's take script:

// is the player already carrying a ball?
if (ListCount (FilterByAttribute (ListAllChildObjects(game.pov), "prototype", heavy_ball)) > 0) {
  msg ("The balls are too heavy to carry more than one.")
}
else {
  AddToInventory (CloneObject (heavy_ball))
  this.count = this.count - 1
}

The pile's changedcount script:

if (this.count = 0) {
  this.visible = false
}
else {
  this.visible = true
  if (this.count = 1) {
    // use the same alias for a pile of a single ball, or a ball being carried
    this.alias = GetDisplayAlias (heavy_ball)
  }
  else {
    this.alias = ToString (this.count) + " balls"
  }
}

Then we have the ball's changedparent script:

// We don't need to do anything special if it's being put in the inventory
if (not Contains (game.pov, this)) {
  // Find any existing piles of balls in this location:
  piles = FilterByAttribute (GetDirectChildren (this.parent), "prototype", pile_of_balls)
  // If there aren't any…
  if (ListCount (piles) = 0) {
    // … create one
    pile = CloneObjectAndMove (pile_of_balls, this.parent)
  }
  else {
    pile = ListItem (piles, 0)
  }
  // increase the count of the pile, and remove the individual ball
  pile.count = pile.count + 1
  destroy (this.name)
}

If the player needs to move the balls to a specific place, it might be worth putting a pile there with 0 balls in it. Initial count as zero, initially invisible, prototype set to the original pile (so the player can add balls to it), and a modified changedcount script that does whatever needs to be done when all the balls are placed there.


Okay.
That seems to work. I gave the 'pile_of_balls' the alias '4 balls' because without it, the room description showed 'pile_of_balls', then when I took one, the changed script kicked in, then read '3 balls'.

When I then moved location and dropped it, I received this error message.

Error running script: Collection was modified; enumeration operation may not execute.

Also, the new location listed '4 balls' (the 'pile_of_balls' alias), in the 'Places and Objects pane.

I then slightly modified the ball 'changedparent' script to 'move the ball' to a room the player cannot access.
Now, no error message, but the new location now contains both 'heavy_ball' and '4 balls' (the 'pile_of_balls' alias).


When I then moved location and dropped it, I received this error message.

Does it say where the error occurred?

Oh… my bad. You specifically can't destroy an object in the middle of a command which allows "all" as a parameter, because it passes the object reference as a list. So it's looping over a list of one object to drop, and destroying an object in the list causes the loop to bail out.

So yeah… move it to an inaccessible room there (and if you want to save memory, use a turnscript or turntimeout to destroy the unneeded clone later)


Also, the new location listed '4 balls' (the 'pile_of_balls' alias), in the 'Places and Objects pane.

I missed a line out:

  if (ListCount (piles) = 0) {
    // … create one
    pile = CloneObjectAndMove (pile_of_balls, this.parent)
    pile.count = 0
  }

I then slightly modified the ball 'changedparent' script to 'move the ball' to a room the player cannot access.
Now, no error message, but the new location now contains both 'heavy_ball' and '4 balls' (the 'pile_of_balls' alias).

I can't figure that out.
I'm assuming you changed:

  destroy (this.name)

to

  RemoveObject (this)

or

  this.parent = null

or

  this.parent = some_inaccessible_room

or

  MoveObject (this, some_inaccessible_room)

Any of those should work as far as I can see.


I've made those alterations, now I'm getting this error message.

Error running script: Error evaluating expression 'FilterByAttribute (GetDirectChildren (this.parent), "prototype", pile_of_balls)': GetDirectChildren function expected object parameter but was passed 'null'

Does it matter that I've got two separate counts going on.
The object 'pile_of_balls' uses this.count, which is essentially 'pile_of_balls.count', then the 'heavy_ball' uses 'pile.count' in the changedparent script.
Should they be the same?


Does it matter that I've got two separate counts going on.

No, you haven't. You have one count for each pile, which will vary depending on how many different places the player has dropped a ball.

this.count doesn't refer to pile_of_balls.count, it refers to the count of the current clone of the pile. And pile is a local variable which points to the pile in the same room as the ball.

I've made those alterations, now I'm getting this error message.

Ah; when you remove a ball, you're setting its parent to null. That means that the script to find other balls in the same room fails.
I'd suggest adding a specific test for that by modifying the first condition:

if (not (this.parent = null or Contains (game.pov, this))) {

so that the changedparent script doesn't do anything when the ball is removed from play.


That works great. Thanks.
When I use the objects display verbs, and click 'Take', is there a way of having it print take ball instead of 'take 4 balls' (or however many there are in the room, if there's more than one).


That's a challenge, but I think you can probably do that with javascript.

Top of my head (I'm on my phone here, sitting out in the garden) something like:

var link = getCurrentDiv().find('.cmdlink').last();
if(link.text().match(/^\d+ balls$/)) {
  link.text('ball');
}

Finds the last object link and changes its text. However, clicking that link and choosing another verb might echo "look at ball" while still targeting the pile.

I can see how tofix that by passing both elementids; but I'd need to double-check the contents of playercore.js for the details.

Also, "take all" will mess up a little. Might be better to print an explanatory message when taking one; so the output looks like:

> take 4 balls

You lift one of the heavy balls, which is all you can carry.

or

> take all

Bell: You pick it up.
Table: It's nailed down.
3 balls: You lift one of the heavy balls, which is all you can carry.

That's great mrangel, I like that last idea, such a simple solution.


Log in to post a reply.

Support

Forums