Modding:Random Functions

From Caves of Qud Wiki
Jump to navigation Jump to search
This page is about modding. See the modding overview for an abstract on modding.
This page is about modding. See the modding overview for an abstract on modding.
For best results, it's recommended to have read the following topics before this one:

If your mod has some element of randomness, you're gonna be looking for a function to call. However, calling the built in Next() function in the Random Class built into C# will net you some compilation errors. The best practice is to use the random functions inside XRL/Rules/Stat.cs. Below are the different random functions inside Caves of Qud and what they are used for.

Randoms

These are the methods that return the Random class. These are all hashed from

      Stat.Rand = new Random(Hash.String("Seed0" + (object) Seed));
      Stat.Rnd = new Random(Hash.String("Seed1" + (object) Seed));
      Stat.Rnd2 = new Random(Hash.String("Seed2" + (object) Seed));
      if (includeLifetimeSeeds)
        Stat.LevelUpRandom = new Random(Hash.String("Seed3" + (object) Seed));
      Stat.Rnd4 = new Random(Hash.String("Seed4" + (object) Seed));
      Stat.Rnd5 = new Random(Hash.String("Seed5" + (object) Seed));

Rnd()

This is the main function that randomizes and determines things such as sultan artifacts, villages, and many other things based on world seed. Using this generator or Stat.Random in a mod may cause a world seed to give different results than in vanilla.

Rnd2(), Rnd4(), Rnd5()

These functions deals with the smaller events you find in Qud.

LevelUpRandom()

The Random used to determine randomized things at level up.

GetSeededRandomGenerator(string Seed)

If you don't want to use the game's seeds in fear of altering worldseed too much, there is a helper function that returns a new random that hashes a new random. This allows your mod to be affected by world seed but does not alter the base game's random number calls.

public static Random GetSeededRandomGenerator(string Seed)
        {
            if (XRLCore.Core.Game == null)
            {
                return new Random();
            }
            return new Random(Hash.String(XRLCore.Core.Game.GetWorldSeed(null) + Seed));
        }

The Seed here should follow best practice conventions, so YourName_YourMod to avoid overlapping conflicts as much as possible.

Returners

These use a specific random class to return a multitude of things.

Random(int low, int high)

Calls Stat.Rnd()


TinkerRandom(int Low, int High)

Calls Stat.Rnd4()

GaussianRandom(float Mean, float StandardDeviation)

double num = Math.Sqrt(-2.0 * Math.Log(Stat.Rnd.NextDouble())) * Math.Sin(2.0 * Math.PI * Stat.Rnd.NextDouble());
      return (double) Mean + (double) StandardDeviation * num;

Returns a random float around the mean with a probability density of a normal distribution.

RandomCosmetic(int low, int high)

Used most often when getting random angles for particles and other cosmetic effects. Calls Stat.Rnd2().

SeededRandom(string Seed, int Low, int High)

Returns an int based on Seed, in the range of [Low, High].

Sample Random Provider for Mod

Here is a fully usable out-of-the box random number provider for your mod, which will not interfere with the game's own random seeds.

This template provides:

  • a Rand property (direct access to the Random object)
  • a Next method that returns a random number in the specified range

It also ties itself to each game's worldseed and automatically resets for new games or save loads.

using System;
using XRL;
using XRL.Core;
using XRL.Rules;

namespace MODNAME.Utilities
{
    [HasGameBasedStaticCache]
    public static class MODNAME_Random
    {
        private static Random _rand;
        public static Random Rand
        {
            get
            {
                if (_rand == null)
                {
                    if (XRLCore.Core?.Game == null)
                    {
                        throw new Exception("MODNAME mod attempted to retrieve Random, but Game is not created yet.");
                    }
                    else if (XRLCore.Core.Game.IntGameState.ContainsKey("MODNAME:Random"))
                    {
                        int seed = XRLCore.Core.Game.GetIntGameState("MODNAME:Random");
                        _rand = new Random(seed);
                    }
                    else
                    {
                        _rand = Stat.GetSeededRandomGenerator("MODNAME");
                    }
                    XRLCore.Core.Game.SetIntGameState("MODNAME:Random", _rand.Next());
                }
                return _rand;
            }
        }

        [GameBasedCacheInit]
        public static void ResetRandom()
        {
            _rand = null;
        }

        public static int Next(int minInclusive, int maxInclusive)
        {
            return Rand.Next(minInclusive, maxInclusive + 1);
        }
    }
}

Example Usage

  1. Save the code above in its own file (for example, MODNAME_Random.cs).
  2. In your other mod code files, include the following using statment: using MODNAME.Utilities;
  3. Call the code in one of the ways demonstrated below.
Get a random number between 1 and 10 (inclusive):
MODNAME_Random.Next(1, 10);
Use the Random object directly. For example, supply it to another method:
someList.ShuffleInPlace(MODNAME_Random.Rand);