Issues with Dropdown in Harlowe

Twine Version: 2.8.1
Story Format: Harlowe 3.3.8

Greetings! I am very new to Twine and am currently working on my first project. I’ve had a look through the forum, but couldn’t find a similar post, which is why I’m writing this. Please excuse if something similar has already been asked.
I’d like to write a quasi text based RPG, so naturally, I want to include a “character creation” screen at the beginning. On this page the user can choose a race for their character, adjust some abilitiy stats and give their character a name, all very reminiscent of classic rpg’s like D&D. I’ve done the ability stats and choosing the name and I’m quite happy with the results, but choosing a race for the character is giving me a hard time.

For referance, the code for adjusting the stats (which works perfectly fine) looks like this:

<==
||||=
Strength: {
	(link-repeat: "|+|")[
    	(if: $points > 0)[
        (set: $str to it + 1)
        (set: $points to it - 1)
        (replace: ?strengthStat)[|strengthStat>[$str]]
        (replace: ?pointsStat)[|pointsStat>[$points]]
     ]
  ] |strengthStat>[0]

	(link-repeat: "|-|")[
    	(if: $str > 0)[
        (set: $str to it - 1)
        (set: $points to it + 1)
        (replace: ?strengthStat)[|strengthStat>[$str]]
        (replace: ?pointsStat)[|pointsStat>[$points]]
      ]
    ]
} 

Intelligence: {
	(link-repeat: "|+|")[
    	(if: $points > 0)[
        (set: $int to it + 1)
        (set: $points to it - 1)
        (replace: ?intStat)[|intStat>[$int]]
        (replace: ?pointsStat)[|pointsStat>[$points]]
      ]
    ] |intStat>[0]

	(link-repeat: "|-|")[
    	(if: $int > 0)[
        (set: $int to it - 1)
        (set: $points to it + 1)
        (replace: ?intStat)[|intStat>[$int]]
        (replace: ?pointsStat)[|pointsStat>[$points]]
      ]
    ]
}

Dexterity: {
	(link-repeat: "|+|")[
    	(if: $points > 0)[
        (set: $dex to it + 1)
        (set: $points to it - 1)
        (replace: ?dexStat)[|dexStat>[$dex]]
        (replace: ?pointsStat)[|pointsStat>[$points]]
      ]
    ] |dexStat>[0]

	(link-repeat: "|-|")[
    	(if: $dex > 0)[
        (set: $dex to it - 1)
        (set: $points to it + 1)
        (replace: ?dexStat)[|dexStat>[$dex]]
        (replace: ?pointsStat)[|pointsStat>[$points]]
      ]
    ]
}

{
	(link-repeat: "|Reset Points|")[
    	(set: $str to 0)
        (set: $int to 0)
        (set: $dex to 0)
        (set: $points to 15)
        (replace: ?strengthStat)[|strengthStat>[$str]]
        (replace: ?intStat)[|intStat>[$int]]
        (replace: ?dexStat)[|dexStat>[$dex]]
        (replace: ?pointsStat)[|pointsStat>[$points]]
      ]
}

(text-style:"underline")[Remaining Points: |pointsStat>[15]] 

The issue that I’m having is with the selection of the character’s race. I’ve made a dropdown menu with three options (Human, Dwarf and Elf). When the user selects one of these options 2 things should happen:

  1. A descriptive text should be displayed
  2. I’d like the choice of character race to influence the ability stats (ie. if “Human” is chosen give a +1 bonus to all stats (strength, intelligence and dexterity), if “Dwarf” is chosen get rid of the Human bonus and instead give a +2 bonus to strength and -1 to intelligence, if “Elf” is chosen get rid of any previous bonus and give a +2 to dexterity and -1 to strength)

The first works just fine, but number 2 is giving me lots of headache, and I just can’t make it work…

The code I wrote for this looks as follows:

Choose your Race: [(dropdown: 2bind $race, " ", "Human", "", "Dwarf", "", "Elf")] 
{
(set: _Hbonus to 1)
(set _HumanSelected to false)
(set: _DwarfSelected to false)
(set: _ElfSelected to false)
|Human>[(event: when $race is "Human")[
(if: not _HumanSelected)[
(set: $str to it + _Hbonus)
(set: $int to it + _Hbonus)
(set: $dex to it + _Hbonus)
(set: _HumanSelected to true)
(set: _DwarfSelected to false)
(set: _ElfSelected to false)
(replace: ?strengthStat)[|strengthStat>[$str]]
(replace: ?intStat)[|intStat>[$int]]
(replace: ?dexStat)[|dexStat>[$dex]]
]
(replace: ?raceText)[
Some descriptive text about Humans.](rerun: ?Human)]]

|raceText>[]
}

The problem I’m having is that the bonuses are cumulative, and whenever a new option is chosen from the dropdown menu, the values of $str, $int and $dex just keep increasing. I don’t know how to make it so that the +1 bonus to all stats from the “Human” choice is reverted when another selection is made (I hope that explanation makes sense). What am I doing wrong/how can this be fixed?

EDIT: Also, I just found out that choosing any option in the dropdown menu makes all other interactable elements un-interactable? Meaning that the user can’t adjust their stats anymore once they used the dropdown menu, as the link-repeat links stop working… Why is that and how can it be fixed?

P.s.: To avoid redundancy and prevent this post from getting too long, I omitted the code I have for Dwarves and Elves which is exactly the same as above with a few words changed.
Thanks a lot in advance!

1 Like

When replacing the current content of a Named Hook you shouldn’t need to redefine that Hook.
eg. notice how the Hook associated with the following (replace:) macro call only includes the value of the variable…

|counter>[$counter]
(link-repeat: "Increase Counter")[
	(set: $counter to it + 1)
	(replace: ?counter)[$counter]
]

…not another re-definition of the same Named Hook like your example has…

(replace: ?counter)[ |counter>[$counter] ]
2 Likes

You’re right, thank you for pointing that out, Greyelf. It makes my code a bit prettier, I guess, but unfortunately doesn’t solve any of the problems that I’m having.

Still, thanks for the hint! :slight_smile:

1 Like

I’ve done something very similar with stats and racial bonuses in an abandoned Harlowe game. I’ll look at it tonight and see what I can glean from it.

From my experience, what you’re trying to accomplish in the character creation passage is probably more complicated than anything you’ll actually do in your game. We’ll figure it out, not to worry. :slight_smile:

Awesome, thank you so much, Hal! :smiley:

From my experience, what you’re trying to accomplish in the character creation passage is probably more complicated than anything you’ll actually do in your game.

Yeah, I was beginning to fear that is the case, actually. But that’s ok, I’m here to learn and I want to get better at this, looking forward to what you’ll have to say!

1 Like

Generally the secret to crafting such a Character Creation screen is to use Temporary variables to store the point assignments and racial bonus, and to only update the related Story variables after the end-user indicates they are finished making their choices.
1: Initialise the Race and Stat related Story variables in the project’s startup tagged Passage.

(set: $race to "", $str to 0, $int to 0, $dex to 0)

2: Ask the end-user to select the Race and assign Points

note: the following only handles Strength Point assignment, but it includes all the Temporary variables required to handle Intelligence and Dexterity as well. I strongly suggest you lookup the documentation of any macro you’re not yet familiar with.

(set: _points to 15, _str to 0, _int to 0, _dex to 0)
(set: _race to $race, _raceStr to 0, _raceInt to 0, _raceDex to 0)

Choose your Race: (dropdown: 2bind _race, "Human", "Dwarf", "Elf")

Assignable Points: [_points]<points| remaining

Strength: {
	(link-repeat: "|+|")[
		(if: _points > 0)[
			(set: _str to it + 1)
			(set: _points to it - 1)
			(rerun: ?strength)
			(rerun: ?points)
		]
	]
	|strength>[(print: $str + _raceStr + _str)]
	(link-repeat: "|-|")[
		(if: _str > 0)[
			(set: _str to it - 1)
			(set: _points to it + 1)
			(rerun: ?strength)
			(rerun: ?points)
		]
	]
}

{
(link-repeat: "|Reset Points|")[
	(set: _points to 15, _str to 0, _int to 0, _dex to 0)
	(rerun: ?strength)
	<!-- also rerun Intelligence and Dexterity -->
	(rerun: ?points)
]
}

(link-reveal-goto: "Save Character", "Second")[
	(set: $str to it + _raceStr + _str)
	(set: $int to it + _raceInt + _int)
	(set: $dex to it + _raceDex + _dex)
]

|race>[{
	(event: when _race is not $race)[
		(set: $race to _race)
		(if: _race is "Human")[
			(set: _raceStr to 1, _raceInt to 1, _raceDex to 1)
		]
		(else-if: _race is "Dwarf")[
			(set: _raceStr to 0, _raceInt to 0, _raceDex to 0)
		]
		(else-if: _race is "Elf")[
			(set: _raceStr to 0, _raceInt to 0, _raceDex to 0)
		]
		(rerun: ?strength)
		<!-- also rerun Intelligence and Dexterity -->
		(rerun: ?race)
	]
}]
1 Like

Fear?! It’s a time for celebration! It’s all downhill from here, man. Easy-peasy! That 5-headed hydra boss monster with independent HP for each head with the enhanced damage evolution, as each head gets lopped off, will be a breeze! :wink:

Edit: Looks like Greyelf solved it! Let us know if you have any more questions.

Just to mention when I did my game, I had Humans, Elves, Dwarves and Orcs. The other races got specific stat bonuses, but the humans had extra points to spend instead. Just putting that out there.

Good luck on your game! Definitely let us know when it’s playable. :slight_smile: