0 votes
by (870 points)

[Disclaimer: I know I'm using ES6 and it's problematic, for now it's easier because it's similar to the Java I'm familiar with]

In my RPG, I have a widget for handling the decay of status effects at the end of each round:

<<widget "endofround">>
<<run console.log("End of round start")>>
<<for _actor range $args[0]>>
	<<run console.log(_actor.name)>>
        <<for _k, _effect range _actor.effects>>
			<<run console.log("Index #"+_k)>>
			<<run console.log(_effect.name)>>
			<<run console.log("Time = "+_effect.duration)>>
                /* DoT check */
                <<if _effect.dot is true>>
                        <<set _message to true>>
                        <<set $dmg = _effect.damage(_actor)>>
						<<print _effect.msg(_actor)>>
                        <<run _actor.setHP(-$dmg)>>
                        <<set $target[0] = _actor>>
                /* decrementor */
                <<if !_effect.topDec>>
					<<if _effect.duration >= 1 and !(_actor.stasis is true and _effect.name != "Stasis")>>
                    	<<set _effect.duration -= 1>>
					<<run console.log("Time = "+_effect.duration)>>
                	<<if _effect.duration == 0>>
                    	<<set _m = _actor.removeEffect(_k,'pierce')>>
						<<set _k -= 1>>
						<<if _m.length > 0>>
							<<print _m>>
							<<set _message to true>>

...where $args[0] is the party (enemies or allies).

removeEffect is a method function I define in the battling character class:

window.Actor = class Actor {
	removeEffect (id,mod) {
		if (!this.stasis || mod == 'pierce'){
			var effect = this.effects[id];
			return effect.removeText(this.name)+"\n";
		} else {
			return `${this.name}'s Stasis held the effect in place!<br/>`;

...where onRemove is a method function for status effects. It works fine when it's successfully called, so I don't think it's a problem.

This is creating an issue: If multiple effects expire on the same turn, the index pointer in the reaper loop is thrown off, because I used deleteAt(), which adjusts the array length to compensate for the deletion. So for instance, if effect #0 and effect #1 both expire simultaneously, the reaper deletes effect #0, which causes effect #1 to become effect #0; but _k is now 1, and the next iteration of the reaper therefore tries to apply removeEffect() to the effect at index 1, which no longer exists.

I'm not entirely sure how to fix this. I attempted to decrement _k after the removal, but that appears to be overridden by the loop logic. Is a simple patch possible, or will I have to scrap this widget and create a new algorithm entirely?

1 Answer

+1 vote
by (68.6k points)
selected by
Best answer

If the effects are unique, then just pass the effect itself to <Actor>.removeEffect() and have it use <Array>.delete().  The <Actor>.effects property looks to be an array and the effects themselves are clearly objects, so they likely are unique (within the array at least).

Alternatively.  If the effects are not unique, then you could simply use the <<for>> macro's 3-part form rather than its range form, which would allow you to modify the loop index outside of the post expression (don't forget to modify the upper bounds as well).

by (870 points)
Some effects are stackable, so multiples of the same type can occur. I'm not sure if that counts as non-unique for objects, though. Does each object have a unique ID even if they have identical attributes, such that delete() would only delete that instance?
by (68.6k points)

Effects would be unique, in the sense I mean, if they refer to different objects (meaning structures in memory).  The equivalence of some or all properties of the objects is irrelevant in this case.  The <Array>.delete() method uses strict equality for its comparisons, which for objects means the references must be exactly identical.

TL;DR: Similar types of effects would still be distinct objects and thus unique.

by (870 points)
Okay, great! I was worried that wasn't true. I changed to using .delete() as you suggested and it works now. Thanks!