Randomised Char Class Stats

by Glidias
A way to randomise/automate/determine characters' stats progression in a tactics/strategy RPG.
Testing random character stat progression based off character class training weights.
♥0 | Line 137 | Modified 2015-07-19 23:43:55 | MIT License
play

ActionScript3 source code

/**
 * Copyright Glidias ( http://wonderfl.net/user/Glidias )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/nJf1
 */

package 
{
    import com.bit101.components.HBox;
    import com.bit101.components.Label;
    import com.bit101.components.NumericStepper;
    import com.bit101.components.VBox;
   // import de.polygonal.math.PM_PRNG;
    import flash.display.Sprite;
    import flash.events.Event;
    /**
     * A way to randomise characters' stats in a tactics/strategy RPG.
     * Testing random character stat progression based off character class weights.
     * @author Glenn Ko
     */
    public class RandCharacterProgressionTest extends Sprite
    {
        
        
        /* // Character class: Pirate Skirmisher 
        private var className:String  = "Pirate Skirmisher";
        private var weights:Array = [
        .75, // Strength
        2, // Dexterity
        .75, // Constitution
        1, // Speed
        1, // Perception
        .25  // Intelligence
        ]
        
         // starting level 1 bonuses
        private var bonuses:Array = [ 
        0, // Strength
        2, // Dexterity
        0, // Constitution
        2, // Speed
        1, // Perception
        0  // Intelligence
        ]

        */
        
        /* // Character class: Indigenous Native 
        private var className:String  = "Indigenous Native";
        private var weights:Array = [
        .7, // Strength
        1, // Dexterity
        .25, // Constitution
        1, // Speed
        .7, // Perception
        2  // Intelligence
        ]
        
         // starting level 1 bonuses
        private var bonuses:Array = [ 
        0, // Strength
        1, // Dexterity
        0, // Constitution
        2, // Speed
        0, // Perception
        2  // Intelligence
        ]

        */

        ///* // Character class: Knight
        private var className:String  = "Knight";
        private var weights:Array = [
        2.5, // Strength
        1, // Dexterity
        1.5, // Constitution
        .3 // Speed
        .5, // Perception
        .5  // Intelligence
        ]
        
         // starting level 1 bonuses
        private var bonuses:Array = [ 
        3, // Strength
        0, // Dexterity
        2, // Constitution
        0, // Speed
        0, // Perception
        0  // Intelligence
        ]

        //*/
        
        
        
        // -------------------------------
        
        private var statLabels:Array = [
        "Strength",
        "Dexterity",
        "Constitution",
        "Speed",
        "Perception",
        "Intelligence"
        ];
        
        private var startingBaseValues:Array = [
        5, // Strength
        5, // Dexterity
        5, // Constitution
        5, // Speed
        5, // Perception
        5  // Intelligence
        ]
        
        private var curValues:Vector.<Number> = new Vector.<Number>(statLabels.length, true);
        
        private var curValueDisplays:Array = [];
        
        private var levelStepper:NumericStepper;
        
        private var randSeed:int = Math.random()*PM_PRNG.MAX;
        private var _statDisplay:VBox;
        
        private var prng:PM_PRNG = new PM_PRNG();
        private var WEIGHTS_TOTAL:Number;
        
        
        
        public function RandCharacterProgressionTest() 
        {
            new Label(this, 0, 0, className+" | Level:");
            levelStepper = new NumericStepper(this, 35, 15, onLevelStepped);
            levelStepper.minimum = 1;
            levelStepper.maximum = 20;
            levelStepper.value = 1;
            
            
            _statDisplay = new VBox(this,5, 37);
            for (var i:int = 0; i < statLabels.length; i++) {
                curValueDisplays.push( getStatDisplay( statLabels[i] ) );
            }
            
            onCharacterChange();
            onLevelStepped();
        }
        
        private function onCharacterChange():void 
        {
            recalculateWeights();
        }
        
         private function recalculateWeights():void {
            var weight:Number;
            var i:int;
            var numUndeclaredWeights:Number = 0;
            var totalDeclaredWeight:Number = 0;
            for (i = 0; i < statLabels.length; i++) {
                weight = weights[i];
               
                 totalDeclaredWeight += weight;
                
            }
            
            WEIGHTS_TOTAL = totalDeclaredWeight;
        }
        
        
         private function getRandomIndex(randRatio:Number, weights:Array ):int {
           // return floatRatio * raceNum + 1;
           randRatio *= WEIGHTS_TOTAL;
           
           
            var accum:Number = 0;
            var result:int = 0;
            
            for (var i:int = 0; i < weights.length; i++) {    
                if (randRatio < accum) {  // did not meet requirement
                    break;
                }
                accum += weights[i];
                result = i;
            }
            
            return result;
        
        }
        
        private function getStatDisplay(labelTxt:String):Label {
            var hBox:HBox = new HBox(_statDisplay);
            new Label(hBox, 0, 0, labelTxt +": ");
            hBox.height = 16;
            return new Label(hBox, 0, 0, "-");
            
        }
        
        private function onLevelStepped(e:Event=null):void 
        {
            var i:int;
            var levelsProgressed:int = levelStepper.value - 1;
            prng.setSeed(randSeed);
            var len:int; 
            
            
        
            len = statLabels.length;
            for (i = 0; i < len; i++) {
                curValues[i] = startingBaseValues[i] + bonuses[i];
            }
            
            
            for (i = 0; i < levelsProgressed; i++) {
                curValues[ getRandomIndex(prng.nextDouble() , weights) ]++;
            }
            
            
            for (i = 0; i < len; i++) {
                curValueDisplays[i].text = String(curValues[i]);
            }
            
        }
        
    }

}

/*
 * Copyright (c) 2009 Michael Baczynski, http://www.polygonal.de
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * Implementation of the Park Miller (1988) "minimal standard" linear 
 * congruential pseudo-random number generator.
 * 
 * For a full explanation visit: http://www.firstpr.com.au/dsp/rand31/
 * 
 * The generator uses a modulus constant (m) of 2^31 - 1 which is a
 * Mersenne Prime number and a full-period-multiplier of 16807.
 * Output is a 31 bit unsigned integer. The range of values output is
 * 1 to 2,147,483,646 (2^31-1) and the seed must be in this range too.
 * 
 * David G. Carta's optimisation which needs only 32 bit integer math,
 * and no division is actually *slower* in flash (both AS2 & AS3) so
 * it's better to use the double-precision floating point version.
 * 
 * @author Michael Baczynski, www.polygonal.de
 */

     class PM_PRNG
    {
        /**
         * set seed with a 31 bit unsigned integer
         * between 1 and 0X7FFFFFFE inclusive. don't use 0!
         */
        public var seed:uint;
        
        public static const MAX:uint = 0X7FFFFFFE;
        
        public function PM_PRNG()
        {
            seed = 1;
        }
        
        /**
         * provides the next pseudorandom number
         * as an unsigned integer (31 bits)
         */
        public function nextInt():uint
        {
            return gen();
        }
        
        /**
         * provides the next pseudorandom number
         * as a float between nearly 0 and nearly 1.0.
         */
        public function nextDouble():Number
        {
            
            return (gen() / 2147483647);
        }
        
        /**
         * provides the next pseudorandom number
         * as an unsigned integer (31 bits) betweeen
         * a given range.
         */
        public function nextIntRange(min:Number, max:Number):uint
        {
            min -= .4999;
            max += .4999;
            return Math.round(min + ((max - min) * nextDouble()));
        }
        
        /**
         * provides the next pseudorandom number
         * as a float between a given range.
         */
        public function nextDoubleRange(min:Number, max:Number):Number
        {
            return min + ((max - min) * nextDouble());
        }
        
        public function setSeed(v:uint):void 
        {
            if (v == 0) throw new Error("Seed value cannot be zero!");
            if (v > MAX)  throw new Error("Seed cannot exceed max:"+seed+" /" + MAX);
            seed = v;
        }
        
        /**
         * generator:
         * new-value = (old-value * 16807) mod (2^31 - 1)
         */
        private function gen():uint
        {
            //integer version 1, for max int 2^46 - 1 or larger.
        
            return seed = (seed * 16807) % 2147483647;
            
            /**
             * integer version 2, for max int 2^31 - 1 (slowest)
             */
            //var test:int = 16807 * (seed % 127773 >> 0) - 2836 * (seed / 127773 >> 0);
            //return seed = (test > 0 ? test : test + 2147483647);
            
            /**
             * david g. carta's optimisation is 15% slower than integer version 1
             */
            //var hi:uint = 16807 * (seed >> 16);
            //var lo:uint = 16807 * (seed & 0xFFFF) + ((hi & 0x7FFF) << 16) + (hi >> 15);
            //return seed = (lo > 0x7FFFFFFF ? lo - 0x7FFFFFFF : lo);
        }
    }