Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

[Sugarcube] Replacing varibles after loop iterations?

Hello, I'm new to Twine and this forum and coding in general. I've looked where I know to look and read the resources I'm aware of, yet I cannot resolve this, so I'll just ask.

I was able to create a cute little random dialogue with a receptionist using:
<<set $array = ["foo", "bar", "baz", "qux"]>>
<<set $length = $array.length>>
<<set $i = Math.floor(Math.random()*$length)>>
<<print $array[$i]>>

which Sharpe suggested in twinery.org/forum/discussion/1581/choosing-at-random-from-an-array. The key feature was that it allowed me to identify the position of the phrase within the array that was printed. Which allows my receptionist to provide a coherent response. The natural progression of course is to grant my reader agency to climb over the desk and initiate combat with the receptionist. Sooo I tried to evolve the above into a looping auto-resolving combat system.

<<for $pchealth and $enemyhealth are gte 1>>

Doesn't work. Because you guessed it: the variables do not change upon each iteration, once "foo" attack is randomly selected and deflected by the "baz" defense, every iteration repeats those same two...uh arguments ad infinitum.

Upon further modification I did find a way to have each iteration select different options, however from what I could tell in the output, each option, "foo", "bar" etc...could only be selected once (like plucking?), afterward the loop just spits out blank space until someone's health is magically reduced to 0.

I would post what I've come up with, but at this point they've mutated beyond comprehension, and Twine can no longer process them.

tl;dr
How do I create a loop that randomly selects components of its array while retaining them, and also allows me to identify which element of the array was utilized in the most recent loop iteration?

I'm pretty sure the answer is temporary variables, but I've been unable to plug them in correctly to create working code.

Also, I have no problem scraping what I've developed thus far and utilizing a more efficient approach.

Comments

  • First. Since you've tagged this with "sugarcube 2.0", I'd suggest starting with the SugarCube 2 documentation if you haven't already.

    ManicPhase wrote: »
    I was able to create a cute little random dialogue with a receptionist using:
    <<set $array = ["foo", "bar", "baz", "qux"]>>
    <<set $length = $array.length>>
    <<set $i = Math.floor(Math.random()*$length)>>
    <<print $array[$i]>>
    SugarCube 2 comes with several randomness functions and methods built-in: either() function, random() function, randomFloat() function, <Array>.pluck() method, Array.random() method, <Array>.random() method (among others). There is no reason to use Math.random() directly.

    Also, please use the code tag, not the quote tag, for code.

    ManicPhase wrote: »
    <<for $pchealth and $enemyhealth are gte 1>>

    Doesn't work. Because you guessed it: the variables do not change upon each iteration, once "foo" attack is randomly selected and deflected by the "baz" defense, every iteration repeats those same two...uh arguments ad infinitum.
    The code shown doesn't work because the syntax is invalid. You didn't bother to show your random attack code, so I have no idea what's wrong with it.

    Something like the following is what you were looking for with your shown code:
    /* $pchealth and $enemyhealth should be properly initialized by now. */
    
    /* Loop until one of the combatants health drops below 1. */
    <<for $pchealth gte 1 and $enemyhealth gte 1>>
    
    	/* Code that modifies $pchealth and $enemyhealth. */
    
    <</for>>
    

    ManicPhase wrote: »
    How do I create a loop that randomly selects components of its array while retaining them, and also allows me to identify which element of the array was utilized in the most recent loop iteration?
    Assuming the following setup:
    <<set $attacks to ["foo", "bar", "baz", "qux"]>>
    
    You could try something like the following:
    <<for /* some condition */>>
    	<<set _attack to $attacks.random()>>
    
    	/* Code that does something with _attack. */
    
    <</for>>
    
    Or the equivalent:
    <<for /* some condition */>>
    	<<set _attack to either($attacks)>>
    
    	/* Code that does something with _attack. */
    
    <</for>>
    
  • Awesome, thank you for your prompt response. Here's what I made with that:
    <<set $health to 8>>
    <<set $enemyhealth to 8>>
    <<set _attack to $attack.random()>>
    <<set _enemydefend to $enemydefend.random()>>
    <<set _enemyattack to $enemyattack.random()>>
    <<set _defend to $defend.random()>>
    
    <<for $health gte 1 and $enemyhealth gte 1>> 
    
    <<print _attack>>
    <<print _enemydefend>>
    <<if _enemydefend is 2>><<set $enemyhealth -= random(1,4)>><</if>>
    <<if _enemydefend is 5>><<set $enemyhealth -= random(1,4)>><</if>>
    <<print "$enemy : $enemyhealth">>
    
    <<print _enemyattack>>
    <<print _defend>>
    <<if _defend is 1>> <<set $health -= random(1,4)>><</if>>
    <<print "You: $health">>
    
    <</for>>
    <<return>>
    

    This still loops the same phrase from my array upon each iteration.

    And since it's probably not clear-- what I'm trying to do with the <<if>> statements is trigger health loss because the phrase at position 1 in the $defend array, and those at positions 2 and 5 in the $enemydefend array indicate an attack has inflicted between 1 and 4 damage.


    Thanks
  • Okay, I fixed the redundant loop problem by putting my set _tempvariables inside the actual <<for>> loop, as you indicated. But the array position issue remains...
  • To determine whether health should be lost, you'd likely be better off checking the attack/defense values, rather than their indexes within the arrays.

    That said, try something like the following to do it by index:
    <<set $health to 8>>\
    <<set $enemyhealth to 8>>\
    <<for $health gte 1 and $enemyhealth gte 1>> 
    <<silently>>
    	<<set _atkIdx      to random($attack.length - 1)>>
    	<<set _defIdx      to random($defend.length - 1)>>
    	<<set _enemyAtkIdx to random($enemyattack.length - 1)>>
    	<<set _enemyDefIdx to random($enemydefend.length - 1)>>
    <</silently>>
    
    <<print $attack[_atkIdx]>>
    <<print $enemydefend[_enemyDefIdx]>>
    <<if _enemyDefIdx is 2 or _enemyDefIdx is 5>><<set $enemyhealth -= random(1, 4)>><</if>>
    $enemy : $enemyhealth
    
    <<print $enemyattack[_enemyAtkIdx]>>
    <<print $defend[_defIdx]>>
    <<if _defIdx is 1>> <<set $health -= random(1, 4)>><</if>>
    You: $health
    
    <</for>>
    
    You'll probably need to police the line breaks a bit, but you should get the idea.
  • Cool. Greatly appreciated.
Sign In or Register to comment.