If all you want to keep track of is one character's affection to one other (the player) TheMadExile's answer is perfectly fine and you won't need much else. If you want the full N:M mapping between multiple characters, read on.
Let's first define what we're trying to have available.
Modify affection from one character to another
As the second argument, we can always use someone's ID (as string) instead of their object
<<affection $aeronda $player +1>>
Print the affection of someone to someone else
<<affection $aeronda $player>>
Check if the affection is at or above 10
<<if affection.between($aeronda, $player) >= 10>>
...
<</if>>
For this, let's define the data structures: All characters are JavaScript objects and have an "aff" property, which itself is an object, and an "id" property which is unique to them and used to identify them, like this:
{
"id": "aeronda",
"aff": {
"player": -2,
"bob": 3,
"sauron": -1000
}
}
Obviously, there are other attributes (like the name!) for each character, but we don't care much about those at the moment. The default affection is 0. In the JavaScript part, let's define a global "affection" object which will hold all our helper JavaScript methods, including an "init" one which initialises the structure and methods for modifying and querying the affection values. At the beginning, it looks like this.
window.affection = {
init: function(ch) {
// Make sure we're dealing with actual characters
if(typeof ch !== 'object' || Array.isArray(ch) || typeof ch.id !== "string") {
throw "Not an valid character: " + JSON.stringify(ch);
}
// Initialise affinity attribute
if(typeof ch.aff !== 'object' || Array.isArray(ch.aff)) {
ch.aff = {};
}
// for call chaining
return ch;
},
between: function(ch, target) {
// target can be a character object or an id string here
if(typeof target === "string") {
return affection.init(ch).aff[target] || 0;
}
if(typeof target !== 'object' || Array.isArray(target) || typeof target.id !== "string") {
throw "Not an valid character: " + JSON.stringify(target);
}
return affection.init(ch).aff[target.id] || 0;
},
mod: function(ch, target, amount) {
var current = affection.between(ch, target);
// ch's affection attribute is initialized at this point,
// so we can use it safely
ch.aff[typeof target === "string" ? target : target.id] = current + amount;
},
};
Now all we need is a small widget to make the usage a bit neater.
<<widget "affection">>
<<if $args.length === 2>>
<<= affection.between($args[0], $args[1])>>
<<elseif $args.length === 3 && Number.isFinite($args[2])>>
<<= affection.mod($args[0], $args[1], $args[2])>>
<<else>>
<<run console.log("Unknown arguments to <<affection>>:"); console.log($args);>>
<</if>>
<</widget>>
Usage examples:
<<set $aeronda = {id: "aeronda", aff: {player: -3, bob: 1, sauron: -1000}}>>
<<set $player = {id: "player"}>>
<<affection $aeronda $player +1>>
Current affection: <<affection $aeronda $player>>
<<if affection.between($aeronda, $player) > 0>>Aeronda likes player!<<else>>Aeronda doesn't care much for player ...<</if>>
Affection to Sauron: <<affection $aeronda "sauron">>