Passing Lists

When passing a list as a parameter, I can't access the list's attribute from within the script.

I have a thing object. If I pass thing.displayverbs to my function, I want my function's script to know if it is dealing with a displayverbs list. Any idea how to accomplish this?

  <function name="ListAdd" parameters="list, value">
    if (not EndsWith(TypeOf(list),"list")) {
      error ("ListAdd: "+list+" is not a list!")
    }
    if (not ListContains(list,value)) {
      list add (list, value)
    }
  </function>

I wanted the function to be able to do this:
ListAdd (thing.displayverbs, "Shake")

...instead of having to do this:

thing.displayverbs = ListExclude(thing.displayverbs,"")
ListAdd (thing.displayverbs, "Shake")

ToString(list) doesn't work. It returns the list as a string (of course).

JS.console.log(list) doesn't work. It passes an array.

list.name doesn't work (throws an error, of course).

It's like I can't find out which attribute or variable is being passed here, but, if the list is not defined by an inherited type, this actually modifies an object's list attribute.

I want the script to tell me that I'm working with thing.displayverbs, if that's what I'm working with.


I'm a bit unclear on what you're asking for, but I'll try to help anyways, lol...

the 'TypeOf' should be working for checking what Attribute Type it is

if you want to check the name of the Attribute, you should be able to use 'GetAttribute' (as there's no specific 'GetList/GetDictionary'): http://docs.textadventures.co.uk/quest/functions/getattribute.html

create ("example_object")

example_object.example_object_attribute = example_object

example_object.example_name_of_object_string_attribute = example_object.name

example_object.example_name_of_attribute_string_attribute = "displayverbs"

example_object.example_value_attribute = "green"

example_object.example_stringlist_attribute = NewStringList ()
list add (example_object.example_stringlist_attribute, "red")
list add (example_object.example_stringlist_attribute, "blue")
list add (example_object.example_stringlist_attribute, "yellow")

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

example_function (example_object.example_object_attribute, example_object.example_name_of_object_string_attribute, example_object.example_name_of_attribute_string_attribute, example_object.example_stringlist_attribute, example_object.example_value_attribute)

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


<function name="example_function" parameters="example_object_parameter, example_name_of_object_string_parameter, example_name_of_attribute_string_parameter, example_attribute_parameter, example_value_parameter">

  // the 'name_of_object' String Parameter/input/value isn't used in the scripting below, but it can be needed for whatever scripting you might have that needs it, though you can always convert between an 'Object' VARIABLE and a 'name' 'String' VARIABLE via 'GetObject (STRING)' and 'GetString (OBJECT, "name") or OBJECT.name', within the scripting too, I just show the function having this distinction in its function call/definition/header/signature, instead of doing it as scripting within the Function)

  if (TypeOf (example_attribute_parameter) = "stringlist" or TypeOf (example_attribute_parameter) = "objectlist") {
    if (GetAttribute (example_object_parameter, example_name_of_attribute_string_parameter) = "displayverbs") {
      if (not ListContains (example_attribute_parameter, example_value_parameter)) {
        list add (example_attribute_parameter, example_value_parameter)
      } else {
        msg ("The list already contains the value, silly")
      }
    } else {
      msg ("The list is not a 'displayverbs' list, silly")
    }
  } else {
    msg ("The input is not a list (it's: not a Stringlist and not an Objectlist), silly")
  }
</function>

I want the script to tell me that I'm working with thing.displayverbs, if that's what I'm working with.

...or widget.inventoryverbs, or whatever. I want object.attribute.

TypeOf(list)just returns stringlist or whatever type of list it is.

I can access the type of list. I have the contents. I want to know the object and the attribute name so I can clone the list if it's an inherited attribute list. To do that, I need the object.attribute that was passed to the function. Doing list = ListExclude(list,"") declares list as a new variable, the value of which is a clone of the list passed in the variable. I don't want this. I want to know that it is a specific object's specific attribute, so I can modify it properly, cloning it first if it's inherited. This way, ListAdd will be less likely to throw an error.


edited my post, see if it works (or ask me if confused by it and need help/explanation of it), and let me know if it works or not.


A List/Dictionary Attribute itself is just storing a pointer (name_of_list/dictionary_attribute) to its address location as its own actual value, with the values/items for it, stored in contigious address locations from the List/Dictionary Attribute's address location in memory.

so, this (hopefully) is why the 'GetAttribute' works... lol... in checking if it's equal to "displayverbs"...


memory:

memory box A: stored data: address: 'name_of_object' String Data // Object 1


Object 1's stored data:

memory box A+1: stored data: address: 'name_of_string/dictionary_attribute' String Data // List/Dictionary Attribute 1
memory box A+2 to B: stored data: the list/dictionary items/values // items/values of List/Dictionary Attribute 1

memory box B+1: stored data: address: 'name_of_string/dictionary_attribute' String Data // List/Dictionary Attribute 2
memory box B+2 to C: stored data: the list/dictionary items/values // items/values of List/Dictionary Attribute 2


memory box C+1: stored data: address: stored data: 'name_of_object' String Data // Object 2


Object 2's stored data:

memory box C+1: stored data: address: 'name_of_string/dictionary_attribute' String Data // List/Dictionary Attribute 3
memory box C+2 to D: stored data: the list/dictionary items/values // items/values of List/Dictionary Attribute 3

memory box D+1: stored data: address: 'name_of_string/dictionary_attribute' String Data // // List/Dictionary Attribute 4
memory box D+2 to E: stored data: the list/dictionary items/values // items/values of List/Dictionary Attribute 4


memory box E: stored data: address: stored data: 'name_of_object' String Data // Object 3


This is my version of your example function:

<function name="ListAdd2" parameters="object,attribute,value">
  list = GetAttribute(object,attribute)
  if (not EndsWith(TypeOf (list),"list")) {
    error ("ListAdd2: "+list+" is not a list!")
  }
  if (EndsWith(attribute,"verbs")){
    set (object, attribute, ListExclude(list,""))
  }
  if (not ListContains(list,value)){
    list add (list, value)
  }  
</function>

It looks like it would work, but I want it to take the same parameters as list add. (Sorry. I should have mentioned that.)



does this work for you?


HK edit:

okay...

the 'list add' only uses 2 parameters, and your example uses 3 (assuming this example of mine does indeed work, which you've adjusted for your own use), and you want it to use only 2 parameters, correct?

this means you're taking/using the 'name_of_object.name_of_attribute', but the 'GetAttribute' requires it to get split into:

  1. an Object Value
  2. a String Value

I'm not sure if you can directly do this or not:

string_variable_1 = ToString (name_of_object.name_of_attribute)

and then hopefully be able to use the String Manipulation Functions on 'string_variable_1' to extract 'name_of_object' and 'name_of_attribute' from it, as is required by/for-using the 'GetAttribute':

object_variable = GetObject (name_of_object)

string_variable_2 = name_of_attribute

if (GetAttribute (object_variable, string_variable_2) = "displaylist")


you're basically trying to do the reverse of 'GetAttribute':

the 'GetAttribute' takes an Object Value and a 'name_of_attribute' String Value (2 values) and combines them into an Attribute Value: name_of_object.name_of_attribute (one value)

you want to use only 1 value (as one parameter, and the other parameter is the 'value' parameter, to match up with the 'list add', instead of having 3 parameters/values: object value, name of attribute string value, value)

so, you're trying to do the reverse of the 'GetAttribute', splitting the Attribute up, into its Object and its name of attribute String


list add (ATTRIBUTE: parameter/value 1+2, VALUE: parameter/value 3)

then in the scripting split ATTRIBUTE into 2 separate values:

OBJECT: parameter/value 1
STRING: 'name of attribute' parameter/value 2
and
VALUE: parameter/value 3

for the 'GetAttribute' to use:

GetAttribute (OBJECT, STRING) = "VALUE"


as opposed to using a Function with the 3 values/parameters


It doesn't do what I'm trying to do.

I want it to take the same, exact parameters as list add.

Quest knows the parameter I'm passing. I'm certain of that, because this changes the attribute's value:

  <function name="ListAdd" parameters="list, value">
    if (not EndsWith(TypeOf(list),"list")) {
      error ("ListAdd: "+list+" is not a list!")
    }
    if (not ListContains(list,value)) {
      list add (list, value)
    }
  </function>

If I do ListAdd(Stimpy.alt, "Ren"), the player will be able to refer to Stimpy as "Ren".

So, the script knows that it is dealing with Stimpy.alt. I want it to do something special when dealing with Stimpy.*verbs, but I can't get list to tell me anything about itself besides the contents of its list inside of my script.

I'm thinking this isn't possible without fooling around deep in the source code.


you're trying to do the reverse of the 'GetAttribute'

Sort of, but not really.

Quest knows what object and attribute I'm passing to the function. I just want it to tell me which one it is, rather than telling me its value.


Things I tried before creating this thread:

ToString(list) helps nothing. It turns the list into a string, just like msg(list) would.

Split(list, ".") throws an error, because it is dealing with a list, not a variable.

JS.console.log(list) sends an array to the console.

Log(list) throws an error because you can only pass strings to the log.

list.name is non-existent.


does the 'GetAttribute' work in checking/getting the name of the Attribute?

(look at my previous post, I just edited it, trying to explain that you're going to have to split your 'Attribute' parameter into its 2 parts: object and 'name of attribute' string, for you to then use the 'GetAttribute')

does your 3 parameter function adaptation of mine work? does it enable you to check the attribute (="alt", EndsWith ("verbs"), ="displayverbs", etc etc etc) ???

if it does... then it's now just a matter of how to (if it can be done, though this should be possible) convert the single parameter of an 'attribute' into its 2 parts, so you can use the GetAttribute, while thus keeping your function to only 2 parameters ( attribute (object+string), value), just like the 'list add' function, instead of using 3 parameters (object, string, value)


(filler for getting my edited post, updated/posted)


if the 'ToString' works... than you can use the String Manipulation Functions to extract the object and 'name of attribute' string from it, which then can be put into the GetAttribute, as the 'GetAttribute' can't directly take an Attribute (object+string)

http://docs.textadventures.co.uk/quest/functions/#string

for example...

example_object.example_stringlist_attribute = NewStringList ()
list add (example_object.example_stringlist_attribute, "red")
list add (example_object.example_stringlist_attribute, "blue")
list add (example_object.example_stringlist_attribute, "yellow")

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

I have extra parameters just to make the function more useful/dynamic for your use of it, so it otherwise, still keeps only the same 2 parameters of the 'list add', that you want

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

custom_list_manipulation_function (example_object.example_stringlist_attribute, "example_stringlist_attribute", "green", "add")

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

<function name="custom_list_manipulation_function" parameters="attribute_parameter, checking_value_parameter, manipulation_value_parameter, manipulation_operation_string_parameter">

  attribute_converted_into_a_string_variable = ToString (attribute_parameter) // does this work or not? if not... hopefully there's some other method/way... hmm... lol

  dot_location_list_count_integer_variable = Instr (attribute_converted_into_a_string_variable, ".")

  extracted_name_of_object_string = Mid (attribute_converted_into_a_string_variable, 1, dot_location_list_count_integer_variable - 2)

  extracted_name_of_attribute_string = Mid (attribute_converted_into_a_string_variable, dot_location_list_count_integer_variable + 1)

  object_variable = GetObject (extracted_name_of_object_string)

  if (GetAttribute (object_variable, extracted_name_of_attribute_string) = checking_value_parameter) {
    if (manipulation_operation_string_parameter = "add") {
      if (not ListContains (attribute_parameter, manipulation_value_parameter) {
        list add (attribute_parameter, manipulation_value_parameter)
      } else {
        msg ("ERROR/BLAH")
      }
    } else if (manipulation_operation_string_parameter = "remove") {
      if (ListContains (attribute_parameter, manipulation_value_parameter) {
        list remove (attribute_parameter, manipulation_value_parameter)
      } else {
        msg ("ERROR/BLAH")
      }
    } else {
      msg ("ERROR/BLAH")
    }
  } else {
    msg ("ERROR/BLAH")
  }

</function>

does the 'GetAttribute' work in checking/getting the name of the Attribute?

It would if I wanted the function to have an object parameter. I do not. I want it to have the same, exact parameters as list add.


does your 3 parameter function adaptation of mine work?

Totally, but that is not at all what I'm wanting to do.


if it does... then it's now just a matter of how to (if it can be done, though this should be possible) convert the single parameter of an 'attribute' into its 2 parts, so you can use the GetAttribute, while thus keeping your function to only 2 parameters ( attribute (object+string), value), just like the 'list add' function, instead of using 3 parameters (object, string, value)

Now you're with me.

Go back through this thread and read all the stuff that I've posted having tried.


if the 'ToString' works...

ToString(list) helps nothing. It turns the list into a string, just like msg(list) would. I want a function like TellMeWhatParameterWasPassedInsteadOfItsValue(list), which would return thing.inventoryverbs. Even if that returned a string, I could do this:

if (not ListContains(list, value)){
  arr = Split (TellMeWhatParameterWasPassedInsteadOfItsValue(list), ".")
  o = arr[0]
  o = GetObject(o)
  att = arr[1]
  set (o, att, list + value)
}

P.S.

you may be able to do this as well:

if (TypeOf (GetAttribute (object_variable, extracted_name_of_attribute_string)) = "stringlist") {
  if (GetAttribute (object_variable, extracted_name_of_attribute_string)) = checking_value_parameter) {

so, my edited code with it added to it:

example_object.example_stringlist_attribute = NewStringList ()
list add (example_object.example_stringlist_attribute, "red")
list add (example_object.example_stringlist_attribute, "blue")
list add (example_object.example_stringlist_attribute, "yellow")

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

I have extra parameters just to make the function more useful/dynamic for your use of it, so it otherwise, still keeps only the same 2 parameters of the 'list add', that you want

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

custom_list_manipulation_function (example_object.example_stringlist_attribute, "example_stringlist_attribute", "green", "add")

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

<function name="custom_list_manipulation_function" parameters="attribute_parameter, checking_value_parameter, manipulation_value_parameter, manipulation_operation_string_parameter">

  attribute_converted_into_a_string_variable = ToString (attribute_parameter) // does this work or not? if not... hopefully there's some other method/way... hmm... lol

  dot_location_list_count_integer_variable = Instr (attribute_converted_into_a_string_variable, ".")

  extracted_name_of_object_string = Mid (attribute_converted_into_a_string_variable, 1, dot_location_list_count_integer_variable - 2)

  extracted_name_of_attribute_string = Mid (attribute_converted_into_a_string_variable, dot_location_list_count_integer_variable + 1)

  object_variable = GetObject (extracted_name_of_object_string)

  if (TypeOf (GetAttribute (object_variable, extracted_name_of_attribute_string)) = "stringlist") {
    if (GetAttribute (object_variable, extracted_name_of_attribute_string) = checking_value_parameter) {
      if (manipulation_operation_string_parameter = "add") {
        if (not ListContains (attribute_parameter, manipulation_value_parameter) {
          list add (attribute_parameter, manipulation_value_parameter)
        } else {
          msg ("ERROR/BLAH")
        }
      } else if (manipulation_operation_string_parameter = "remove") {
        if (ListContains (attribute_parameter, manipulation_value_parameter) {
          list remove (attribute_parameter, manipulation_value_parameter)
        } else {
          msg ("ERROR/BLAH")
        }
      } else {
        msg ("ERROR/BLAH")
      }
    } else {
      msg ("ERROR/BLAH")
    }
  } else {
    msg ("ERROR/BLAH")
  }

</function>

hmm.. well, we can work with however it creates the String... might be a bit more (or maybe less) work with the String Manipulation Functions...

I think if you look at my previous 2 posts with the big chunk of codes, I think you can understand what I've done and understand the concept/code design that needs to be done... but if not, let me know and we'll work on it together (I'll help)


what is the String that is created/displayed, when you do the 'ToString (NAME_OF_OBJECT.NAME_OF_ATTRIBUTE)'

(too lazy to open up quest to test/see it myself, lol --- HK is always so lazy, likes theory crafting... then get burned cuz he was too lazy to just actually code/test it, lol)

is it something like this?:

Object: List: red, blue, yellow


my use of String Manipulation Functions, was based on it being able to direct convert the Attribute to a String:

ToString (NAME_OF_OBJECT.NAME_OF_ATTRIBUTE) ---> "NAME_OF_ATTRIBUTE.NAME_OF_STRING"

which I then first found the integer position of the 'dot' via the 'Instr' String Manipulation Function, and then I can use that in the 'Mid' String Manipulation Function to extract the String of the 'NAME_OF_OBJECT' and the String of the 'NAME_OF_ATTRIBUTE', which I can then convert the 'NAME_OF_OBJECT' String into an Object via 'GetObject (NAME_OF_OBJECT)', and then now that I got the 2 needed values, I can the OBJECT value with the 'NAME_OF_ATTRIBUTE' String Value within the 'GetAttribute' Function

but we can also work with whatever the String is, such as if it's like this:

Object: List: red, blue, yellow

though, it'll take more/less and/or different String Manipulation Function design/methods/ways to extr...


NVM!!!! WHOOPSY


ya... we do got an issue... with the 'ToString' as it doesn't work... just realized... we got an issue if it displays/returns/gets something like this 'Object: List: red, blue, yellow' --- lol, whoopsy...

hmm... hopefully something else can work to extract the 2 values we need... maybe .... 'Eval' Function? hmm... this might be not possible... I only just cuaght up to your thinkning KV.... sorry about being so stupid... sighs.


I do not want any extra parameters. Only the same, exact, two parameters as list add.

The function I posted after your first example works, but that third parameter is exactly what I'm trying to avoid.

I could make my function's first parameter have to be a string, like "thing.displayverbs", then break that down like I posted above, but, again, that would be changing the parameters, and I want it to take the same, exact, two parameters as list add.

The only reason I'm creating this function is to avoid pointless errors. When the list already contains the value, my function will just skip over adding the value, hence avoiding a pointless error during play. I also want it to check whether or not it is modifying an inherited list before doing anything, and that is where I run into the issue. Anything I try on list returns the list, and not thing.displayverbs or lamp.alt or whatever may have been passed as a parameter.

I want ListAdd to be identical to list add, only better. For ListAdd to be perfect, it would clone an inherited list before attempting to modify it. As far as I can tell, there is no way to check this. So, authors will still need to clone inherited attribute lists before using ListAdd or ListRemove. (Sorry, authors.)


Here is an example game, in which I include every way to try to see what list is which doesn't throw an error, none of which return the parameter I pass, which is thing.displayverbs. They all return the value of that attribute. BUT the function still modifies that attribute, so Quest definitely knows that it's dealing with thing.displayverbs within this script.

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="ListAdd">
    <gameid>850c8ad7-0432-4e1d-b550-dd066a8c9b94</gameid>
    <version>1.0</version>
    <firstpublished>2018</firstpublished>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <enter type="script">
      thing.displayverbs = ListExclude(thing.displayverbs,"")
      ListAdd (thing.displayverbs, "Shake")
    </enter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <object name="thing">
      <inherit name="editor_object" />
    </object>
  </object>
  <function name="ListAdd" parameters="list, value">
    if (not EndsWith(TypeOf(list),"list")) {
      error ("ListAdd: "+list+" is not a list!")
    }
    msg(list)
    msg(TypeOf(list))
    msg(ToString(list))
    JS.console.log(list)
    if (not ListContains(list,value)) {
      list add (list, value)
    }
  </function>
</asl>

hmm... how to convert an Attribute (extracting its 'name_of_object' and 'name_of_attribute') into a String... hmm....


probably going to need Pixie's expertise (or mrangel's), as I'm stumped, now that I've no idea how to convert an Attribute into a String (meaning the string contains/extracts its two values: name_of_object and name_of_attribute)


hmm....

you might just have to use an extra parameter(s) ... as there might be no way to do it that directly with only the Attribute (1/2 parameters that you want to have like 'list add') and the 'value' Parameter (the other 1/2 parameter)


well... there's a way around it... just thought of it... just now... lol

...simply use a List Attribute within your Function's scripting, which has all of the names of the Attributes of that Object (or of ALL Attributes within the entire game, lol) ...

as Attributes are global, they can trespass upon a Function with impunity lol...

but.. you still need a dynamic way of checking/determining/selecting what you want... which does require a parameter... as that is literally doing the selecting that is needed... hmm....


never mind... we can use another Attribute to store the selection... hehe... HK's brain is now thinking... outside of the box... lol


example_object.all_attributes_stringlist_attribute = NewStringList ()
list add (example_object.all_attributes_stringlist_attribute, "displayverbs")
list add (example_object.all_attributes_stringlist_attribute, "inventoryverbs")
list add (example_object.all_attributes_stringlist_attribute, "alt")
list add (example_object.all_attributes_stringlist_attribute, "take")
list add (example_object.all_attributes_stringlist_attribute, "drop")
list add (example_object.all_attributes_stringlist_attribute, "parent")

// ---------

msg ("selection?")
get input {
  if (ListContains (example_object.all_attributes_stringlist_attribute, result)) {
    // hmm... still am a bit stumped... argh...
  }
}

// --------

<function name="ListAdd" parameters="list_attribute_parameter, value_parameter">
<function>

actually... still am stumped... HK's brain while working... was working wrongly... lol

I'm just creating two functions (one function to handle all the stuff you don't want to change of the other 'ListAdd' function)... lol.... which isn't really what you want... hmm....


not want you want...

but by in the same wrong vein as above... you can use the 'foreach' for both your passed in 'list attribute' Parameter and an outside selected list attribute, and then within the Function you can 'foreach' check if they got the same items... as a way around possibly not being able to extract/convert your list attribute parameter into its two values of 'object' and 'name_of_attribute'... not really what you want though... lol...


it's disappointing that this doesn't work, sighs

string_variable = example_object.example_stringlist_attribute.name


maybe the...

'GetUniqueElementName'

will work?


you can use the 'foreach' for both your passed in 'list attribute' Parameter and an outside selected list attribute, and then within the Function you can 'foreach' check if they got the same items

Hehehe.

That might change the display verbs of every object with "Look at;Take"!

...and I tried GetUniqueElementName just for the heck of it, and that only accepts a string for the parameter, and it's doing something totally different than what we want.


Quest knows the parameter I'm passing. I'm certain of that, because this changes the attribute's value:

No, it doesn't.
Lists are passed by reference.

Imagine that every list variable is actually a signpost, giving you directions to a place in memory where the actual list of items starts. You can have multiple signs pointing to the same list, and they can have different names. As long as you follow one of them and change what it points to, then someone following any of the others will see your changes. But the list doesn't know what names are printed on the signs, and it doesn't know where the signs are.

BUT… the equality operator compares two signposts to see if they point to the same place…
You could loop over AllObjects, and then loop over ListExclude(GetAttributeNames(obj, true), GetAttributeNames(obj, false)) to find all their inherited attributes, and see if any of them are equal to the list you're looking at. I wrote the function to do this, then realised it probably won't help you.

"Find any objects who have an attribute that's a signpost pointing to this location, and change all of them". But I think you probably only want to change one; and this will change every instance of the type. Because they all point to the same actual list.

On the plus side, we now have a way to change a list attribute for all objects that inherit the same type :p

<function name="ListAdd" parameters="list,value">
  if (not EndsWith(TypeOf(list), "list")) {
    error ("Not a list!")
  }
  original_list = list
  foreach (obj, AllObjects()) {
    foreach (attribute, ListExclude(GetAttributeNames(obj, true), GetAttributeNames(obj, false))) {
      if (Equal(GetAttribute(obj, attribute), original_list)) {
        if (original_list = list) {
          list = ListExclude(list, "")
        }
        set (object, attribute, list)
      }
    }
  }
  list add (list, value)
</function>

personally... unless Pixie or mrangel (or you figure something out, lol), I'd just go with using/creating a Function with the extra parameters, as trying to keep just having an 'attribute' (and the 'value') parameter... is becoming too much of a nightmare due to seemingly having no way of converting an attribute into a string of its two (or three) string values of a 'name of object' and 'name of attribute (and the 'dot' string value)


and also...

I'm pretty sure that using extra parameters is more efficient code wise than whatever scripting that might be possible, and it's easier for us than trying to come up with some really fancy (and hopefully concise/short/"simple") scripting...

easier to pass extra needed data than trying to convert the limited data into what you need...


hmm...

so there's no way of getting the 'name' data used as the pointer to the address... that sucks...

create ("katana") // katana.name = "katana"

katana.damage = 50

player.weapon = katana

player.weapon.name // works ( = "katana") // object.pointer.value_(its 'name' string value)_of_the_data_at_the_pointer's_memory_location

player.weapon.damage // works // object.pointer.value_(its 'damage' integer value)_of_the_data_at_the_pointer's_memory_location

but there's no way to extract/get this, I guess, sighs:

player.weapon.name = "weapon"
or
weapon.name = "weapon"

I thought that the 'name of object' and 'name of attribute' would be stored as data... that you could access... like everything else... but I guess not...

when you create an Attribute, it doesn't store its 'name of object' and 'attribute name' (or its 'name_of_object.name_of_attribute') as part of its data (as 'string' data) ??? ....that sucks...

An Attribute should create and store a pointer to its current 'name of object' and its 'name of attribute' (or a pointer to a 'name_of_object.name_of_attribute' string data being stored)...


@ mrangel:

is there also no way of being able to convert an Attribute Value (NAME_OF_OBJECT.NAME_OF_ATTRIBUTE) into a String Value ("NAME_OF_OBJECT.NAME_OF_ATTRIBUTE"), or to "extract/determine" its two parts (NAME_OF_OBJECT and NAME_OF_ATTRIBUTE), at all, ???


Better metaphor:

Imagine your variables are pieces of paper. An integer is a piece of paper with a number on. A string is a piece of paper with words on.
A list is a piece of paper with a treasure map on, telling you where to find a pile of paper.

When you call a function, you're giving it a photocopy of some variables, and telling it to do something with them. In the case of a string, you have no way of seeing what the function has done with that photocopy unless it returns it to you.

With a list, if the function modifies it, you can tell. Because you and the function now have copies of the same map, so if the function puts a new item on top of the pile, you can follow the map yourself and see it.

In the case of inherited attributes, the stack of papers is inside some kind of display case. You can look at it, but not modify it. So you use ListExclude to make a copy of the whole list, and give the object a new map, pointing to your new list.

So your function here, you're giving the function a copy of a map, and a copy of some value. And you're telling it "Go put this value on the pile of papers indicated by this map. If the pile is locked, copy it and change my map."
It can't do that, because it only has a copy of the map. Now, in the function I posted, it can search the whole world looking for maps identical to the one it's holding. I think that's not what you want; but it's the best you can do. Because the list doesn't tell you whose map you used to get to it.

Another example:

list = NewStringList()
john.alt = list
bob.alt = list
dave.alt = list
ListAdd(list, "That guy")

You said you want to get the object that the list belongs to. Which one? There are five maps pointing to the same list. John, Dave, and Bob all have a copy of the map. The variable "list" itself if a copy of the map. And the variable within the ListAdd function is another copy.


I was trying to avoid iterating through everything. I thought it would add that to every list which had the same values.


set throws the same inherited attribute error as list add!

So, that does single out which object and attribute the script is dealing with (which was what I was trying to do), but it doesn't help my cause (because I thought set would work, and it doesn't).

set does not throw an error when dealing with an inherited list, that code simply isn't firing.

If I put set (thing, "displayverbs", Split("Look at;Take:Shake")), it works with no errors without cloning the list first.


The variable "list" itself if a copy

That's how I always think of it, but these work:

list add (list, "new thing")

list remove(list, "old thing")

So, Quest knows what list is "tied to".


Note that doing this "unties" the list variable, and it will no longer effect thing.displayverbs:

list = ListExclude(list,"")

Doing anything that begins list = redeclares the variable.

The only ways to modify it that I can find are list add or list remove, and these will modify an inherited list.

So, the author will just have to make sure he or she clones an inherited list before using ListAdd (if they use my function). Besides, that, it will not throw an error if the value already exists on the list.


That works for me.

I just tried it in my test game; AddList(exit17.alt, "downwind"). Adds an alias to all exits that inherit southwestdirection.
(because objects that inherit a type all have maps directing them to the same actual list, and those maps are identical. So there's no possible way to tell whose map a copy was taken from to pass to the function)

Edit: The function posted above has a typo, I have object instead of obj in the set function.


I fixed that typo and still got the error when trying to add a display verb.


Here's my workaround (which only covers display and inventory verbs):

REMOVED. CODE DID NOT WORK.


So, Quest knows what list is "tied to".

No, it doesn't.

If I give you a copy of my treasure map, then you can go and bury something and I can go and dig it up.

That does not mean that your map knows it's tied to my map. Both maps know about the same treasure chest, but the chest doesn't need to know about the maps.


Something somewhere has to be keeping track, because this changes it:

  <function name="ListAdd" parameters="list, value">
    if (not EndsWith(TypeOf(list),"list")) {
      error ("ListAdd: "+list+" is not a list!")
    }
    if (not ListContains(list,value)) {
      list add (list, value)
    }
  </function>

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="ListAdd">
    <gameid>850c8ad7-0432-4e1d-b550-dd066a8c9b94</gameid>
    <version>1.0</version>
    <firstpublished>2018</firstpublished>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <beforeenter type="script">
      thing.displayverbs = ListExclude(thing.displayverbs, "")
      ListAdd (thing.displayverbs, "Shake")
    </beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <object name="thing">
      <inherit name="editor_object" />
    </object>
  </object>
  <function name="ListAdd" parameters="list, value">
    if (not EndsWith(TypeOf(list),"list")) {
      error ("ListAdd: "+list+" is not a list!")
    }
    if (not ListContains(list,value)) {
      list add (list, value)
    }
  </function>
  <function name="ListRemove" parameters="list, value">
    if (ListContains(list,value)) {
      list remove (list, value)
    }
  </function>
</asl>

This does nothing:

<function name="ListAdd" parameters="list,value">
  if (not EndsWith(TypeOf(list), "list")) {
    error ("Not a list!")
  }
  original_list = list
  foreach (obj, AllObjects()) {
    foreach (attribute, ListExclude(GetAttributeNames(obj, true), GetAttributeNames(obj, false))) {
      if (Equal(GetAttribute(obj, attribute), original_list)) {
        if (original_list = list) {
          list = ListExclude(list, "")
        }
        set (obj, attribute, list)
      }
    }
  }
  list add (list, value)
</function>

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="ListAdd">
    <gameid>850c8ad7-0432-4e1d-b550-dd066a8c9b94</gameid>
    <version>1.0</version>
    <firstpublished>2018</firstpublished>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <enter type="script">
    </enter>
    <beforeenter type="script">
      ListAdd (thing.displayverbs, "Shake")
    </beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <object name="thing">
      <inherit name="editor_object" />
    </object>
  </object>
<function name="ListAdd" parameters="list,value">
  if (not EndsWith(TypeOf(list), "list")) {
    error ("Not a list!")
  }
  original_list = list
  foreach (obj, AllObjects()) {
    foreach (attribute, ListExclude(GetAttributeNames(obj, true), GetAttributeNames(obj, false))) {
      if (Equal(GetAttribute(obj, attribute), original_list)) {
        if (original_list = list) {
          list = ListExclude(list, "")
        }
        set (obj, attribute, list)
      }
    }
  }
  list add (list, value)
</function>
</asl>

Adding debugging messages:

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="ListAdd">
    <gameid>850c8ad7-0432-4e1d-b550-dd066a8c9b94</gameid>
    <version>1.0</version>
    <firstpublished>2018</firstpublished>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <enter type="script">
    </enter>
    <beforeenter type="script">
      ListAdd (thing.displayverbs, "Shake")
    </beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <object name="thing">
      <inherit name="editor_object" />
    </object>
  </object>      
<function name="ListAdd" parameters="list,value">
  if (not EndsWith(TypeOf(list), "list")) {
    error ("Not a list!")
  }
  original_list = list
  foreach (obj, AllObjects()) {
    foreach (attribute, ListExclude(GetAttributeNames(obj, true), GetAttributeNames(obj, false))) {
      if (Equal(GetAttribute(obj, attribute), original_list)) {
        msg(obj)
        msg(attribute)
        msg(GetAttribute(obj, attribute))
        if (original_list = list) {
          list = ListExclude(list, "")
        }
        set (obj, attribute, list)
      }
    }
  }
  list add (list, value)
</function>
</asl>

image


What am I doing differently, mrangel?

..and why would original_list not equal list?


if you want, consolidating them (but this means having extra parameter/s, though it's only one Function compared to multiple Functions):

(we could expand/consolidate this further, by: including in whether you want to sort it or not, and what type of sorting to do, including dictionary handling, and etc etc etc stuff that one can think of, lol)

// for example:

ListModify (orc.displayverbs, "fight", "add", "displayverbs") // adding 'fight'

// then (just for continued example):

ListModify (orc.displayverbs, "fight", "remove", "displayverbs") // removing 'fight'

// ----

<function name="ListModify" parameters="list, value, operation_string, check_string">
  // you might need this to happen repeatedly... not sure if first time will cause you issues or not, wouldn't you need to re-copy the lists every time they get modified?
  firsttime {
    CloneAllVerbsLists (check_string)
  }
  if (not EndsWith (TypeOf (list), "list")) {
    error ("ListAdd: " + list + " is not a list!")
  } else {
    if (operation_string = "add") {
      if (not ListContains (list, value))
        list add (list, value)
      } else {
        msg ("ERROR/BLAH")
      }
    } else if (operation_string = "remove") {
      if (ListContains (list, value))
        list remove (list, value)
      } else {
        msg ("ERROR/BLAH")
      }
    }
    // optional more operations like:
    else if (operation_string = "replace") {
      // scripting using the 'replace' Function (too lazy to look it up, lol)
    }
    // optional whatever other more operations
    else {
      msg ("ERROR/BLAH")
    }
  }
</function>

<function name="CloneAllVerbsLists" parameters="check_string">
  foreach (o, AllObjects ()) {
    if (HasAttribute (o, check_string)) {
      o.check_string = o.check_string)
    }
  }
</function>

OK, I need to poke this more.

I've used lists as parameters for doing some weird stuff, and they act just like referenced lists in other languages.
Lists as attributes, maybe there's some very strange behaviour here.

I'll look at this some time when I can avoid panic.


Ah ... it looks like set implicitly copies the list?
That's really awkward, but I can kind of see why you'd do that.

I want to keep on testing this, but I've got housemates pulling at me to do things that aren't the 8 hours of work I need to do to get back on target today. And I'm just getting "Your session has timed out"

Am I right in thinking that after I do object.attribute = somelist, I can then do msg (object.attribute = somelist) and get "false"?


Sorry, mrangel.

I was just making sure someone didn't say I could put parameters{0} or something crazy like that. I didn't mean to make you go crazy right along with me.

If list add and list remove didn't work, I could declare this mystery solved, but I'll just have to go with thinking this is happening in a script to which I have no access without changing some serious source code.


I understand it now. It's a horrible, horrible bodge though.

Test 1

somelist = Split("a;b;c")
someobject.attribute = somelist
msg (someobject.attribute = somelist)

displays false - the attribute and the local variable point to two different copies of the same list. Modifying either of them will not affect the other.

Test 2

someobject.attribute = Split("a;b;c")
somelist = someobject.attribute
msg (someobject.attribute = somelist)

displays true - the attribute and the local variable are two variables pointing to the same list. Calling list add or list remove on either of them will affect the other, because they're just signs pointing to the same actual list.
(Note that two variables still don't know about each other. The list doesn't know how many variables point to it; and may continue taking up space in memory for a while after the last one has been deleted)

So assigning something to an attribute, or calling set, implicitly copies the list.


Ah!

The plot thickens.

  <function name="ListAdd" parameters="list, value">
    if (not EndsWith(TypeOf(list),"list")) {
      error ("ListAdd: "+list+" is not a list!")
    }
    matched = false
    foreach (obj, AllObjects()) {
      foreach (attribute, GetAttributeNames(obj, true)) {
        if (Equal(GetAttribute(obj, attribute), list)) {
          matched = true
          msg (obj)
          msg (attribute)
          msg (GetAttribute(obj, attribute))
          clone = ListExclude(list,"")
          set (obj, attribute, Split("NEW;VERBS",";"))
        }
      }
    }
    if (matched){
      if (not ListContains(list,value)) {
        list add (list, value)
      }
    }
  </function>

This will change all matching verbs lists, but still throw the error.

Your last post taught me why.

list is still pointing to a copy of an inherited list! (Ha! I love understanding stuff, even when I learn I can't do what I was attempting to do.)

image


Something knows that list is pointing to thing.displayverbs in my script in the first post.

My mission was to make Quest tell me what list pointed to. I failed.


The reason some code I posted (and removed because it didn't work) last night didn't work was because I was running CloneAllVerbsLists from the ListAdd function. The last example I posted shows why that didn't work.

So, if I am authoring a game in which I decide to modify even one object's verbs list, I shall be adding this to the start script of the game to cover the inherited attribute error for any display or inventory verbs lists:

  <function name="CloneAllVerbsLists">
    foreach (o, AllObjects()) {
      if (HasAttribute(o,"displayverbs")) {
        o.displayverbs = ListExclude(o.displayverbs,"")
      }
    }
    foreach (o, AllObjects()) {
      if (HasAttribute(o,"inventoryverbs")) {
        o.inventoryverbs = ListExclude(o.inventoryverbs,"")
      }
    }
  </function>

Now, these functions will work fine (unless I try to modify some other inherited list):

  <function name="ListAdd" parameters="list, value">
    if (not EndsWith(TypeOf(list),"list")) {
      error ("ListAdd: "+list+" is not a list!")
    }
    if (not ListContains(list,value)) {
      list add (list, value)
    }
  </function>
  <function name="ListRemove" parameters="list, value">
    if (ListContains(list,value)) {
      list remove (list, value)
    }
  </function>

Example game:

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="ListAdd">
    <gameid>850c8ad7-0432-4e1d-b550-dd066a8c9b94</gameid>
    <version>1.0</version>
    <firstpublished>2018</firstpublished>
    <start type="script">
      CloneAllVerbsLists
    </start>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <beforeenter type="script">
      ListAdd (thing.displayverbs, "Shake")
    </beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <object name="thing">
      <inherit name="editor_object" />
    </object>
  </object>
  <function name="ListAdd" parameters="list, value">
    if (not EndsWith(TypeOf(list),"list")) {
      error ("ListAdd: "+list+" is not a list!")
    }
    if (not ListContains(list,value)) {
      list add (list, value)
    }
  </function>
  <function name="ListRemove" parameters="list, value">
    if (ListContains(list,value)) {
      list remove (list, value)
    }
  </function>
  <function name="CloneAllVerbsLists">
    foreach (o, AllObjects()) {
      if (HasAttribute(o,"displayverbs")) {
        o.displayverbs = ListExclude(o.displayverbs,"")
      }
    }
    foreach (o, AllObjects()) {
      if (HasAttribute(o,"inventoryverbs")) {
        o.inventoryverbs = ListExclude(o.inventoryverbs,"")
      }
    }
  </function>
</asl>

Thanks, mrangel!


Log in to post a reply.

Support

Forums