# *Rand values (traits) repeating twice help

If you still want to do this, it would probably be easiest to generate three unique numbers before assigning trait names. Solskin’s code already works for that, but if loops are giving you trouble here’s a non-looping version (assuming 20 traits):

``````*temp A
*temp B
*temp C

*rand A 1 20
*rand B 1 19
*rand C 1 18
*if B >= A
*set B +1
*if (C>=B) and (C>=A)
*set C +2
*goto display
*elseif C>=B
*set C +1
*if C=A
*set C +1
*goto display
*elseif C>=A
*set C +1
*if C=B
*set C +1
*goto display
*else
*goto display

*label display
\${A},\${B},\${C}
*finish
``````
2 Likes

What might be easier here is: First getting 3 random Numbers, then Check of any of them is equal to another, if there are matches Go to the beginning of the label, if not Look which traits WE got. I am at Work atm will send a Code later

1 Like

Thanks for coding this.
So what is the +1 +2 meaning? Is +1 meant to be a trait name? And how can B >= A…etc… C=A, C>=B…I’m confused. How can a letter be greater or less than or equal to?

Using MeltingPenguin’s code idea I’ve come up with a personality system consisting of setting three traits. Per personality system, there could be three trait sets under the same title. For example: The Pushover personality type is repeated three times with slightly different variations in traits. I’ve made it still random of which personality will be picked, but the traits within those personalities remain the same. If that makes sense…
Pros: It’s easy to code and fun to think of which traits might go to which personality
Cons: It’s manually done, people could get upset based on which traits go under each personality heading (like if “Ideal Partner” has certain traits that not everyone thinks are ideal).

1 Like

The only things the code does is come up with three unique random numbers within 1~20, called A,B and C. The numbers can be matched up with the traits later.

Hmm alright, I’ll break the code down and try to explain how it works bit by bit. I’ll also only leave the essentials. It’s gonna be long but I’ll try my best to break it down. If you still don’t feel comfortable in using it, I don’t mind. I had fun making it.

Here is the simplified code, I removed the search and made only one type of display available. This one is 159 lines.

``````*title Trait randomizer
*author GS

*create implicit_control_flow true

*create trait_1 "Compassionate"
*create trait_2 "Tall"
*create trait_3 "Strong"
*create trait_4 "Pretty"
*create trait_5 "Patient"
*create trait_6 "Smart"
*create trait_7 "Diligent"
*create trait_8 "Just"
*create trait_9 "Honest"
*create trait_10 "Shy"
*create trait_11 "Young"
*create trait_12 "Greedy"
*create trait_13 "Brave"
*create trait_14 "Groomed"
*create trait_15 "Stubborn"
*create trait_16 "Fussy"
*create trait_17 "Curious"
*create trait_18 "Playful"
*create trait_19 "Quick"
*create trait_20 "Humble"

*create trait_quantity 20
*create char_quantity 10
*create allowed_traits 3

*create char_1_1 "Michelle"
*create char_1_2 ""
*create char_1_3 ""
*create char_1_4 ""

*create char_2_1 "John"
*create char_2_2 ""
*create char_2_3 ""
*create char_2_4 ""

*create char_3_1 "Kevin"
*create char_3_2 ""
*create char_3_3 ""
*create char_3_4 ""

*create char_4_1 "Erica"
*create char_4_2 ""
*create char_4_3 ""
*create char_4_4 ""

*create char_5_1 "Jackson"
*create char_5_2 ""
*create char_5_3 ""
*create char_5_4 ""

*create char_6_1 "Samuels"
*create char_6_2 ""
*create char_6_3 ""
*create char_6_4 ""

*create char_7_1 "Merlin"
*create char_7_2 ""
*create char_7_3 ""
*create char_7_4 ""

*create char_8_1 "Stanley"
*create char_8_2 ""
*create char_8_3 ""
*create char_8_4 ""

*create char_9_1 "Waits"
*create char_9_2 ""
*create char_9_3 ""
*create char_9_4 ""

*create char_10_1 "Ripley"
*create char_10_2 ""
*create char_10_3 ""
*create char_10_4 ""

*choice
#Randomize traits.
*gosub randomizer

*gosub show_chars_simpler

*finish

*comment =============SHOW CHARACTERS SIMPLER===============
*label show_chars_simpler
*temp counter 0
*temp trait_counter 2
*label show_chars_simpler_loop
*set counter + 1

*if (counter > char_quantity)
*return

==================
*line_break
\${char[counter][1]}'s traits (Character id: \${counter})
*line_break
==================

*label show_chars_simpler_traits_loop
*if (trait_counter > "\${allowed_traits+1}")
*goto show_chars_simpler_loop
-\${char[counter][trait_counter]}
*line_break
*if (trait_counter > allowed_traits)
*set trait_counter 2
*goto show_chars_simpler_loop
*else
*set trait_counter + 1
*goto show_chars_simpler_traits_loop

*comment =============RANDOMIZER===============
*label randomizer
*temp new_trait 0
*temp char_counter 1
*temp trait_counter 2
*label randomizer_loop
*temp proceed false
*rand new_trait 1 trait_quantity

*if (char_counter > char_quantity)
*return
*else
*gosub check_existent char_counter new_trait
*if (trait_counter > "\${allowed_traits+1}")
*set char_counter + 1
*set trait_counter 2
*goto randomizer_loop
*else
*if (proceed)
*set char[char_counter][trait_counter] trait[new_trait]
*set trait_counter + 1
*goto randomizer_loop
*else
*goto randomizer_loop

*comment =============CHECK EXISTENT TRAIT===============
*label check_existent
*temp check_counter 1
*label check_existent_loop
*set check_counter + 1
*if (check_counter = "\${allowed_traits+1}")
*set proceed true
*return
*else
*set proceed false
*return
*else
*goto check_existent_loop

*return

``````

To start off, let’s go over the variable creation:

``````*create trait_1 "Compassionate"
*create trait_2 "Tall"
*create trait_3 "Strong"
*create trait_4 "Pretty"
*create trait_5 "Patient"
*create trait_6 "Smart"
*create trait_7 "Diligent"
*create trait_8 "Just"
*create trait_9 "Honest"
*create trait_10 "Shy"
*create trait_11 "Young"
*create trait_12 "Greedy"
*create trait_13 "Brave"
*create trait_14 "Groomed"
*create trait_15 "Stubborn"
*create trait_16 "Fussy"
*create trait_17 "Curious"
*create trait_18 "Playful"
*create trait_19 "Quick"
*create trait_20 "Humble"
``````

This part is creating an array of 20 elements. An array is like a list that holds objects which you can get by index. To use this, you use the name of the variable and square brackets right after it. Like this: `variable[index]`.

(For a short explanation about arrays, check this video.) (In ChoiceScript arrays start at 1 unlike what he is using there though.)

For example, `trait[3]` would contain “Strong”. `trait[14]` is “Groomed”.

The good thing about this is that you can use variables for the index as well. Suppose I have a variable called `var1`:

``````*create var1 17
``````

And that `var1` equals 17. I could use this variable inside those square brackets too. If I used `trait[var1]` it would be the same as `trait[17]` which contains the “Curious” trait. This allows you to access things in your list more dynamically which will be very useful because it allows the code to accomodate however many traits you want and “loop” through the list when checks need to be made.

Now let’s see the character declaration:

``````*create char_1_1 "Michelle"
*create char_1_2 ""
*create char_1_3 ""
*create char_1_4 ""

*create char_2_1 "John"
*create char_2_2 ""
*create char_2_3 ""
*create char_2_4 ""

*create char_3_1 "Kevin"
*create char_3_2 ""
*create char_3_3 ""
*create char_3_4 ""
``````

This one might be a little more complicated to explain but I’ll try. We are going to use multidimensional arrays (in this case two-dimensional).

What we are doing here is making a character that will contain 4 things. A name and 3 trait slots. For this it’s easier to imagine a table of sorts.

The “ID” is always the number inside the first brackets. `char[THIS][]`.

The rest of the attributes (name, trait slots) would always be the things inside the second brackets. `char[][THIS]`.

And when our “table” would be filled with traits it would be like:

To get things here we would need to use two square brackets. I think to better explain this you can imagine as each block of 4 things as one character. The first square brackets will be the character’s “id” and the second set of square brackets what you want to select from it (the name or the traits).

So say I want to select John’s variable that stores his name. I would need to use `char[2][1]`. The first square brackets will go to the character in question, which in this case all attributes of John’s is of “id” number 2. If I wanted to get Kevin’s name I would use `char[3][1]` and so on.

For now the traits are empty, but say I want to see what is Michelle’s second trait, I would use `char[1][3]` since I’m going for character of “id” 1 which is Michelle and then getting the second trait slot (which is index 3 in that example). It would be empty now but it will be randomized later.

So the actual randomization is done in the `*gosub randomizer`:

``````*comment =============RANDOMIZER===============
*label randomizer
*temp new_trait 0
*temp char_counter 1
*temp trait_counter 2
*label randomizer_loop
*temp proceed false
*rand new_trait 1 trait_quantity

*if (char_counter > char_quantity)
*return
*else
*gosub check_existent char_counter new_trait
*if (trait_counter > "\${allowed_traits+1}")
*set char_counter + 1
*set trait_counter 2
*goto randomizer_loop
*else
*if (proceed)
*set char[char_counter][trait_counter] trait[new_trait]
*set trait_counter + 1
*goto randomizer_loop
*else
*goto randomizer_loop
``````

The code will use the arrays from both the trait list and the characters to randomize all traits from all characters in one swoop. It will be first a loop through all the traits of one character, then it will proceed to the next character and assign their traits and so on, as in looping through all available characters.

First what it’s doing is creating three variables:

• `new_trait` = This is the variable that will hold the randomized trait
• `char_counter` = Since we will loop through the characters, we will need a counter for the characters. This will start at 1 since the first “id” we have for our characters starts at 1.
• `trait_counter` = Since we will also loop through trait slots of a character, we need a counter for them as well. This will start at 2 because the trait slots for everyone start at index 2 (since index 1 of everybody holds their name).

Alright, after making those variables it will also create a `proceed` variable, but let’s ignore that one as it’s not important right now.

Now we apply a `*rand` to our `new_trait` variable to randomize it to a specific number between 1 and the amount of traits possible (in the example I’ve made that would be 20). So after new_trait is randomized, it will have a value between 1 to 20.

Right after that we have a big `*if` chain. The first condition is to treat the character counter, but since we didn’t fiddle with it for now, we can ignore it. Since this is the first character this won’t be passed now anyways.

The code will get inside the `*else` and it will hit the `*gosub check_existent char_counter new_trait`. What this is doing is calling the `*gosub` called `check_existent` and passing our `char_counter` variable and our `new_trait` variable as parameters. From what we saw when we created them above, their current values are 1 and something between 1-20 respectively.

That *gosub is where the trait is checked to make sure it’s not a trait the character already has.

``````*comment =============CHECK EXISTENT TRAIT===============
*label check_existent
*temp check_counter 1
*label check_existent_loop
*set check_counter + 1
*if (check_counter = "\${allowed_traits+1}")
*set proceed true
*return
*else
*set proceed false
*return
*else
*goto check_existent_loop

*return
``````

It starts by assigning both our parameters as `char_to_check` and `trait_being_added` in the same order we called them. So this `*gosub` will make these two variables in its scope:

• `char_to_check` = This is the char_counter we passed before, which equals to 1.
• `trait_being_added` = This is the new_trait variable we randomized before, which is somewhere between 1 and 20. For easier to explain purposes, let’s assume the random result was 6, which equals “Smart” in our list.

Now what we need to do is to check all the trait slots of this character to see if the character already has this trait that was just randomized. (Since this is the first trait that we are going to assign to Michelle, we could just have assigned it instead of checking but I forgot to account for that, oops! But the code will work and check it either way.)

Since we are going to be looping through the character trait slots, we need a counter for that, so we create a `check_counter`. It starts at 1 because it will be added right after +1 after our loop label, so that it starts at 2 for the first check, with 2 being the index of first slot traits for everyone.

Now we get to the first condition, `*if (check_counter = "\${allowed_traits+1}")`, this will not be triggered now because this is a condition to see if we reached the number of available slots for our characters with our counter. Since we did not yet reach that (as our counter is 2 and the allowed_traits+1 is 4, we can still run this a few times).

Since that condition will fail, we get to the `*else`, and this is where the important part is at. The following condition:

``````*else
*set proceed false
*return
*else
*goto check_existent_loop
``````

Is where we check if the trait exists in a trait slot. Let’s break it down to parts:

1. `"\$!!{char[char_to_check][check_counter]}"` = What we are getting here is the content of the variable that would be of the character, in this case we are still checking Michelle, so `char_to_check` is 1. So what we have now would be like `char[1][check_counter]`. `check_counter` is what we made in this `*gosub`, that starts at 1 and then receives +1.
``````*temp check_counter 1
*label check_existent_loop
*set check_counter + 1
``````
1. (cont) So this means our variable would be `char[1][2]` right now. This means that what’s on the left of the condition on the first run would be `char[1][2]`. So the first thing being checked in our `*if` would be this: `"\$!!{char[1][2]}"`. This is the content of Michelle’s first trat slot. Which now is empty but there will be something there in the next runs.

(OBS: You may notice there is a \$!!. This is to make sure the trait being compared is in ALL CAPS. This is better for comparisons as if a trait is typed as “Smart” or “smART” they will all be made into caps to make sure the upper or lower case doesn’t matter, but this isn’t really necessary for this code, just a little bonus.)

Now we need to decipher the second part of this `*if` condition, the `"\$!!{trait[trait_being_added]}"`.

1. `"\$!!{trait[trait_being_added]}"` = Now we are messing with the trait list, which we have 20 elements. The `trait_being_added` is a variable that we got from passing the `new_trait` as a parameter, which is our randomized one between 1 to 20. Like I said before we will consider the result of the randomization as 6. So this would be `"\$!!{trait[6]}"`. If we go into our trait list and we check what trait[6] is, it would be “Smart”.

So, in all, our condition during runtime would be:

`*if ("" = "Smart")`

The “” is because the first trait slot of Michelle (`char[1][2]`) is currently empty. So this means our condition would fail and go to the `*else`.

Now let’s see what happens after this `*if` has its result.

``````*if ("" = "Smart")
*set proceed false
*return
*else
*goto check_existent_loop
``````

If the result is:

• `true` = This means that the character already has the trait we randomized. The code will enter what is below the `*if`. It will set a variable called `proceed` as false and then `*return` (break out of the *gosub it’s in) to go back to the previous `*gosub`.
• `false` = This means that this trait slot we checked does NOT have the current trait we randomized. Beware that this is the trait SLOT, not the entire character. Since we only checked the first trait slot, we need to go back to the loop, which adds +1 to the `check_counter` so that the next slot is checked this time (as in `char[1][3]` is checked). This will make the code check the same condition again but with all traits.

If at any time in the loop this `true` condition is never reached (eventually the `check_counter` will be higher than the `allowed_traits` so we need to stop it as we checked all trait slots), this means that the character we checked does not have the trait we randomized. This means that we are now free to assign this trait. If the `true` is reached, the character already has this trait and it needs to be re-randomized again.

``````*if (check_counter = "\${allowed_traits+1}")
*set proceed true
*return
``````

The `proceed` variable is the key here, it will be set to true when we verify that this trait is not located in any of the slots.

Now we will have `*returned` to the `randomizer` `*gosub` carrying the value of our `proceed` variable.

``````	*gosub check_existent char_counter new_trait
WE ARE NOW HERE <--------------------------------
*if (trait_counter > "\${allowed_traits+1}")
*set char_counter + 1
*set trait_counter 2
*goto randomizer_loop
*else
*if (proceed)
*set char[char_counter][trait_counter] trait[new_trait]
*set trait_counter + 1
*goto randomizer_loop
*else
*goto randomizer_loop
``````

The check there is to see if we already went over the amount of traits for a character by checking this `*gosub`'s `trait_counter`, but we have not since this is still slot 2 (which there are 4). This means this condition will not yet be triggered so we enter the `*else`

``````	*else
*if (proceed)
*set char[char_counter][trait_counter] trait[new_trait]
*set trait_counter + 1
*goto randomizer_loop
*else
*goto randomizer_loop
``````

So this is when we check our `proceed` variable. If proceed is:

• `true` = It means that this randomized trait was not found in the other trait slots of this character, therefore we can now safely assign this trait to the slot we are currently working with and then continue the randomizer loop to do all this over again to the next trait slot of this character. Therefore we assign the `trait[new_trait]` (with `new_trait` being the randomized variable we got, in this case 6) to the current slot `*set char[char_counter][trait_counter]` with `char_counter` still being 1 for Michelle and the `trait_counter` being 2 since it’s our first slot. So we have `*set char[1][2] trait[6]` which would be `*set char[1][2] "Smart"`. This menans now that “Smart” is Michelle’s first trait.
• `false` = It means that the character already has the trait we randomized. So we need to go back to the loop without adding anything as it will re-do all the work for this same trait slot. It will re-randomize it again and compare if the char already has it until it manages to randomize something that the char doesn’t have.

So after all the trait slots for this character are done, then it will go to the next character and start the process again in the:

``````*if (trait_counter > "\${allowed_traits+1}")
*set char_counter + 1
*set trait_counter 2
*goto randomizer_loop
``````

By adding 1 to `char_counter` and resetting the trait_slot to randomize to 2 (which is everyone’s first trait slot). So then it would go with (`char[2][2]`) which are John’s slots and after he finishes move on to the next character.

Since this code uses loops and stuff it can fit whatever changes you want by altering those control variables (`trait_quantity`, `char_quantity` and `allowed_traits`).

This is pretty much it, hopefully I could explain it well but I do understand it’s quite complex since it’s a lot of loops with other more complicated stuff. There is a section to list all characters but it’s pretty much a loop like the previous ones; I can still explain it if anyone wishes. I can also explain the search and add it back to the code if you want (it functions very similarly with the check to see if a character already has a trait that was randomized).

9 Likes

Do you know if ChoiceScript supports removing an element from the middle of an array and shortening the array?

1 Like

Ah…I think I see.

1 Like

I’m not sure?

1 Like

Probably not; you’d have to do that manually. There’s also no “array_length” feature, which is why I added those trait, character and slot size variables.

Are thd random assigned traits for npcs absolutely necessary for plot or gameplay?

1 Like

They’re necessary for the player, as to not be predictable. My game has a lot of randomization, so even I as the creator won’t be bored easily. Other randomization is much easier. Thank you for your input on the code because that has been the simplest version for me.

1 Like

I think I’ll have to read through this several times, but thank you again. You’re the kind of coder I’d love to collaborate with, because you can turn complicated coding into an easy past time. I feel like I’ve missed many lessons on Choicescript coding in my research. I don’t think I’ve ever come across tutorials that teach everything you just wrote.

1 Like

You will hate yourself.
As you’ll have, if I understood this correctly, this for all npcs. Meaning it’d have an influence on how they talk and react?
Which in combination would mean a ton if different dialogue bits unrelated to the story or the choices.
Not to forget the combination of the traits with those choices.

2 Likes

Not how they talk. Just randomized scenes based on their traits.

1 Like

A post was merged into an existing topic: [CSIDE] The ChoiceScript IDE (v1.3.0 Now Available — 18/06/2019)