Making every Food item in the Room or Inventory Rot.

YiKwang
21 Feb 2022, 13:59I 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:12Each 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:21So, 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:37I 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:01I 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:05So, 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:07Looks 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:34So, 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:40Maybe I could use my method, but add a:
if object has attribute prototype
if object.parent = null
destroy object
?
mrangel
21 Feb 2022, 15:43That'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:44Ok, 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:46Now 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:48looks identical... I have no idea where the empty call function came from o.O