Jump to content

Photo

Randomly generated gear?


  • Please log in to reply
8 replies to this topic

#1 Master Maniac

Master Maniac

    Earth, Wind, Fire, and Water.

  • Members
  • Real Name:kris

Posted 09 June 2014 - 09:59 AM

This is something I've been thinking about for a while, but I'm not sure how to script it out myself.

 

I'm sure it's possible, especially when working with scripted subscreens, so I'd like to know how to go about scripting in randomized gear drops, such as weapons or armor with randomized stats, or even stats that scale with the player's "level".

 

Allow me to elaborate. I want equippable armor that's randomly generated. I'm working in a stat system, and a leveling system. The randomized/scaled gear drops would NOT come in the form of items given by dropsets of enemies, nor will the gear be acquired from chests  and such. At the end of battles and such, the player will be given their statistics for that battle, and a list of any items acquired from the enemies they faced. This part is purely visual. Once the battle is complete, these items are added to the player's scripted inventory, and they become equippable.

 

It's an obscure thing to do in ZScript, so I have no idea how I would go about handling such a thing. Any suggestions?



#2 Avaro

Avaro

    o_o

  • Members
  • Real Name:Robin
  • Location:Germany

Posted 09 June 2014 - 10:18 AM

Basically, what you need is the rand function, to randomize the drops.

I'd like to help out more, but I think I need more insight on what the gear actually is. Is the gear available in form of items? If yes, you can use Link->Item[] = true, to add gear to Link's inventory.

#3 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 09 June 2014 - 11:03 AM

You may want to use one of my functions as a base here. You;d need to adapt it, to produce Rands for thr stats of the equipment, and possibly my reRand function.

 

One benefit of this, is that it produces a Screen-Item, so if the item has a pickup script (which can be used to set its statistics, and store them in an array), it will still execute.

 

 

These should all be in RPG.zh, if you want to view that.

 

 

 

 



#4 RetraRoyale

RetraRoyale

    Doyen(ne)

  • Members

Posted 09 June 2014 - 11:43 AM

That is one ugly function. You really shouldn't be willing to copy-paste code like that, it's really inefficient and ripe for errors. Here's how you should start to fix it:

(Also, you don't need "else {}", that's useless.)

int randItem(int list, int locX, int locY){
    
    int rollValue;
    int d100 = rollDie(100);
    rollValue = d100;
    int dropItem = -1;
    if ( list < 2 ) {
        if ( rollValue > 0 && rollValue < 6 ) { //01%-10%
            dropItem = 2;
        }
        if ( rollValue > 10 && rollValue < 16 ) { //11%-20%
            dropItem = 0;
        }
        if ( rollValue > 20 && rollValue < 23 ) { //21%-25%
            dropItem = 2;
        }
        if ( rollValue > 26 && rollValue < 29 ) { //26%-30%
            dropItem = 1;
        }
        if ( rollValue > 40 && rollValue < 42 ) { //31%-35%
            dropItem = 170;
        }
        if ( rollValue > 43 && rollValue < 46 ) { //36%-40%
            dropItem = 70;
        }
        if ( rollValue > 60 && rollValue < 62 ) { //41%-45%
            dropItem = 149;
        }
        if ( rollValue > 65 && rollValue < 67 ) { //46%-47%
            dropItem = 86;
        }
        if ( rollValue > 74 && rollValue < 76 ) { //48%-49%
            dropItem = 171;
        }
        if ( rollValue == 80 ) { //50%
            dropItem = 38;
        }
        if ( rollValue == 85 ) { //51%
            dropItem = 39;
        }
        if ( rollValue == 90 ) { //52%
            dropItem = 87;
        }
        if ( rollValue == 95 ) { //53%
            dropItem = 187;
        }
        if ( rollValue == 99 ) { //54%
            dropItem = 180;
        }
        if ( rollValue == 100 ) { //55%
            dropItem = 197;
        }

        // Drop item if there is an item to drop.
        if ( dropItem > 0 ) {
            item dropThis = Screen->CreateItem(dropItem);
            dropThis->X = locX;
            dropThis->Y = locY;
        }
    }
}
 
int reRand(int min, int max, int exclude){
        int value;
        do{
            value = Rand(min, max);
        }
            while(value < min || value == exclude);
            return value;
        }
 

item script produceReRand{
    void run(int min, int max, int exclude){
        int value = reRand(min, max, exclude);
        Trace(value);
    }
}
 

But even then, you could easily index an array for your item drops, and not even bother with all those if statements. You can use parallel arrays, for example:

 

items = {-1, 2, 0, 2, 131, 244, 16, 17}

probs = {30, 40, 50, 60, 70, 80, 90, 100}

 

Then, you grab items[prob] where prob is the index of probs with the greatest value <= your roll.

 

You should also comment your code, because reRand and list don't mean anything. (Why is list an int and not an array?)

This line is also useless:

int rollValue;
int d100 = rollDie(100);
rollValue = d100;

Why do you have a d100 variable if you never even use it? It's just wasting memory and confusing people. This is what it should say:

 

int rollValue = rollDie(100);

 

 

You also don't want to reroll random numbers, since it makes your code unstable. (I've mentioned this before...) If it takes you a billion tries to reroll a number, then you're wasting lots of time doing nothing. You should exclude numbers from a random range by shifting off the excluded numbers, not by re-rolling them. Brute force via Monte-carlo is just about the worst possible algorithm a computer can run.


Edited by RetraRoyale, 09 June 2014 - 11:49 AM.


#5 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 10 June 2014 - 01:33 AM

Actually, it's a proto-function.
 
The idea, is that the function will read a list of items, and produce probabilities from a given chart, which may have sub-probabilities.

'Tis ugly, but that's because it's incomplete...
 
One wanting to make something similar, could use it as a base, but until I have a chance to finish it, it is, what it is.
 
The purpose of using 1d100, is because that gives a flat percentage chance of any given event. Depending on the list, each event will have a specific percentage window. Those windows can be spread out, as desired, if the random number generator has any level of prejudice.
 
(I mis-read your remark: You are correct, that I'm declaring a value without necessity. That's how I write functions... I produce effects, one line at a time, and once I test everything, and know that it's working, I then condense it, if applicable. It's sort of a habit, because in some older languages, you needed to do that. i.e. Every variable was declared, and then it could be assigned. You couldn't both declare a value, and give it a value, on the same line. After a lifetime of that kind of habit, you tend to follow that procedure, even when not mandatory.
 
I'm not sure if the compiler ultimately cares though; and having a 5% increase in local variables really should matter, in this regard. Aye, doing it in one instruction is cleaner, but in some cases, it can also make source code harder to read.
 
I also didn't comment that function at all, at all. I generally do commenting last.
 
I do typically reduce things, when I'm certain they work as intended. In this case, I'm not done with the function, as I need to adjust the basic percentages, and I need to create sub-tables. I posted it here, as an example of how to make items generate statistics on pick-up... It clearly doesn't do that, but it's a method that could be converted to produce what I believe to be the desired outcome.
 
That's also why i just copy+paste'd the item creation code blocks. I was containing everything within that function, to test it; particularly the frequency of drops.
 
it's just my normal procedure; which is a bit more formulaic than what people probably do today. When I fee that this is working as desired, then, and only then, will I reduce it to its minimum constituents, move the item generation to its own function, and begin working on imported tables of item sets. Those, will by their very nature, be arrays, as that;s the most convenient way to store the information.)
 
I also by habit, declare things, in order. I find it easier to construct something, when I know the exact flow of an operation; and I generally condense it at some future point.
 
Shifting values may be ideal, but it does not work for fixed numeric probabilities. It's not just a 5% chance that event X occurs, it's a specific window, between 01 and 05, out of 100. If you needed a list with millions of excludes, that would be a problem, but a single exclude, or a small list, with the calculation capacity of a modern system, will produce a result in under one second. Further, the smaller the list, and the greater the value pool the less likely that it would be to produce an excluded value. 
 
It's theoretically possible to always produce an excluded value, but the probability of that is exponentially unprecedented. The actual probability of producing the same result is

c = (n) * ( (p) ^ (A) )

 
...where c is the number of permutations n is the number of possible vales per random set, p is the possible number of values per recurring random set, and A is the number of attempts beyond the first, to produce any result. For example:
 
 

1d10
c = (10) (10^0) , producing a number from 1-10, on the first attempt (A = 0)
c =10; 1:c = 1:10.
 
7d10
c = (10)*(10^6)
c = 10,000,000 ; 1:c - 1:10,000,000
 
3d6
c = (6)*(6^2)
c = 216
1:c = 1:216

 
The chance of producing any number of values (v) out of the possible number of values, is:

(v:c).

 
If you increase the number of excluded values (v), the probability chance remains v:c. This is necessary, when desiring, or requiring a specific number, rather than a raw probability.
 
If you roll 3d6, and are excluding 5, 24, and 11; then the probability of producing any of these values is 3:216
 

i.e. Three vales (v), and 216 chances (c).

 
You can then convert that into a statistical percentage:
 
 

 (100 / c) * v
 For the above example, (100/216) * 3 = 1.3888(recurring), or 1.39%.

 
We'll convert this to the decimal value .0139 , and assign this the value L.
 Recurring events that produce an identical result, are the value R.
 
Now, with this statistical projection, you can predict the statistical probability of needing to repeat an operation:
 
 

B = (L^R).

 
Thus, if on the first attempt, you produce one of these values (a 1.39% chance), then on the second attempt, your likelihood of again producing any of the excluded values, sequentially falls to 0.00019321, or 0.019%.
 
A third attempt, again squares this value(B), now 0.00000268561, or .000267%.
 
Continued attempts produce exponentially diminishing probabilities of the operation producing specific results.
 
Note: I'm using basic algebraic expression here, rather than proper constants/variables. I clearly don;t mean mesons, or amperes, with my uses of A and B. Ordinarily, I'd be more concise, but I feel horrible today.
 
The correct formula, would be more like this, assuming I'm not too far gone to do this using correct probabilities expressions. (Anyone who wishes to contradict, or correct these, may feel free to do thus...):
 
∑ P(A) =  ( (x1) · (x2xn) )

Where P(A) is the number of permutations x1 is the number of possible vales per random set, x2 is the possiblen umber of values per recurring random set and xn is the number of attempts, beyond the first.

 

∵ |A| : P(A)

Where |A| is the number of values, in the list of excluded values.

 

∑ E(A) =  ( ( 100 ÷ P(A) ) · |A| )

∑ E(B) = ( E(A) ÷ 100 )
∴ P(A | B) ρ  E(B)( E(B) ·xr )

Where xr is the number of times that you repeat this event.

 

∴ E(X)% = P(A | B)

 

 

I think my [ first ] above example is easier for most people to comprehend.


Edited by ZoriaRPG, 10 June 2014 - 07:01 AM.


#6 Master Maniac

Master Maniac

    Earth, Wind, Fire, and Water.

  • Members
  • Real Name:kris

Posted 10 June 2014 - 09:03 AM

Zoria, that actually may be a good method for me to start with. I'd likely simplify it, but I believe this will work just fine.

 

Also, no, the items won't take up anything in the item editor. Which sounds odd, but yeah.All of the special equipment will be on the scripted subscreen, while built-in stuff will be in the built-in subscreen.

 

Avataro, to elaborate, here's how I plan to make the gear work:

 

Each piece of gear has a few variables (I'm thinking of using a pseudo 2D array for this), to contain the ID (which type of equipment), the stat yield, and possibly another variable which determines how this item can be used.

I'm thinking maybe running a function in the subscreen scripts which adds the items graphics based on their ID's to the subscreen, but I'm not entirely sure how I want to implement them. They would be fully selectable and swappable. Again, in pseudo 2D arrays.

 

My main issue is the drops, and I may already have that worked out. Since the player won't actually pick these items up, I can simply script-add these to the inventory when the player reaches the battle stats page. Producing them was the issue though, as I wasn't sure how to go about that >.< I mean using the Rand() function was an obvious point, but I'm not sure how exactly I want it to work out. Here's an example of a basic set of gear:

 

Slot 1: Mind.

Stat: Attack power

Attunement: Random (This is the extra thing I spoke of earlier).

 

Slot 2: Body

Stat: Defense

Attunement: Random

 

Slot 3: Heart

Stat: Health

Attunement: Random

 

Slot 4: Soul

Attunement: Random

 

 

 

The Soul item determines the player's attunement. All pieces of equipment that the player equips with that soul item must match the attunement of the soul item. This allows for different stat benefits between classes.

 

EDIT: And actually, there's going to be 6 tiers of equipment slots. Each tier can hold one of each item, with the exception of the first which doesn't use a soul item. This is for a convoluted form system that i'll show off later once it's put together.

 

Is any of this making sense? I'm not very awake at the moment, sorry >.<


Edited by Master Maniac, 10 June 2014 - 09:05 AM.


#7 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 10 June 2014 - 11:17 AM

I sort of figured that you weren't going to use normal equipment; fro our earlier conversations. I wasn'tt certain mind you, but I had an idea.

 

the reason that I suggested using an item script (pick-up), is that you can use one script, when giving equipment, that does no more than run functions that store vales for attack/defence modifies, using your tatistics system, when the player picks up the item.

 

You can also do this with an FFC script; which I could make for yo in one session.

 

If you want to discuss it on Skype, i can probably create a function set to do exactly what you want to do here. I still need to work out some ideas for how I want my custom subscreens to look, and work:

 

What I was thinking of doing, assuming that you still have the time to work on this with me, is to make a .sub file for the two main screens, and a general layout for the third screen, and see if we can put together something that merges the three types.

 

I'm about to retire for today; however I'll be back in ten hours, or thereabout, if you want to discuss this.

 

P.S. if you want to simplify these kinds of functions, or expand on them, I'd be happy to accept Rand-based functions, to add to RPG.zh. I really need to work out an array-based table system, that is easy for people to use, which is the plan for the above function(s). The present model is very much a WIP, that i was testing to balance the percentage potentials.

 

I've found that a raw Rand(1,100) seems biased: Most random number generators are, which is why I spread fixed values in such a staggered manner. As a generic example, despite originally having a total of a 40% chance to drop anything, and many items having a 2% to 5% chance, I was seeing a drop rate of close to 90%, with very low probability drops occurring with greater frequency than desired.

 

I should really run a 10,000 to 50,000 spread of Rand(1,100), just to evaluate its bias.

 

I sort of comprehend the model that RR mentioned, using vale shifts, but I don't see how to use that with fixed tables. To be frank, that seems (in my mind) far more convoluted than this method.

 

As an equational example, if you have 3 1d100 values, and each excludes the number that it made from the last, the chances of producing an excluded value with reRand methods are:

 

First roll: 0%

Second roll: 1%

First re-roll, assuming a mattch on Second roll: 1% of 1% (1 in 10,000)

Second re-roll of second roll: 1% of 1^ of 1% *(1 in 1,000,000)

Third roll: 3%

First re-roll of third roll: 3% of 3%.(1 in 9,000)

Second re-roll of third roll:  (1 in 27,000 )

 

The greater the list of excludes, in ration to a small pool of numbers, is the basis for the permutations here.

 

Even assuming that you are rolling 1d2, and excluding results of 1, this is the flow:

First roll: 50% chance, of producing the excluded value.

Second roll: 25% chance of producing the excluded value.

Third roll: 12.5% chance of producing the excluded value.

Fourth roll: 6.25% chance...

Fifth roll: 3.125% chance

Sixth roll: 1.5625% chance...

Seventh roll: 0.78125% chance

Eighth roll: 0.390625% chance

Ninth roll: 0.1953125 chance.

Tenth roll: 0.09765625% chance

 

By the tenth reRand, the statistical probability drops to  ~9:1000

 

Those ten calculations occur in nanoseconds, and apply to any set of excludes, that have an initial 50% chance of selecting an exclude. By a mere twenty rolls, the chance is: 0.000095367431640625% (unless I missed a calculation, in which case, it's even lower). That;s the chance of on 1d2, rolling a 2, twenty times consecutively. (~1:100,000).

 

That calculation, also occurs in nanoseconds.

 

While it is feasible that this kind of thing may produce the same value, perpetually, the statistical probability of doing so, is so small as to be trivial. (This is how we determine bell curves.)



#8 Master Maniac

Master Maniac

    Earth, Wind, Fire, and Water.

  • Members
  • Real Name:kris

Posted 10 June 2014 - 11:30 AM

That sounds good, actually. I mean I still need to work on a lot of my underlying systems, and by the end of it the subscreen data will be directly interlaced with my other scripted mechanics (skill trees, etc). Also, skill trees are going to be a colossal pain >.< But I'll deal with that when the time comes.

 

I'll contact you later on this, and see if we can come up with some functional stuff.



#9 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 11 June 2014 - 12:51 PM

You'd need to define your skill trees for me, but they shouln't be to difficult to implement. At least, ho more than skill usage is for my projects.

It all comes down to this:

Arrays to hold current level of specific skills.
A function, to do mathematical calculations for skill checks.
Tango menus, to select skills.
FFC scripts, to allow skill checks to interact with a game environment.
Functions, to allow skill checks to interact with your custom subscreen.
alt. Tango menus, and functions therewith, to allow skill checks to interact with other Tango menus or Tango functions.

That's my basic framework for skills in LoE. I'm still working on the FFC code, and I'm working to define new functions to judge the relationship of the coordinates of the player, to objects. That will likely also include functions that I'll dump into sideView.zh, as the present method of reading the X/Y position of Link is a bit broken, because it's based on his centre, and not his absolute coordinates.

That's one of the reasons that FFC interaction is such a pain: The present collision system isn't precise, or ideal for a good many things. I do need to figure out exactly what pixel(s) define the centre of X/Y, as the tile is 16x16, so it has no true centre. I'm assuming that the central two pixels are used for this calculation, but that may not be true.


0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users