0 votes
by (390 points)

Running Twine 2. Harlowe 2.0.1

I am working on a combat model that is based loosely on the GURPS role-playing system. I wanted to give the player options to "Defend" or "Berserk" on their turn.

I wanted Defend to modify their defense skills in a positive way and attack skills negatively; Berserk would improve attack while lowering defenses. These benefits would last only for the one round and all statistics should reset to their original states at the start of the next round.

I used a (set:) macro and did something like:

<!--MODIFIERS-->
(if:$defend is  'on')[
(set:$hero's attskill to it - 2)
(set:$hero's defskill to it + 2)
(set:$hero's def to it +2)]

(if:$berserk is 'on')
[(set:$hero's attskill to it +4)
(set:$hero's defskill to it - 4)
(set:$hero's dam to it +2)]

This runs prior to the routine that does all of the attack/defense checks and doles out damage to determine the round. Before the round turns, I then set "$defend" and "$berserk" to 'off' thinking that that would not maintain those bonuses.

Unfortunately, what ends up happening is that the statistics change permanently after each round. So if I choose Berserk, my attack skill can get into 30s or 40s. This is not good.

I've gotten all of my characters/NPC stats, weapons, and armor into a datamap and have ways to influence the game based on what type of weapon or armor someone has equipped, but I can't for the life of me figure out how to get this temporary modifier to work correctly.

Can I use temporary variables? Should I datamap the modifiers so I can add more in the future? Is this a lost cause?

Thanks for any help. I have been searching endlessly for this scenario. Happy to clarify if there's any confusion.

1 Answer

0 votes
by (8.9k points)
edited by

It's doing what you asked it to!  You told it to change the hero's stats if $defend or $berserk were 'on', and it did.  

Changing the value of $defend or $berserk later won't make it also change the hero's stats again; you need to tell it to do that.

You could do something like this at the end of the passage...

(if:$defend is  'on')[
(set:$hero's attskill to it + 2)
(set:$hero's defskill to it - 2)
(set:$hero's def to it -2)
(set:$defend to 'off')
]

(if:$berserk is 'on')
[(set:$hero's attskill to it - 4)
(set:$hero's defskill to it + 4)
(set:$hero's dam to it -2)
(set:$berserk to 'off')
]

 

by (390 points)
edited by

Thanks for the response! I will give this a shot today and see how it works.

Would there be a more efficient way to do this? For example, if I had a routine or datamap I could reference so that I could apply the berserk or defend options to NPCs as well? Or even implement things like being stunned?

Such as:

(set:$berserk to (datamap:
"attskill",$hero's attskill + 4,
"defskill",$hero's defskill - 4,
"dam",$hero's dam+2)
)

So then those values would only be referenced based on the PC stats, which should remain unchanged?

I tried to set each "modifier" as its own datamap (as above), then reference those prior to the fight routine, but because I have reference to the PC's datamap and the NPC's datamap throughout the routine itself, it make it a lot trickier to line those up.

Would a solution potentially be to assign the PC or NPC a code (ie (set: $hero to 'initiative1')(set: $opponent to 'initiative2')) prior to the fight routine so the variables throughout the checks would have generic names that could be influenced by other data sets?

Another thing I considered was adding modifier slots to the PC's datamap (ie $attmod or $defmod), set them to 0 and then when the berserk or defend options are, those mods are temporarily populated with the benefits.

Thanks again, I have literally just picked up Twine this week and have been working with it non-stop.

by (8.9k points)
Sorry, I don't know Harlowe well enough to advise you on that (I'm a SugarCube user myself).  It might be best to ask that as a new question.

Welcome to Twine!  It's awesome.  :-)
by (390 points)
Thanks! I haven't done any programming/coding since BASIC, so this is a real hoot.
by (63.1k points)

I would suggest using a separate set of "actual" variables that are rolled every time they're needed and constructed from the possible modifiers and the player's actual stats. That way, you only need to alter the modifiers themselves, and you won't need an (if:) at all. 


(set: $atk to $hero's attskill + $berserkerAtk + $weaponAtk + $etc)

<!-- when the player berserks -->
(set: $berserk to 4)

 

by (390 points)

That's a very good suggestion. I have added a couple entries to the datamap for the PC to include modifiers for attack, defense, and damage. So, the code (though in separate areas) sort of amounts to:

<!--PC GENERATION-->

(set:$hero to (datamap:
"hp",100,
"attskill",10,
"defskill",10,
"str",10,
"dam",0,
"DR",0,
"oDR",0,
"exp",0,
"gp",10,
"level",1,
"weapon",'none',
"armor",'none',
"magic",'none',
"attmod",0,
"defmod",0,
"dammod",0))

<--!MODIFIER at TOP OF FIGHT ROUTINE-->

(if:$mystance is 'berserk')[
(set:$hero's attmod to 4)
(set:$hero's defmod to -4)
(set:$hero's dammod to 2)
]

(if:$mystance is 'defend')[
(set:$hero's attmod to -2)
(set:$hero's defmod to 2)
(set:$hero's dammod to 0)
]

Where clicking your action on the battle screen assigns the variable to $mystance. At the end of the round, all the modifiers (attmod, defmod, dammod) are set back to zero and the stance is reset.

My goal is to be able to add a plethora of modifiers with as little difficulty and additional programming as possible.

I have started working on a "stunned" modifier that would last for multiple rounds, but it is difficult to get it timed correctly to last and be correctly displayed over the course of several rounds. That's the next challenge, I guess.

...