[Solved] Create a Inventory menu - How to print a highlighted object after getting the object via Iterator (ForEach)?

This may be a real beginner question but...
I tried out to make a separated inventory for the stackable items in the game. So, the only problem is to display the items itself correctly.

foreach (stc, GetDirectChildren (player_inv_items)) {
  msg ("" + stc + " x " + stc.player_stack_value + "")
}

This only put this out.

Object: drop_old_coin x 1
Object: drop_paper x 2

I tried...

[...]
  msg ("{object:stc} x " + stc.player_stack_value + "")
}

This only put this out.

{object:stc} x 2
{object:stc} x 1

And the item isn't highlighted after all. The stack value is correctly.

What I want to get is the highlighted object which will open the verbs tab on click:

Old Coin x 1
Paper x 2


Try:

foreach (stc, GetDirectChildren (player_inv_items)) {
  msg ("{b:" + GetDisplayName(stc) + "} x " + stc.player_stack_value + "")
}

It uses GetDisplayName to get the name of the object (the alias if there is one), rather than using the object itself. The text processor command "{b:...}" does the bold.


try this:

foreach (stc, GetDirectChildren (player_inv_items)) {
  msg ("{object:" + stc.name + "} x " + stc.player_stack_value)
}

HK crosses his fingers (let me know if it doesn't work... there's a way to do the syntax, I'm sure... I might have it wrong...

you can take a look here:

https://textadventures.co.uk/forum/quest/topic/5089/solved-level-library-pixies

(too lazy to search for jay's/Pixie's 'levellib' itself, but the thread covers its content fully, I think)


@ Pixie:

what's the difference in using the 'GetDisplayName/GetDisplayAlias' Scripts/Functions vs just using the 'NAME_OF_OBJECT.name/NAME_OF_OBJECT.alias', ???

(I have the feeling I've probably asked this before years ago... lol... but I've forgotten what the difference/s was/were, sighs)


from years back (as I've not done this stuff for while), I learned that you could do (if I remember right):

potion.alias = "POTION"
potion.quantity = 99
potion.alias = GetDisplayAlias (potion) + " (" + potion.quantity + ")"
msg (potion.alias)
// POTION (99)

though, couldn't you just do this too?

potion.alias = "POTION"
potion.quantity = 99
potion.alias = potion.alias + " (" + potion.quantity + ")"
msg (potion.alias)
// POTION (99)

what's the difference?


@ Curt A.P.

to explain:

the '{object:NAME_OF_OBJECT}' text processor command requires the 'name' String Attribute of the Object

whereas, you're using the built-in 'GetDirectChildren' Script/Function which returns an: Object List Variable, which means that it's items are 'Object' Values, and thus not meeting the requirement of the '{object:NAME_OF_OBJECT}' text processor command, as it requires the string name Value of the Object, and thus the 'foreach' Script's/Function's item Variable (which is your use of 'stc'), is holding/storing an Object Value, and thus without converting it into a String Value, is causing your issues with the text processor command

that was probably confusing... not worded/explained very well... sorry... I tried to explain... and failed (probably confusing you more, sighs)... lol


let's try explaining it this way:

what you did:

{object:OBJECT_VALUE}

// OBJECT_VALUE = NAME_OF_OBJECT

// OBJECT_VALUE = stc

whereas it has to be:

{object:STRING_VALUE}

// STRING_VALUE = "NAME_OF_OBJECT"

// but you can't just do this to convert it into a string (too technical/hard/long to explain why this is so wrong syntax/programming wise, lol): "stc"

// so to convert an Object Value into a String value:

// STRING_VALUE = stc.name
// or:
// STRING_VALUE = GetDisplayName (stc)

// 'stc.name' returns/is a String Value
// 'GetDisplayName (stc)' returns/is a String Value

if you need to understand difference between a String Value and an Object Value:

create ("example_object")

// -------------

msg (example_object.name)
// displays (as text only, NOT a hyperlink): example_object

msg ("{object:example_object}")
// displays (as object hyperlink, showing you its verbs, when you click on it): example_object

object_variable = example_object
msg ("{object:" + object_variable.name + "}")
// displays (as object hyperlink, showing you its verbs, when you click on it): example_object

-----------

example_object.alias = "EXAMPLE OBJECT"

msg (example_object.alias)
// displays (as text only, NOT as a hyperlink): EXAMPLE OBJECT

msg ("{example_object.alias}")
// displays (as text only, NOT as a hyperlink): EXAMPLE OBJECT

string_variable = example_object.name
msg ("{object:" + string_variable + "}")
// displays (as object hyperlink, showing you its verbs, when you click on it): example_object

string_variable = GetdisplayName (example_object)
msg ("{object:" + string_variable + "}")
// displays (as object hyperlink, showing you its verbs, when you click on it): example_object

string_variable = example_object.name
msg ("{object:string_variable}")
// ERROR!!!!! (the text processor is literally using 'string_variable' instead of the Value that it's holding, which is why you got to use the concatenation to tell quest that the 'string_variable' is a VARIABLE, and thus to get and replace it with the Value that it is holding, as it needs the 'name' String Value of the Object)

string_variable = example_object.alias
msg ("{object:string_variable}")
// ERROR!!!!! (wrong syntax, ... AND... you can't use the 'alias', as that's not the 'name' (ID) String Attribute of the Object)

string_variable = example_object.alias
msg ("{object:" + string_variable + "}")
// ERROR!!!!! (correct syntax, ...BUT... you can't use the 'alias', as that's not the 'name' (ID) String Attribute of the Object)

if you need to understand difference between a String Value and an Object Value:

Object Values/Variables/Attributes/Data:

create ("katana")
katana.damage = 50

create ("dagger")
dagger.damage = 10

player.weapon = katana
msg (player.weapon.damage)
// displays: 50

player.weapon = dagger
msg (player.weapon.damage)
// displays: 10

// String Values/Attributes (the 'player.weapon' however still remains as an Object Value/Attribute):

katana.alias = "KATANA"

player.weapon = katana
msg (player.weapon.alias)
// displays: KATANA

dagger.alias = "DAGGER"

player.weapon = dagger
msg (player.weapon.alias)
// displays: DAGGER

// but now, let's make the 'player.weapon' a String Value/Attribute instead of an Object Value/Attribute:

player.weapon = katana.alias
msg (player.weapon)
// displays: KATANA

player.weapon = dagger.alias
msg (player.weapon)
// displays: DAGGER

msg (player.weapon.damage)
// ERROR!!!!

msg (player.weapon.alias)
// ERROR!!!!

Okay, I'll try them.

I try to understand Quest itself better.

using the built-in 'GetDirectChildren' Script/Function which returns an: Object List Variable, which means that it's items are 'Object' Values,

How does this values look like? I thought they're just the object's name (THE_OBJECTS_NAME)

And this maby?

foreach (stc, GetDirectChildren (GetDisplayName (player_inv_items))) {
  msg (" +stc + " + stc.player_stack_value)
}

I got the most now, I think. I read in the Documentaition, the GetAllDirectChildren function returns an object list. So, I wonder why this aren't object values.


what's the difference in using the 'GetDisplayName/GetDisplayAlias' Scripts/Functions vs just using the 'NAME_OF_OBJECT.name/NAME_OF_OBJECT.alias', ???

Using .name will work fine, as long as every object has a nice name, but often that is not the case (eg, objects with apostrophes need to use the alias, clones have numbers added). Using .alias will work fine, as long as every object has an alias - and his is what I do, I make sure everything has an alias, so I can use .alias.

GetDisplayName and GetDisplayAlias will use the alias if it exists, or the name otherwise, so in general are safer to use. I think one prepends "the" where appropriate (eg "you pick up the spade"), but I can never remember which, but that would be a further reason.


foreach (stc, GetDirectChildren (GetDisplayName (player_inv_items))) {
  msg (" +stc + " + stc.player_stack_value)
}

Function calls work from the inside outwards. You start with player_inv_items, which is ab object. Then you have GetDisplayName (player_inv_items), which will return a string, the name of player_inv_items. Then you send that string to GetDirectChildren... which wants an object. It is going to try to find the child objects of a string, and get confused!


@ Curt A.P.

err... I'm failing at this... been trying to write something... but... I'm failing... at the moment... sighs...

maybe I'm just tired and I can explain better when my brain's working better... or maybe not, lol... but right now.. I'm not able to explain it well... sighs... lol


I think it'd be better to let Pixie help/explain, as he is very clear and easy to understand in his posts and explanations, unlike me

(I'll probably just make you more confused)


in quest, 'The_OBJECTS_NAME', can be many different things:

  1. the Object itself, the 'name' (ID) of the Object, but NOT as a String Value (NOT as, or NOT converted-as-to, the 'name' String Attribute)
  2. a reference/pointer: an Object VARIABLE/Data_Type/Value
  3. a String Data Type
  4. the Object itself, the 'name' (ID) of the Object, AS a String Value (AS the 'name' String Attribute)

this is why I'm having such a hard time explaining it... lol... quest is simple to use, but hard to explain... lol...


so this is why there's a big difference between:

foreach (stc, NAME_OF_OBJECT_LIST) {
 // msg ("{object:"+ stc + "}") // ERROR!
 // vs
 // msg ("{object:" + stc.name + "}") // NO error
}

// VS

foreach (stc, NAME_OF_STRING_LIST) {
  if (GetObject (stc) = null) {
    msg ("ERROR: your inputted string list's string value item, " + stc + ", does not match up with any existing Object's name" )
  } else {
     msg ("{object:" + stc + "}") // NO error
  }
}

Yes, no errors but highlights something doesn't work. I thought, if it's working as text then I should make it text.

show_inv_stack = NewStringList()
foreach (itm, GetDirectChildren (player_inv_items)) {
  get_inv_name = itm.name
  list add (show_inv_stack, "{object:" + get_inv_name + "} x " + itm.player_stack_attribute + "")
}
msg ("" + (FormatList(show_inv_stack, "<br/>", "<br/>", "You have no items.")) + "")

Basicly I just took the non-highlighted output into a stringlist,
added the stack value into the string value
and print this well prepared stringlist with FormatList and linebreak parameters.
Now it's working like I wished, Thanks x)

Edit:
The new stringlist value's are like,
("{object:" + get_inv_name + "} x " + itm.player_stack_attribute + "")

Printed as normal text the '{object:}' expression have no problems taking the variable as plain text instead of a object value. I'll try my best to understand this thing better...


it's that Data Types are different:

String vs Boolean vs Integer vs Double vs Object vs List vs Dictionary vs etc (quest doesn't really have these, but in many languages: char, long: long integer, short: short integer, byte, word, double word, etc)

you can read up on Data Types in general and/or specific languages:

https://en.wikipedia.org/wiki/Data_type
https://chortle.ccsu.edu/java5/index.html#09 (see 'part 3: data' and 'part 6: object oriented programming: OOP')


if you want to learn/understand this stuff more deeply, let me know, I'd be happy to help if you're interested in learning to program/code more fully.

you can take a look at this, which is an Assembly Language (a low level language), which is close to the computer-machine level, on how programming is actually working underneath all of the high level programming languages we use, but do NOT be messing with this stuff, unless you know what you're doing, as you can f' up your computer!, lol:

http://www.plantation-productions.com/Webster/www.artofasm.com/DOS/pdf/0_AoAPDF.html

if you want to get more into the technical/advanced programming and computer stuff


I'm still undiceded how deep I wanna go. I discovered Quest only six months ago more or less still working on my first idea. For now I only try to get the stuff I'm imaging working. Every time when I got stuck I just look how could I get it work. Sometimes I dropped a element in my project because it efforts too much work and some of them were impleted back because I've learned more about Quest. I'll keep it goin' like this a bit longer.


I'm still undiceded how deep I wanna go. I discovered Quest only six months ago more or less still working on my first idea. For now I only try to get the stuff I'm imaging working. Every time when I got stuck I just look how could I get it work. Sometimes I dropped a element in my project because it efforts too much work and some of them were impleted back because I've learned more about Quest. I'll keep it goin' like this a bit longer.


for a simple demonstration of how data types matter:


String Data Types vs Integer Data Types:


4 + "HK" -> ERROR! both human and computer have no idea what the sum/addition is of the '4' number-amount-value (integer) and of the string 'HK', lol.

whereas:

"4" + "HK" -> (string) concatenation (literally putting together) -> "4HK"


addition:

5 + 5 = 10
55 + 55 = 110
"5" + 5 = ERROR!
"mama" + 5 = ERROR!

concatenation:

"5" + "5" = "55"
"55" + "55" = "5555"
"mama" + "mia" = "mamamia"
"mama" + "5" = "mama5"
"5" + 5 = ERROR!
"mama" + 5 = ERROR!


I moved new string list setup to the start script.

player_inventory.show_inv_stack = NewStringList()

At the beginning of the InventoryFunction the tempory item list will be cleared.

foreach (clitl, player_inventory.show_inv_stack) {
    list remove (player_inventory.show_inv_stack, clitl)

Then I decided to have a container which is following the player to keep the inventory clean.
To interact correctly with the inventory items I move them into a container the player is carrying. This way the items stay highlighted with the 'invetory verbs' listed.
Then I move them back to their container.

        foreach (ojt, GetDirectChildren (player_inv_items)) {
          MoveObject (ojt, player_inventory)
          SetTurnTimeout (2) {
            foreach (ojtb, GetDirectChildren (player_inventory)) {
              MoveObject (ojtb, player_inv_items)
            }

Now it feels like it's done, finally. I repeated this in a menu to cover all categories of items.

msg ("<br/><b>INVENTORY<b/><br/>")
ShowMenu ("", player_inventory.inventory_start, false) {
  foreach (clitl, player_inventory.show_inv_stack) {
    list remove (player_inventory.show_inv_stack, clitl)
  }
  switch (result) {
    case ("Items") {
      msg ("> Items<br/>")
      foreach (itm, GetDirectChildren (player_inv_items)) {
        get_inv_name = itm.name
        list add (player_inventory.show_inv_stack, "{object:" + get_inv_name + "} x " + itm.player_stack_attribute + "")
        msg ("" + (FormatList(player_inventory.show_inv_stack, "<br/>", "<br/>", "You have no items.")) + "")
        foreach (ojt, GetDirectChildren (player_inv_items)) {
          MoveObject (ojt, player_inventory)
          SetTurnTimeout (2) {
            foreach (ojtb, GetDirectChildren (player_inventory)) {
              MoveObject (ojtb, player_inv_items)
            }
          }
        }
      }
    }
    case ("Tools") {
      msg ("> Tools<br/>")
      foreach (itm, GetDirectChildren (player_inv_tools)) {
        get_inv_name = itm.name
        list add (player_inventory.show_inv_stack, "{object:" + get_inv_name + "} x " + itm.player_stack_attribute + "")
        msg ("" + (FormatList(player_inventory.show_inv_stack, "<br/>", "<br/>", "You have no tools.")) + "")
        foreach (ojt, GetDirectChildren (player_inv_tools)) {
          MoveObject (ojt, player_inventory)
          SetTurnTimeout (2) {
            foreach (ojtb, GetDirectChildren (player_inventory)) {
              MoveObject (ojtb, player_inv_tools)
            }
          }
        }
      }
    }
    case ("Armor and Clothes") {
      msg ("> Armor and Clothes<br/><br/>")
      foreach (itm, GetDirectChildren (player_inv_armor)) {
        get_inv_name = itm.name
        list add (player_inventory.show_inv_stack, "{object:" + get_inv_name + "} x " + itm.player_stack_attribute + "")
        msg ("" + (FormatList(player_inventory.show_inv_stack, "<br/>", "<br/>", "You have no armor or clothes.")) + "")
        foreach (ojt, GetDirectChildren (player_inv_armor)) {
          MoveObject (ojt, player_inventory)
          SetTurnTimeout (2) {
            foreach (ojtb, GetDirectChildren (player_inventory)) {
              MoveObject (ojtb, player_inv_armor)
            }
          }
        }
      }
    }
    case ("Important Items") {
      msg ("> Important Items<br/>")
      foreach (itm, GetDirectChildren (player_inv_iportant)) {
        get_inv_name = itm.name
        list add (player_inventory.show_inv_stack, "{object:" + get_inv_name + "} x " + itm.player_stack_attribute + "")
        msg ("" + (FormatList(player_inventory.show_inv_stack, "<br/>", "<br/>", "You have no important items.")) + "")
        foreach (ojt, GetDirectChildren (player_inv_important)) {
          MoveObject (ojt, player_inventory)
          SetTurnTimeout (2) {
            foreach (ojtb, GetDirectChildren (player_inventory)) {
              MoveObject (ojtb, player_inv_important)
            }
          }
        }
      }
    }
    case ("Close Inventory") {
      msg ("> Close Inventory<br/>")
    }
    case ("Weapons") {
      msg ("> Weapons<br/>")
      foreach (itm, GetDirectChildren (player_inv_weapons)) {
        get_inv_name = itm.name
        list add (player_inventory.show_inv_stack, "{object:" + get_inv_name + "} x " + itm.player_stack_attribute + "")
        msg ("" + (FormatList(player_inventory.show_inv_stack, "<br/>", "<br/>", "You have no weapons.")) + "")
        foreach (ojt, GetDirectChildren (player_inv_weapons)) {
          MoveObject (ojt, player_inventory)
          SetTurnTimeout (2) {
            foreach (ojtb, GetDirectChildren (player_inventory)) {
              MoveObject (ojtb, player_inv_weapons)
            }
          }
        }
      }
    }
  }
}

I forgot about dropping items. If a item is used up or dropped it shouldn't move back to the the inventory. I'll test putting a 'if' condition between. So, if the stack_attribute reaches 0 it won't be moved to the inventory and the item's drop or whatever script can move it correctly, theoretically.

foreach (ojtb, GetDirectChildren (player_inventory)) {
  if (ojtb.player_stack_attribute >= 0) {
    MoveObject (ojtb, player_inv_items)
  }
  else {
  }
}

Actually it says, if the stack_attribute is bigger as 0 it will be moved. Else, nothing.


Oh, another sleepless night with Quest...

So, everytime I remove a item from the inventory by wielding or dropping it, the next time I open the Inventory shows up a error. If try to open it again everything works fine again.
This is the error message. I have no idea.

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


K.V.

You have something scripted that is modifying the list through which a block of code is iterating.


This will throw the error of which you speak:

list = Split("one;two;three;four;five")
foreach (a, list) {
  if (StartsWith(a,"f")) {
    list remove (list, a)
  }
}

A workaround:

list = Split("one;two;three;four;five")
// Make a copy of the list by excluding nothing when setting the variable:
cloned_list = ListExclude (list, "")
// Iterate through the cloned list:
foreach (a, cloned_list) {
  if (StartsWith(a,"f")) {
    list remove (list, a)
  }
}

Not sure. I found the problem is this code at the beginning:

foreach (clitl, player_inventory.show_inv_stack) {
    list remove (player_inventory.show_inv_stack, clitl)

Is there any other way to clear a list? Or remove a list completely from game so the function can set a NewStringList() ?


re-creating the same list will clear/over-ride/over-write it:

example_stringlist_variable = NewStringList ()

DisplayList (example_stringlist_variable, true)
// (I'm not sure what happens when there's no items in the list, lol, as I've not tried/tested it yet, lol), though probably there won't be any display (as there's nothing to display), or otherwise, it'll give an error message for whatever the reason it can't handle an empty list

list add (example_stringlist_variable, "red")
list add (example_stringlist_variable, "blue")
list add (example_stringlist_variable, "yellow")

DisplayList (example_stringlist_variable, true)
// output:
// 1. red
// 2. blue
// 3. yellow

example_stringlist_variable = NewStringList ()

DisplayList (example_stringlist_variable, true)
// (I'm not sure what happens when there's no items in the list, lol, as I've not tried/tested it yet, lol), though probably there won't be any display (as there's nothing to display), or otherwise, it'll give an error message for whatever the reason it can't handle an empty list

list add (example_stringlist_variable, "orange")
list add (example_stringlist_variable, "green")
list add (example_stringlist_variable, "purple")

DisplayList (example_stringlist_variable, true)
// output:
// 1. orange
// 2. green
// 3. purple


Thx, looks like there was no need to add a 'list remove' after all. That's why I 'allways' should do a test run.

(I'm not sure what happens when there's no items in the list, lol, as I've not tried/tested it yet, lol), though probably there won't be any display (as there's nothing to display), or otherwise, it'll give an error message for whatever the reason it can't handle an empty list

I use FormatList. The last parameter will be printed if the list is empty.

msg ("" + (FormatList(list, "<br/>", "<br/>", "The list is empty.")) + "")

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

Support

Forums