Script Dictionary - As Attribute

Raist
29 Jun 2018, 11:01Good 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
mrangel
29 Jun 2018, 11:37OK, 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 dictionaryalphabetdict.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?

Raist
29 Jun 2018, 12:30Thanks 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
The Pixie
29 Jun 2018, 12:49If 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.

Raist
29 Jun 2018, 13:06Thanks 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
mrangel
29 Jun 2018, 13:35<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>
.
mrangel
29 Jun 2018, 13:42Ah, 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.

Raist
29 Jun 2018, 14:22Thanks 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).
mrangel
29 Jun 2018, 15:31If 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?)

Raist
29 Jun 2018, 16:26Thanks 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
mrangel
29 Jun 2018, 16:38I 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.
mrangel
29 Jun 2018, 16:49<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.

Raist
29 Jun 2018, 17:00And 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