Making every Food item in the Room or Inventory Rot.

YiKwang
21 Feb 2022, 13:59

I am having trouble figuring out how to do this...

I have several Food items, each with an Int Attribute 'FRESHNESS'

Each item has its own starting FRESHNESS from 18 to 63, but every turn i want every single item i nthe Player's current room AND inventory to have it's FRESHNESS reduced by 1.

I know I can FRESHNESS = FRESHNESS - 1, but I dont know how work that into making the script find and choose every object with the FRESHNESS attribute, and affect ONLY those objects.


mrangel
21 Feb 2022, 14:12

Each item has its own starting FRESHNESS from 18 to 63, but every turn i want every single item i nthe Player's current room AND inventory to have it's FRESHNESS reduced by 1.

So food doesn't go off if the player leaves the room?

Well, that's not a difficult thing to handle. You will want to use a foreach loop, which lets you go over a list of objects and do the same thing to each one.

Something like:

foreach (object, GetAllChildObjects (game.pov.parent)) {
  if (HasInt (object, "FRESHNESS")) {
    object.FRESHNESS = object.FRESHNESS - 1
  }
}

Where object is an arbitrary name; you can call the variable whatever you want; and FRESHNESS is the name of the attribute.

As I previously mentioned, you must not destroy the object within this loop, as foreach generates an error if the list changes before it has finished. But you can do anything else you would normally do with an object.

GetAllChildObjects gets a list of every object that is inside the room, or inside an object inside the room. You could use ScopeReachable() or ScopeVisible() instead; those only deal with objects the player can see (so not objects that are invisible or in a closed box)


YiKwang
21 Feb 2022, 14:21

So, If I just replace 'game.pov.parent' with 'game', will that affect everything?

If I did that I would want to also only affect objects which have the attribute Prototype, since I do not want the original items that were cloned to rot.


YiKwang
21 Feb 2022, 14:37

I think i have it working using:

If object has FRESHNESS
  then
  if object has attribute prototype
    then
    fresh = fresh - 1

with:

loop all obj,
if object fresh <= 0
  then
  remove object

now I want a message saying 'your fish has rotted', but is there a way I can have the game print: 'your [FISH ALIAS] has rotted'?


YiKwang
21 Feb 2022, 15:01

I found AllObjects() and got the Rot to apply to everything, and a way for it to only show a rot message if you are in the room, or when you reach the room.

for Curious parties, so far I have:

foreach (object, AllObjects()) {
  if (HasObject (object, "prototype") and HasInt (object, "FRESHNESS")) {
    object.FRESHNESS = object.FRESHNESS - 1
  }
}
foreach (object, GetAllChildObjects (game.pov.parent)) {
  if (HasAttribute(object, "FRESHNESS")) {
    if (object.FRESHNESS <= 0) {
      if (Contains (game.pov.parent,object)) {
        msg ("A Fish has rotted away.")
      }
      RemoveObject (object)
    }
  }
}

mrangel
21 Feb 2022, 15:05

So, If I just replace 'game.pov.parent' with 'game', will that affect everything?

If I did that I would want to also only affect objects which have the attribute Prototype, since I do not want the original items that were cloned to rot.

To affect all items, you would probably want to use AllObjects ().
For all cloned objects, I think it would be:

foreach (object, AllObjects()) {
  if (HasObject (object, "prototype") and HasInt (object, "FRESHNESS")) {
    object.FRESHNESS = object.FRESHNESS - 1 
    if (object.FRESHNESS <= 0) {
      RemoveObject (object)
    }
 ​ }
}

However, this might become slow after time, because it will still keep reducing the freshness of all the removed objects.
One way to avoid this slowdown would be destroying clones rather than removing them; which is easiest to accomplish by making a list of objects to destroy (because foreach and destroy interact oddly)
So it would look like:

foodToRemove = NewStringList()
foreach (object, AllObjects()) {
  if (HasObject (object, "prototype") and HasInt (object, "FRESHNESS")) {
    object.FRESHNESS = object.FRESHNESS - 1 
    if (object.FRESHNESS <= 0) {
      list add (foodToRemove, object.name)
    }
 ​ }
}
foreach (objectname, foodToRemove) {
  destroy (objectname)
}

(destroy is called using a string containing the name of an object, not the object itself… so you make a list of object names)


mrangel
21 Feb 2022, 15:07

Looks like we were typing at the same time. That seems valid, but it's probably more efficient to do things inside the same loop. And you will have the problem I mentioned if the number of destroyed objects gets large.


YiKwang
21 Feb 2022, 15:34

So, i definitely want to destroy with that last example, but when I replace what I last posted with what you last posted, I get:

> fish
You attempt to catch a fish...
You have caught a Roach!
You pick it up.
Error running script: Function not found: '​'

The same Error running scr... prints after every action, wait, or what have you.

Everything still seems to work, and I cannot find where this blank function is.


YiKwang
21 Feb 2022, 15:40

Maybe I could use my method, but add a:

if object has attribute prototype
  if object.parent = null
    destroy object

?


mrangel
21 Feb 2022, 15:43

That's confusing. Can you share a link to the game so I can take a look at it? My first guess would be an extra , somewhere, or a , that should be a ..


YiKwang
21 Feb 2022, 15:44

Ok, I couldnt find it in Code View, but in the Quest GUI I found an empty call function underneath 'foodtoremove [value] [expression] object.name

I think one too many } at the bottom...


YiKwang
21 Feb 2022, 15:46

Now I have this and the error is gone: (EDITED TO ADD FISH ROT MESSAGE)

foodToRemove = NewStringList()
foreach (object, AllObjects()) {
  if (HasObject (object, "prototype") and HasInt (object, "FRESHNESS")) {
    object.FRESHNESS = object.FRESHNESS - 1
    if (object.FRESHNESS <= 0) {
      if ((Contains (game.pov.parent,object))) {
        list add (foodToRemove, object.name)
        msg ("A Fish has rotted away...")
      }
    }
  }
}
foreach (objectname, foodToRemove) {
  destroy (objectname)
}

YiKwang
21 Feb 2022, 15:48

looks identical... I have no idea where the empty call function came from o.O