Script Dictionary - As Attribute

Good day everyone,
KV has been invaluable over these last few months in helping me accomplish several goals, but knowing how busy KV has been outside of Quest, I wanted to open this up for the rest of you folks. Would anyone mind running through using a script dictionary? Every time I use one, the only result I see is (script). I have tried assigning a variable at the start and even adding a return, but no matter what the result displayed is (script).

What am I doing?
I have a list of attributes that randomly get assigned a value greater than 0, turning that attribute "On" as it were. The value the attribute is assigned is what I'm trying to get.

So I have an item with a String Dictionary attribute that contains my list. The attributes are being assigned and "turned on", but I want to display the value of the attribute.

Working part:
Item: staff1 - attribute string dictionary list (with only each attribute & value).
Call to the function that adds the random attributes to the items, up to 5.
That function calls another function that iterates through the attributes assigned with a value greater than 0 and adds them to a list. Finally, the last attribute field is populated with the string values of ALL the attributes, but only ones greater than 0 are actually added.

My problem:
I can get the name of an attribute to display, because I set a string value, but I cannot get the numeric value to display. For example, if an attribute is AttackChance, the string value is

"Attack Chance: "+AttackChance+""

That should display something like - Attack Chance: 5
Instead, all I can get is - Attack Chance: +AttackChance+

I need to get the value assigned to AttackChance to display the full string, with the numeric value and not just the text.

(object)mag_props.alphabetdict attribute: string dictionary
(object)alphabetdict.alphabetdict attribute: string dictionary (attribute names have a 2 added, so AttackChance = AttackChance2 and each entry looks like this - (AttackChance <--key) ("Attack Chance: " + obj.AttackChance + "
" <---string)

object.m_props: string
object.m_props2: script dictionary (in order to combine the string and int values into one value)
AttackChance2 + BonusDex2 + BonusHits2 + etc + etc
object.attribute: Integer

Function to assign up to 5 attributes:

<function name="Magical_Props" parameters="object"><![CDATA[
    obj = object
    if (GetInt(obj, "rarity") > 91) {
      magical = NewStringDictionary()
      obj = object
      keys = NewStringList()
      dict = mag_props.alphabetdict
      foreach (key, dict) {
        list add (keys, key)
      }
      list = PickFiveStrings(keys)
      foreach (key, list) {
        val = DictionaryItem (dict, key)
        set (obj, key, val)
        // for debugging
        msg (obj.name + "." + key + " = " + val)
        // for debugging
        msg (GetAttribute(obj, key))
        dictionary add (magical, key + "2", val)
      }
      set (obj, "m_props2", magical)
      Properties_List1 (obj)
    }
    else if (GetInt(obj, "rarity") > 71) {
      magical = NewStringDictionary()
      obj = object
      keys = NewStringList()
      dict = mag_props.alphabetdict
      foreach (key, dict) {
        list add (keys, key)
      }
      list = PickFourStrings(keys)
      foreach (key, list) {
        val = DictionaryItem (dict, key)
        set (obj, key, val)
        // for debugging
        msg (obj.name + "." + key + " = " + val)
        // for debugging
        msg (GetAttribute(obj, key))
        dictionary add (magical, key + "2", val)
      }
      set (obj, "m_props2", magical)
      Properties_List1 (obj)
    }
    else if (GetInt(obj, "rarity") > 51) {
      magical = NewStringDictionary()
      obj = object
      keys = NewStringList()
      dict = mag_props.alphabetdict
      foreach (key, dict) {
        list add (keys, key)
      }
      list = PickThreeStrings(keys)
      foreach (key, list) {
        val = DictionaryItem (dict, key)
        set (obj, key, val)
        // for debugging
        msg (obj.name + "." + key + " = " + val)
        // for debugging
        msg (GetAttribute(obj, key))
        dictionary add (magical, key + "2", val)
      }
      set (obj, "m_props2", magical)
      Properties_List1 (obj)
    }
    else if (GetInt(obj, "rarity") > 31) {
      magical = NewStringDictionary()
      obj = object
      keys = NewStringList()
      dict = mag_props.alphabetdict
      foreach (key, dict) {
        list add (keys, key)
      }
      list = PickTwoStrings(keys)
      foreach (key, list) {
        val = DictionaryItem (dict, key)
        set (obj, key, val)
        // for debugging
        msg (obj.name + "." + key + " = " + val)
        // for debugging
        msg (GetAttribute(obj, key))
        dictionary add (magical, key + "2", val)
      }
      set (obj, "m_props2", magical)
      Properties_List1 (obj)
    }
    else if (GetInt(obj, "rarity") > 11) {
      magical = NewStringDictionary()
      obj = object
      keys = NewStringList()
      dict = mag_props.alphabetdict
      foreach (key, dict) {
        list add (keys, key)
      }
      list = PickOneStrings(keys)
      foreach (key, list) {
        val = DictionaryItem (dict, key)
        set (obj, key, val)
        // for debugging
        msg (obj.name + "." + key + " = " + val)
        // for debugging
        msg (GetAttribute(obj, key))
        dictionary add (magical, key + "2", val)
      }
      set (obj, "m_props2", magical)
      Properties_List1 (obj)
    }
    msg ("Magical properties added on " + obj.name + "")
  ]]></function>

Function to stuff attributes into a list:

<function name="Properties_List1" parameters="obj" type="list">
    list = obj.m_props2
    magical2 = NewStringList()
    dict = alphabetdict.alphabetdict
    foreach (key, dict) {
      list add (magical2, key)
    }
    foreach (key, list) {
      val = DictionaryItem (dict, key)
      set (obj, key, val)
      // for debugging
      msg (obj.name + "." + key + " = " + val)
      // for debugging
      msg (GetAttribute(obj, key))
    }
    set (obj, "m_props", (obj.AttackChance2 + obj.BonusDex2 + obj.BonusHits2 + obj.BonusInt2 + obj.BonusMana2 + obj.BonusStam2 + obj.BonusStr2 + obj.Chaos2 + obj.Cold2 + obj.DefendChance2 + obj.Direct2 + obj.Energy2 + obj.Fire2 + obj.LowerManaCost2 + obj.Luck2 + obj.NightSight2 + obj.Physical2 + obj.Poison2 + obj.ReflectPhysical2 + obj.RegenHits2 + obj.RegenMana2 + obj.RegenStam2 + obj.ResistColdBonus2 + obj.ResistEnergyBonus2 + obj.ResistFireBonus2 + obj.ResistPhysicalBonus2 + obj.ResistPoisonBonus2 + obj.SpellChanneling2 + obj.SpellDamage2 + obj.WeaponDamage2 + obj.HitColdArea2 + obj.HitDispel2 + obj.HitEnergyArea2 + obj.HitFireArea2 + obj.HitFireball2 + obj.HitHarm2 + obj.HitLeechHits2 + obj.HitLeechMana2 + obj.HitLeechStam2 + obj.HitLightning2 + obj.HitLowerAttack2 + obj.HitLowerDefend2 + obj.HitMagicArrow2 + obj.HitPhysicalArea2 + obj.MageWeapon2))
  </function>

Thanks,

  • Raist

OK, I can't understand a word of your explanation.
The code, I can follow what it's doing. It's inefficient, but it looks like it should work. It's very confusing to read, because you have things like a dictionary named list (when a list and a dictionary are very different things).

It picks between 1 and 5 keys from the dictionary mag_props.alphabetdict.

For example, if mag_props.alphabetdict had a key "NightSight" and value "someValue", then this function could give obj:

  • An attribute obj.NightSight with the value "someValue"
  • An attribute obj.m_props2 which is a dictionary containing the key "NightSight2" and value "someValue"
  • An attribute obj.NightSight2 whose value is determined by looking for the value corresponding to the key "NightSight2" in the dictionary alphabetdict.alphabetdict
  • An attribute obj.m_props which is a huge string containing a whole load of attribute values

Is that what you want?
What do you want it to do?

Maybe if you give an example of a key and value from each of the dictionaries mag_props.alphabetdict and alphabetdict.alphabetdict, I'd have a better idea how this is supposed to work?


Thanks for the reply mrangel,
Yep, that's what it IS doing. The only thing that is NOT happening is the actual integer value assigned to obj.NightSight is not being carried over into the String when it is displayed.

The end result should look like this -
Attribute: Int

The code is roughly -
"NightSight: " +obj.NightSight+"
"

That is the value of NightSight2, so when ALL of the attributes greater than 0 are added to that huge string (obj.m_props), it is adding that NightSight2 value of "NightSight: " +obj.NightSight+"
" (and then each attribute value for AttackChance2, BonusDex2, etc, etc). When you LOOK at the item in the game you see:

Bow
Damage: 6
Type: Ranged
Attack Chance: 15
Bonus Dexterity: 3

Attack Chance and Bonus Dexterity are the "2" values (AttackChance2, BonusDex2, etc). I cannot get the INT from inside a "2" value to actually display the INT, instead it displays something like Attack Chance: +obj.AttackChance+.

KV suggested changing obj.m_props2 to a Script Dictionary, but when I do that the result displayed is Attack Chance: (script). I added the creation of the lists inside the functions to more easily reference the attributes being changed.

This is all happening during initialise for an object, but all of the values exist and are in place when I look in the Debugger (except that INT will not show up instead of +obj.AttackChance+).

mag_props.alphabetdict example:

<item>
  <key>AttackChance</key>
  <value type="string">1</value>
</item>

alphabetdict.alphabetdict example:

<item>
  <key>AttackChance2</key>
  <value type="string">"Attack Chance: " + obj.AttackChance + "<br>"</value>
</item>

Thanks,

  • Raist

If you change your PickFiveStrings etc. to one PickSomeStrings it will be much easier.

  <function name="PickSomeStrings" parameters="list, n" type="stringlist"><![CDATA[
    if (n > ListCount(list)) {
      error ("Trying to get " + n + " items from a list of only " + ListCount(list))
    }
    result = NewStringList()
    for (i, 1, n) {
      s = PickOneString(list)
      while (s in result) {
        s = PickOneString(list)
      }
      list add (result, s)
    }
    return (result)
  ]]></function>

Your first function should then be just this:

<function name="Magical_Props" parameters="obj"><![CDATA[
  obj.m_props2 = NewStringDictionary()
  keys = NewStringList()
  foreach (key, mag_props.alphabetdict) {
    list add (keys, key)
  }
  list = PickSomeStrings(keys, (obj.rarity - 1) / 20 + 1)
  foreach (key, list) {
    val = DictionaryItem (mag_props.alphabetdict, key)
    set (obj, key, val)
    // for debugging
    msg (obj.name + "." + key + " = " + val)
    // for debugging
    msg (GetAttribute(obj, key))
    dictionary add (obj.m_props2, key + "2", val)
  }
  Properties_List1 (obj)
]]></function>

What that will do is add one to five attributes to the given object, chosen randomly from mag_props.alphabetdict.

For the second, try this:

<function name="Properties_List1" parameters="obj" type="list">
    foreach (key, obj.m_props2) {
      val = DictionaryItem (alphabetdict.alphabetdict, key)
      set (obj, key, val)
      // for debugging
      msg (obj.name + "." + key + " = " + val)
      // for debugging
      msg (GetAttribute(obj, key))
    }
  </function>  

The last line I have just deleted. It looks to set the "m_props" to the total of all the attributes (an int or a string), and I suspect that is wrong.

You talk about script dictionaries in the OP, and it is not clear where they are. Are the properties scripts? There is some background here that we are not seeing.


Thanks for the reply Pixie,
The attribute obj.m_props2 is the Script Dictionary. KV believed/believes that is the only way to combine a String and an Int into one value. I just can't seem to get it to work so that it actually displays the String/Int combination properly.

(NOTE: Setting m_props2 to a Script Dictionary gives the result of (script), see this code below)

<m_props2 type="scriptdictionary">
	<item key="AttackChance2"><![CDATA[
          obj = this
          set (obj, "AttackChance2", Attack Chance: " + obj.AttackChance + "<br>)
        ]]></item>
	<item key="BonusDex2"><![CDATA[
          obj = this
          set (obj, "BonusDex2", Bonus Dexterity: " + obj.BonusDex + "<br>)
        ]]></item>
	<item key="BonusHits2"><![CDATA[
          obj = this
          set (obj, "BonusHits2", Bonus Hit Points: " + obj.BonusHits + "<br>)
        ]]></item>
	<item key="BonusInt2"><![CDATA[
          obj = this
          set (obj, "BonusInt2", Bonus Intelligence: " + obj.BonusInt + "<br>)
        ]]></item>
	<item key="BonusMana2"><![CDATA[
          obj = this
          set (obj, "BonusMana2", Bonus Mana: " + obj.BonusMana + "<br>)
        ]]></item>
	<item key="BonusStam2"><![CDATA[
          obj = this
          set (obj, "BonusStam2", Bonus Stamina: " + obj.BonusStam + "<br>)
        ]]></item>
	<item key="BonusStr2"><![CDATA[
          obj = this
          set (obj, "BonusStr2", BOnus Strength: " + obj.BonusStr + "<br>)
        ]]></item>
	<item key="Chaos2"><![CDATA[
          obj = this
          set (obj, "Chaos2", Chaos: " + obj.Chaos + "<br>)
        ]]></item>
	<item key="Cold2"><![CDATA[
          obj = this
          set (obj, "Cold2", Cold: " + obj.Cold + "<br>)
        ]]></item>
	<item key="DefendChance2"><![CDATA[
          obj = this
          set (obj, "DefendChance2", Defense Chance: " + obj.DefendChance + "<br>)
        ]]></item>
	<item key="Direct2"><![CDATA[
          obj = this
          set (obj, "Direct2", Direct: " + obj.Direct + "<br>)
        ]]></item>
	<item key="Energy2"><![CDATA[
          obj = this
          set (obj, "Energy2", Energy: " + obj.Energy + "<br>)
        ]]></item>
	<item key="Fire2"><![CDATA[
          obj = this
          set (obj, "Fire2", Fire: " + obj.Fire + "<br>)
        ]]></item>
	<item key="LowerManaCost2"><![CDATA[
          obj = this
          set (obj, "LowerManaCost2", Lower Mana Cost: " + obj.LowerManaCost + "<br>)
        ]]></item>
	<item key="Luck2"><![CDATA[
          obj = this
          set (obj, "Luck2", Luck: " + obj.Luck + "<br>)
        ]]></item>
	<item key="NightSight2"><![CDATA[
          obj = this
          set (obj, "NightSight2", Nightsight)
        ]]></item>
	<item key="Physical2"><![CDATA[
          obj = this
          set (obj, "Physical2", Physical: " + obj.Physical + "<br>)
        ]]></item>
	<item key="Poison2"><![CDATA[
          obj = this
          set (obj, "Poison2", Poison: " + obj.Poison + "<br>)
        ]]></item>
	<item key="ReflectPhysical2"><![CDATA[
          obj = this
          set (obj, "ReflectPhysical2", Reflect Physical: " + obj.ReflectPhysical + "<br>)
        ]]></item>
	<item key="RegenHits2"><![CDATA[
          obj = this
          set (obj, "RegenHits2", Hit Point Regeneration: " + obj.RegenHits + "<br>)
        ]]></item>
	<item key="RegenMana2"><![CDATA[
          obj = this
          set (obj, "RegenMana2", Mana Regeneration: " + obj.RegenMana + "<br>)
        ]]></item>
	<item key="RegenStam2"><![CDATA[
          obj = this
          set (obj, "RegenStam2", Stamina Regeneration: " + obj.RegenStam + "<br>)
        ]]></item>
	<item key="ResistColdBonus2"><![CDATA[
          obj = this
          set (obj, "ResistColdBonus2", Cold Resistance: " + obj.ResistColdBonus + "<br>)
        ]]></item>
	<item key="ResistEnergyBonus2"><![CDATA[
          obj = this
          set (obj, "ResistEnergyBonus2", Energy Resistance: " + obj.ResistEnergyBonus + "<br>)
        ]]></item>
	<item key="ResistFireBonus2"><![CDATA[
          obj = this
          set (obj, "ResistFireBonus2", Fire Resistance: " + obj.ResistFireBonus + "<br>)
        ]]></item>
	<item key="ResistPhysicalBonus2"><![CDATA[
          obj = this
          set (obj, "ResistPhysicalBonus2", Physical Resistance: " + obj.ResistPhysicalBonus + "<br>)
        ]]></item>
	<item key="ResistPoisonBonus2"><![CDATA[
          obj = this
          set (obj, "ResistPoisonBonus2", Poison Resistance: " + obj.ResistPoisonBonus + "<br>)
        ]]></item>
	<item key="Spellchanneling2"><![CDATA[
          obj = this
          set (obj, "Spellchanneling2", Spellchanneling)
        ]]></item>
	<item key="SpellDamage2"><![CDATA[
          obj = this
          set (obj, "SpellDamage2", Spell Damage: " + obj.SpellDamage + "<br>)
        ]]></item>
	<item key="WeaponDamage2"><![CDATA[
          obj = this
          set (obj, "WeaponDamage2", Weapon Damage: " + obj.WeaponDamage + "<br>)
        ]]></item>
	<item key="HitColdArea2"><![CDATA[
          obj = this
          set (obj, "HitColdArea2", Hit Cold Area: " + obj.HitColdArea + "<br>)
        ]]></item>
	<item key="HitDispel2"><![CDATA[
          obj = this
          set (obj, "HitDispel2", Hit Dispel: " + obj.HitDispel + "<br>)
        ]]></item>
	<item key="HitEnergyArea2"><![CDATA[
          obj = this
          set (obj, "HitEnergyArea2", Hit Energy Area: " + obj.HitEnergyArea + "<br>)
        ]]></item>
	<item key="HitFireArea2"><![CDATA[
          obj = this
          set (obj, "HitFireArea2", Hit Fire Area: " + obj.HitFireArea + "<br>)
        ]]></item>
	<item key="HitFireball2"><![CDATA[
          obj = this
          set (obj, "HitFireball2", Hit Fireball: " + obj.HitFireball + "<br>)
        ]]></item>
	<item key="HitHarm2"><![CDATA[
          obj = this
          set (obj, "HitHarm2", Hit Harm: " + obj.HitHarm + "<br>)
        ]]></item>
	<item key="HitLeechHits2"><![CDATA[
          obj = this
          set (obj, "HitLeechHits2", Hit Leech Hits: " + obj.HitLeechHits + "<br>)
        ]]></item>
	<item key="HitLeechMana2"><![CDATA[
          obj = this
          set (obj, "HitLeechMana2", Hit Leech Mana: " + obj.HitLeechMana + "<br>)
        ]]></item>
	<item key="HitLeechStam2"><![CDATA[
          obj = this
          set (obj, "HitLeechStam2", Hit Leech Stamina: " + obj.HitLeechStam + "<br>)
        ]]></item>
	<item key="HitLightning2"><![CDATA[
          obj = this
          set (obj, "HitLightning2", Hit Lightning: " + obj.HitLightning + "<br>)
        ]]></item>
	<item key="HitLowerAttack2"><![CDATA[
          obj = this
          set (obj, "HitLowerAttack2", Hit Lower Attack: " + obj.HitLowerAttack + "<br>)
        ]]></item>
	<item key="HitLowerDefend2"><![CDATA[
          obj = this
          set (obj, "HitLowerDefend2", Hit Lower Defense: " + obj.HitLowerDefend + "<br>)
        ]]></item>
	<item key="HitMagicArrow2"><![CDATA[
          obj = this
          set (obj, "HitMagicArrow2", Hit Magic Arrow: " + obj.HitMagicArrow + "<br>)
        ]]></item>
	<item key="HitPhysicalArea2"><![CDATA[
          obj = this
          set (obj, "HitPhysicalArea2", Hit Physical Area: " + obj.HitPhysicalArea + "<br>)
        ]]></item>
	<item key="MageWeapon2"><![CDATA[
          obj = this
          set (obj, "MageWeapon2", Mage Weapon)
        ]]></item>
</m_props2>

When you run this game below, answer Yes/No before doing anything else (you will see attributes being set, because of the debugging lines in the code). Then just open the Debugger and look at one of the objects in the weap_room (they are weapons except for: mag_props and alphabetdict). The function is adding random attributes, based upon an object's Rarity. So any object with a rarity greater than 11, will have at least ONE random attribute added. If you want to see what an object displays when you LOOK at it, just type LOOK SELF (x me) and three weapons will be added to the inventory. Just LOOK at one with a Rarity higher than 10.

Thanks,

  • Raist

<item>
  <key>AttackChance2</key>
  <value type="string">"Attack Chance: " + obj.AttackChance + "<br>"</value>
</item>

There's your problem.
The value of the AttackChance2 attribute is the string "Attack Chance: " + obj.AttackChance + "<br>" - that exact sequence of characters, including the quotes and the plus signs. That is a string, not an expression.

Solution 1

You can get it to be treated as an expression using the Eval function; but this is usually a bad idea because it increases your chance of bugs later.

This should work with your current alphabetdict.alphabetdict, but is inefficient:

<function name="Magical_Props" parameters="obj"><![CDATA[
  dict = mag_props.alphabetdict
  magical = NewStringDictionary()
  keys = NewStringList()
  foreach (key, dict) {
    list add (keys, key)
  }
  if (GetInt(obj, "rarity") > 91) {
    list = PickFiveStrings(keys)
  }
  else if (GetInt(obj, "rarity") > 71) {
    list = PickFourStrings(keys)
  }
  else if (GetInt(obj, "rarity") > 51) {
    list = PickThreeStrings(keys)
  }
  else if (GetInt(obj, "rarity") > 31) {
    list = PickTwoStrings(keys)
  }
  else if (GetInt(obj, "rarity") > 11) {
    list = PickOneStrings(keys)
  }
  else {
    list = NewStringList()
  }

  foreach (key, list) {
    val = DictionaryItem (dict, key)
    set (obj, key, val)
    // for debugging
    msg (obj.name + "." + key + " = " + val)
    // for debugging
    msg (GetAttribute(obj, key))
    dictionary add (magical, key + "2", val)
  }
  set (obj, "m_props2", magical)
  Properties_List1 (obj)

  msg ("Magical properties added on " + obj.name + "")
]]></function>

<function name="Properties_List1" parameters="obj" type="list">
    props = obj.m_props2
    dict = alphabetdict.alphabetdict
    foreach (key, props) {
      val = DictionaryItem (dict, key)
      set (obj, key, Eval(val))
      // for debugging
      msg (obj.name + "." + key + " = " + val)
      // for debugging
      msg (GetAttribute(obj, key))
    }
    set (obj, "m_props", (obj.AttackChance2 + obj.BonusDex2 + obj.BonusHits2 + obj.BonusInt2 + obj.BonusMana2 + obj.BonusStam2 + obj.BonusStr2 + obj.Chaos2 + obj.Cold2 + obj.DefendChance2 + obj.Direct2 + obj.Energy2 + obj.Fire2 + obj.LowerManaCost2 + obj.Luck2 + obj.NightSight2 + obj.Physical2 + obj.Poison2 + obj.ReflectPhysical2 + obj.RegenHits2 + obj.RegenMana2 + obj.RegenStam2 + obj.ResistColdBonus2 + obj.ResistEnergyBonus2 + obj.ResistFireBonus2 + obj.ResistPhysicalBonus2 + obj.ResistPoisonBonus2 + obj.SpellChanneling2 + obj.SpellDamage2 + obj.WeaponDamage2 + obj.HitColdArea2 + obj.HitDispel2 + obj.HitEnergyArea2 + obj.HitFireArea2 + obj.HitFireball2 + obj.HitHarm2 + obj.HitLeechHits2 + obj.HitLeechMana2 + obj.HitLeechStam2 + obj.HitLightning2 + obj.HitLowerAttack2 + obj.HitLowerDefend2 + obj.HitMagicArrow2 + obj.HitPhysicalArea2 + obj.MageWeapon2))
  </function>

(I've tidied up the code a bit, removing a lot of code which seems to make no difference at all, as well as adding the Eval. I figured that it's better to go through the whole thing, to make sure I'm not missing any nuances in how it works)

Solution 2

This is more efficient code, and less likely to introduce bugs later. But you'd need to change your alphabetdict.alphabetdict to look like:

<item>
  <key>AttackChance</key>
  <value type="string">Attack Chance</value>
</item>

Then the code would be:

<function name="Magical_Props" parameters="obj"><![CDATA[
  dict = mag_props.alphabetdict
  keys = NewStringList()
  foreach (key, dict) {
    list add (keys, key)
  }
  list = NewStringList()
  if (GetInt(obj, "rarity") > 11) {
    for (i, 12, GetInt(obj, "rarity"), 20) {
      list add (list, PickOneString(ListExclude (keys, list)))
    }
  }

  foreach (key, list) {
    val = DictionaryItem (dict, key)
    set (obj, key, val)
  }
  Properties_List1 (obj)

  msg ("Magical properties added on " + obj.name + "")
]]></function>

<function name="Properties_List1" parameters="obj" type="list">
    dict = alphabetdict.alphabetdict
    props = ""
    foreach (key, dict) {
      if (HasAttribute (obj, key)) {
        label = DictionaryItem (dict, key)
        val = label + ": " + GetAttribute(obj, key) + "<br/>"
        set (obj, key+2, val)
        // for debugging
        msg (obj.name + "." + key + "2 = " + val)
        props = props + val
      }
    }
    set (obj, "m_props", props)
  </function>

(In this case, the obj.m_props string lists all the attributes in the order they appear in alphabetdict.alphabetdict rather than having a manual list of them. It's usually better to not have the same list of attributes in multiple places in your code; because if you come to add more attributes later, or if someone else is learning from your code, it doubles the chance of adding a typo or something)

Of course, this option would only work if all the attributes should be displayed as name: value<br>.


Ah, just saw your post about making m_props2 a scriptdictionary.

Pretty sure this isn't what you want to do. Because a scriptdictionary's values are scripts. If you just want to combine a string and an attribute (and you want to combine them all in different ways), you would want a dictionary of expressions. In which case you have a stringdictionary, and use Eval as in my example above.

If all you want to do is make AttributeName2 equal to "Attribute Name: "+value of attribute + "<br>" then put that expression in the second function, as in my second example. There's no need for the dictionary to contain code at all.


Thanks for the reply mrangel,
I changed the functions to what you have above and the result does work. However, it displays every attribute, when it should only display the attributes with values greater than 0.

That was why I was adding them to a temporary list, putting that list into an attribute and then calling the value of that attribute to display the string/int combinations. Having an attribute hold this value, allows me to compare it to the list of keys with the string/int combinations.

EDIT: Just saw your other post. KV brought up the ScriptDictionary because that was the only way to get Quest to recognize a String with an Int. Each key would have a value like:

<item key="AttackChance2"><![CDATA[
          obj = this
          set (obj, "AttackChance2", Attack Chance: " + obj.AttackChance + "<br>)
        ]]></item>

That shows - Attack Chance: (script)
I tried setting the variable in different ways, adding a return function, the result was always (script).


If you have a script dictionary, you would need to do:

params = NewDictionary()
dictionary add (params, "obj", obj)
invoke (val, params)

(And remove the line obj = this, because this doesn't have any meaning in a script dictionary)

With a string dictionary where the string is an expression, you'd have:

params = NewDictionary()
dictionary add (params, "obj", obj)
set (obj, key, Eval (val, params))

That was why I was adding them to a temporary list, putting that list into an attribute and then calling the value of that attribute to display the string/int combinations.

Might make more sense to pass the list to the second function, rather than saving it as an attribute. Unless you need to access it later.

However, it displays every attribute, when it should only display the attributes with values greater than 0.

Ah, let's try to fix that…

<function name="Properties_List1" parameters="obj" type="list">
    dict = mag_props.alphabetdict
    props = ""
    foreach (key, dict) {
      if (HasAttribute (obj, key)) {
        if (IsInt (obj.key) and ToInt (obj.key) > 0) {
          val = UnCamelCase (key) + ": " + GetAttribute(obj, key) + "<br/>"
          set (obj, key+2, val)
          // for debugging
          msg (obj.name + "." + key + "2 = " + val)
          props = props + val
        }
      }
    }
    set (obj, "m_props", props)
  </function>

  <function name="UnCamelCase" parameters="input" type="string">
    output = ""
    for (i, 1, LengthOf(input)) {
      letter = Mid (input, i, 1)
      if (letter = UCase (letter) and not output = "") {
        output = output + " "
      }
      output = output + letter
    }
    return (output)
  </function>

(This version should work with the version of Magical_Props in my solution 2; any better?)


Thanks for clarifying the ScriptDictionary, that makes sense now.
Adding the list to an attribute is not a huge deal, I can always put it back in if I DO need to access that list for some reason. I just thought it might work better to "write" it to an attribute during initialise.

I adjusted my game to the above code. You have a function added that I do not have. I just downloaded Quest 5.8 beta 11 to be sure.
IsInt
Error running script: Error compiling expression 'IsInt (obj,key) and ToInt(obj,key) > 0':
FunctionCallElement: Could not find function 'IsInt(Object)'

Hopefully that is all it is. It seems like the code would work from looking at it. I understand that you cannot compare a Str and an Int, without converting one to the other first. In creating a new Dictionary, Quest changes the value to a string. If it remains an Integer, it simplifies this process a ton. Because then all I have to do is add an attribute to a list if it is greater than 0, set obj.mag_props = list. Because Quest changes the Dictionary to a StringDictionary, all of this has become increasingly...educational. For example, I started with:

<alphabetdict type="dictionary">
  <item>
        <key>AttackChance</key>
        <value>1</value>
   </item>

When I switched from Code view and back again, Quest changed it to:

<alphabetdict type="dictionary">
  <item>
        <key>AttackChance</key>
        <value type="string">1</value>
   </item>

I don't know if it is supposed to do that or not, but after that this was the direction KV helped point me in (most of the code came from KV, I just changed values here and there to see if I could get what I wanted without pestering everyone again).

Thanks,

  • Raist

I adjusted my game to the above code. You have a function added that I do not have.

Sorry; blame autocomplete.

Was typing on my phone, and sometimes it makes weird changes. In this case, it recognised a tap as a tap-and-hold, and did a search and replace.

If it remains an Integer, it simplifies this process a ton.

OK. I'll fix the error in my previous code, and also force the attribute to be saved as an integer for convenience.
I've got RL stuff to deal with now; but I should have it done for you in about half an hour.


<function name="Magical_Props" parameters="obj"><![CDATA[
  dict = mag_props.alphabetdict
  keys = NewStringList()
  foreach (key, dict) {
    list add (keys, key)
  }
  list = NewStringList()
  if (GetInt(obj, "rarity") > 11) {
    for (i, 12, GetInt(obj, "rarity"), 20) {
      list add (list, PickOneString(ListExclude (keys, list)))
    }
  }

  foreach (key, list) {
    val = DictionaryItem (dict, key)
    if (IsInt (val)) {
      val = ToInt (val)
    }
    set (obj, key, val)
  }
  Properties_List1 (obj)

  msg ("Magical properties added on " + obj.name + "")
]]></function>

<function name="Properties_List1" parameters="obj" type="list">
    dict = mag_props.alphabetdict
    props = ""
    foreach (key, dict) {
      if (HasInt (obj, key)) {
        if (GetInt(obj, key) > 0) {
          val = UnCamelCase (key) + ": " + GetInt(obj, key) + "<br/>"
          set (obj, key+2, val)
          // for debugging
          msg (obj.name + "." + key + "2 = " + val)
          props = props + val
        }
      }
    }
    set (obj, "m_props", props)
  </function>

  <function name="UnCamelCase" parameters="input" type="string">
    output = ""
    for (i, 1, LengthOf(input)) {
      letter = Mid (input, i, 1)
      if (letter = UCase (letter) and not output = "") {
        output = output + " "
      }
      output = output + letter
    }
    return (output)
  </function>

Does that work as expected?

I removed the second dictionary alphabetdict.alphabetdict here. You can add it back if you prefer.
But one of the most common ways to add bugs, and the place you find the hardest bugs to track down, is if you have the same list of attributes in 3 different places in the code, and one of them has a typo or something. So I think it's nearly always better to only have the list in one place. In this case, mag_props.alphabetdict.

If you need to have more than one dictionary, let me know and I can change it back. But before you include 2 copies of the same data, think about why it's necessary.


And there it is.
Thanks mrangel, that worked exactly as I saw in my head. I was thinking I might need three lists to cross-reference from AttackChance->AttackChance2->Attack Chance: 2, so that was why I was using two lists, one had the String values with the Ints that wasn't displaying.

I appreciate you both taking the time to give me a hand. Thanks for all of the help.

  • Raist

Log in to post a reply.

Support

Forums