Custom Macro does not recognize objects properly

Custom macros recognize objects passed to it as strings, I don’t quite understand what’s going on and I think I’m letting something go…

<<addToInvent>>
    {itemName: "water", quantity: 5, masQuantity: 12}
<</addToInvent>>

The macro recognizes this as a string… In this case I used the JSON.parse() method.

Macro.add("addToInvent", {
    tags    : [null],
    handler : function() {
        if (this.payload[0].contents.length == 0) {
            return this.error("Error! No items specified!");
        }
        
        var itemToAdd = JSON.parse(this.payload[0].contents);
        var inventory = State.active.variables.player.inventory;

        for(let index = 0; index < inventory.length; index++) {
            if (inventory[index].itemName === itemToAdd.itemName) {
                if (inventory[index].quantity < inventory[index].maxQuantity) {
                    inventory[index].quantity += itemToAdd.quantity;
									
		            if (inventory[index].quantity > inventory[index].maxQuantity) {
	                    itemToAdd.quantity = inventory[index].quantity - inventory[index].maxQuantity; 
			            inventory[index].quantity = inventory[index].maxQuantity;
		            } else {
			            return;
		            }
                }
            }
        }	
	    inventory.push({
            itemName: itemToAdd.itemName,
            quantity: itemToAdd.quantity,
            maxQuantity: itemToAdd.maxQuantity
        });
	    return;
    }
});

You mean custom macros within the <<widget>> tagged passage or with the Macro.add() of the Macro API?

What worked for me:

<<widget addToInvent>>\
   <<set $item to {itemName: "water", quantity: 5, masQuantity: 12}>>\
<</widget>>\

Not a widget, I refer to a Macro.add().

Macro.add("customMacroName", {
    tags    : null,
    handler : function() {
       [Code]
});

I’m not clear what you mean by “does not recognize objects properly”. In what way is it failing?

In any case, you’ll need to include the code to your custom macro before we can figure out what’s going wrong with it.

Yes, I just posted the macro I created to add items to inventory… Like I said I pass an object to the Macro (a new item) but the Macro takes it as a string.
"{itemName: 'water' , quantity: 5, butQuantity: 12}"
I used the JSON.parse() method to convert strings back to objects… But I think I’m missing something about how the Macro interprets objects

You need to use back-quotes mentioned within the Macro Arguments documentation when passing an object as an argument to a macro.
eg. <<addToInvent `{itemName: "water", quantity: 5, maxQuantity: 12}`>>

The following is a modified version of your macro example, with a little more error checking added.

Macro.add('addToInvent', {
	handler() {

		if (this.args.length === 0) {
			return this.error('no item specified');
		}

		var item = this.args[0];

		if (typeof item !== 'object') {
			return this.error('specified item is not an object');
		}


		/* Check integery of item. */
		if (! item.itemName || typeof item.itemName !== 'string') {
			return this.error('<item>.itemName String not specified');
		}
		if (! item.quantity || typeof item.quantity !== 'number') {
			return this.error('<item>.quantity Number not specified');
		}
		if (! item.maxQuantity || typeof item.maxQuantity !== 'number') {
			return this.error('<item>.maxQuantity Number not specified');
		}
		/* Fix item's quantity if outside allowed range. */
		item.quantity.clamp(0, item.maxQuantity);

		var inv = State.variables.player.inventory;

		/* Loop inventory for exisiting instance of item. */
		for (var i = 0; i < inv.length; i++) {
			if (inv[i].itemName === item.itemName) {
				inv[i].quantity = (inv[i].quantity + item.quantity).clamp(0, inv[i].maxQuantity)
				return;
			}
		}

		/* Item not in inventory, so add it. */
		inv.push({
			itemName: item.itemName,
			quantity: item.quantity,
			maxQuantity: item.maxQuantity
		});
	}
});
1 Like

Greyelf provides a variant of your original macro that is probably more along the lines of what you want, so I strongly suggest looking into that.


That said, I can provide some comments on your original macro that may help in future attempts. Your macro has a few issues basic issues that I noticed in a very brief review—basically, I stopped after the first few I noticed:

1. The value you’re using for the macro definition’s tags property is incorrect—i.e., tags : [null],. To signify that a macro is a container macro with no child tags, the value provided to the tags property should be either null or an empty array ([]), never an array containing null—i.e., use null or [], rather than [null].

 
2. The payload test will fail to detect “empty” payloads that contain any whitespace, because you’re not trimming the payload. Rather than something like your original code:

if (this.payload[0].contents.length == 0) {
	return this.error("Error! No items specified!");
}

var itemToAdd = JSON.parse(this.payload[0].contents);

I would instead suggest:

var jsonContent = this.payload[0].contents.trim();

if (jsonContent.length === 0) {
	return this.error("No items specified!");
}

var itemToAdd = JSON.parse(jsonContent);

Optionally. It might be nice to catch exceptions thrown by JSON.parse() and return them as errors.

 
3. You’re using JSON.parse() to parse the macro’s payload, however, you’re specifying an object literal within the payload in your usage example. JavaScript object literals and JSON are not the same thing—see JavaScript and JSON differences. Here’s an example of what was supplied in your example, an object literal, versus what you needed, a JSON string:

  • Object literal: {itemName: "water", quantity: 5, masQuantity: 12}
  • JSON string: {"itemName": "water", "quantity": 5, "masQuantity": 12}

Note how in the JSON example the key/property names are quoted.

1 Like