local sim_states = {} local sim_state_counter = 1 local hud_states = {} setmetatable(hud_states, {__mode='k'}) local unpack = unpack addHook('NetVars', function(sync) sim_states = sync(sim_states) sim_state_counter = sync(sim_state_counter) end) local function generate_internal(real_state) local a, b, c, counter = unpack(real_state) local result = a + b + counter real_state[1] = b ^^ (b >> 9) real_state[2] = c + (c << 3) real_state[3] = ((c << 21) | (c >> 11)) + result real_state[4] = counter + 1 return result end local function generate_many_internal(real_state, count) local a, b, c, counter = unpack(real_state) local output = {} for i=1,count do local result = a + b + counter counter = counter + 1 a = b ^^ (b >> 9) b = c + (c << 3) c = ((c << 21) | (c >> 11)) + result output[i] = result end real_state[1] = a real_state[2] = b real_state[3] = c real_state[4] = counter return output end local function generate_bounded_internal(real_state, range) if range == 0 or range == 1 then return 0 end range = $ - 1 local remaining_range_bits = range | 1 local leading_zeroes = 0 if not (remaining_range_bits & 0xFFFF0000) then leading_zeroes = $ + 16 remaining_range_bits = $ << 16 end if not (remaining_range_bits & 0xFF000000) then leading_zeroes = $ + 8 remaining_range_bits = $ << 8 end if not (remaining_range_bits & 0xF0000000) then leading_zeroes = $ + 4 remaining_range_bits = $ << 4 end if not (remaining_range_bits & 0xC0000000) then leading_zeroes = $ + 2 remaining_range_bits = $ << 2 end if not (remaining_range_bits & 0x80000000) then leading_zeroes = $ + 1 end local mask = 0xFFFFFFFF >> leading_zeroes local range_high_bit = range < 0 local result local result_is_valid local a, b, c, counter = unpack(real_state) repeat result = a + b + counter counter = counter + 1 a = b ^^ (b >> 9) b = c + (c << 3) c = ((c << 21) | (c >> 11)) + result result = $ & mask local result_high_bit = result < 0 if range_high_bit ~= result_high_bit then result_is_valid = range_high_bit else local value_mask = 0x7FFFFFFF result_is_valid = (result & value_mask) <= (range & value_mask) end until result_is_valid real_state[1] = a real_state[2] = b real_state[3] = c real_state[4] = counter return result end local function create_state_internal(seed_a, seed_b) local output = {} output[1] = 0 output[2] = seed_b or 0xDEAD5EED output[3] = seed_a output[4] = 1 generate_many_internal(output, 16) return output end local function generate_between_internal(real_state, minimum, maximum) local difference = maximum - minimum if difference == 0xFFFFFFFF then return generate_internal(real_state) end return generate_bounded_internal(real_state, difference+1) + minimum end local function shuffle_internal(real_state, array) local array_size = #array if array_size > 1 then for item1=array_size, 2, -1 do local item2 = 1+generate_bounded_internal(real_state,item1-1) array[item1], array[item2] = $2, $1 end end end local function generate_normal_internal(real_state, degree) degree = ($ and $ > 6) and $ or 6 local deviates = generate_many_internal(real_state, degree) local final_sample = 0 local mask_and_limit = 65535 for i=1,degree do local deviate = deviates[i] final_sample = final_sample + (deviate & mask_and_limit) + (deviate >> 16) end return final_sample - (degree*mask_and_limit) end local function hud_check(hud_mode, err_level) local in_hud = not pcall(S_IdPlaying, 0) if in_hud ~= hud_mode then local message = hud_mode and "FlowerRNG: Sim functions cannot be used in HUD hooks." or "FlowerRNG: HUD functions cannot be used outside HUD hooks." error(message, err_level+1) end end local function token_to_state(token, hud_mode, err_level) hud_check(hud_mode, err_level + 1) local state_table = hud_mode and hud_states or sim_states local state = state_table[token] if not state then local message = hud_mode and "FlowerRNG: invalid HUD state: " or "FlowerRNG: invalid Sim state: " error(message .. tostring(token), err_level+1) end return state end local function user_int32_array(token, hud_mode, count, err_level) local state = token_to_state(token, hud_mode, err_level+1) if type(count) ~= 'number' then error("FlowerRNG: count must be a number", err_level+1) elseif count < 1 then error("FlowerRNG: count must be 1 or greater", err_level+1) else return generate_many_internal(state, count) end end local function user_between(token, hud_mode, minimum, maximum, wraparound, err_level) local state = token_to_state(token, hud_mode, err_level+1) if type(minimum) ~= 'number' or type(maximum) ~= 'number' then error("FlowerRNG: minimum and maximum must both be numbers", err_level+1) elseif maximum == minimum then error("FlowerRNG: a range of 0 is invalid", err_level+1) elseif maximum < minimum and not wraparound then error("FlowerRNG: wraparound is required if maximum < minimum", err_level+1) else return generate_between_internal(state, minimum, maximum) end end local function user_limit(token, hud_mode, range, err_level) local state = token_to_state(token, hud_mode, err_level+1) if type(range) ~= 'number' then error("FlowerRNG: limit must be a number", err_level+1) end if range < 0 then return generate_between_internal(state, range, 0) else return generate_bounded_internal(state, range+1) end end local function user_key(token, hud_mode, range, err_level) local state = token_to_state(token, hud_mode, err_level+1) if type(range) ~= 'number' then error("FlowerRNG: range must be a number", err_level+1) end return generate_bounded_internal(state, range) end local function user_normal(token, hud_mode, iterations, err_level) local state = token_to_state(token, hud_mode, err_level+1) local iterations_type = type(iterations) if iterations_type ~= 'number' and iterations_type ~= 'nil' then error("FlowerRNG: iterations must be a number or nil", err_level+1) end return generate_normal_internal(state, range) end local function user_shuffle(token, hud_mode, shuffle_table, err_level) local state = token_to_state(token, hud_mode, err_level+1) if type(shuffle_table) ~= 'table' then error("FlowerRNG: shuffle_table must be a table", err_level+1) end shuffle_internal(state, shuffle_table) end local function user_create(hud_mode, seed_a, seed_b, err_level) hud_check(hud_mode, err_level + 1) if type(seed_a) ~= 'number' or (seed_b ~= nil and type(seed_b) ~= 'number') then error("FlowerRNG: seeds must be numbers", err_level+1) end local token local state = create_state_internal(seed_a, seed_b) if hud_mode then token = {} hud_states[token] = state else token = sim_state_counter sim_state_counter = $ + 1 sim_states[token] = state end return token end local function user_destroy(hud_mode, token, err_level) local state = token_to_state(token, hud_mode, err_level+1) if hud_mode then if hud_states[token] then hud_states[token] = nil end else if sim_states[token] then sim_states[token] = nil end end end local FRNG = {} function FRNG.Hud_Create(a, b) return user_create(true, a, b, 1) end function FRNG.Hud_Destroy(token) return user_destroy(true, token, 1) end function FRNG.Hud_GetFixed(token) return generate_internal(token_to_state(token, true, 2)) & 0xFFFF end function FRNG.Hud_GetByte(token) return generate_internal(token_to_state(token, true, 2)) & 0xFF end function FRNG.Hud_GetSigned(token) return (generate_internal(token_to_state(token, true, 2)) & 0xFF) - 128 end function FRNG.Hud_GetInt32(token) return generate_internal(token_to_state(token, true, 2)) end function FRNG.Hud_GetInt32Array(token, count) return user_int32_array(token, true, count, 1) end function FRNG.Hud_GetKey(token, range) return user_key(token, true, range, 1) end function FRNG.Hud_GetZeroToLimit(token, limit) return user_limit(token, true, limit, 1) end function FRNG.Hud_GetRange(token, minimum, maximum, wraparound) return user_between(token, true, minimum, maximum, wraparound, 2) end function FRNG.Hud_GetApproxNormal(token, iterations) return user_normal(token, true, iterations, 1) end function FRNG.Hud_Shuffle(token, shuffle_table) return user_shuffle(token, true, shuffle_table, 1) end function FRNG.Sim_Create(a, b) return user_create(false, a, b, 1) end function FRNG.Sim_Destroy(token) return user_destroy(false, token, 1) end function FRNG.Sim_GetFixed(token) return generate_internal(token_to_state(token, false, 2)) & 0xFFFF end function FRNG.Sim_GetByte(token) return generate_internal(token_to_state(token, false, 2)) & 0xFF end function FRNG.Sim_GetSigned(token) return (generate_internal(token_to_state(token, false, 2)) & 0xFF) - 128 end function FRNG.Sim_GetInt32(token) return generate_internal(token_to_state(token, false, 2)) end function FRNG.Sim_GetInt32Array(token, count) return user_int32_array(token, false, count, 1) end function FRNG.Sim_GetKey(token, range) return user_key(token, false, range, 1) end function FRNG.Sim_GetZeroToLimit(token, limit) return user_limit(token, false, limit, 1) end function FRNG.Sim_GetRange(token, minimum, maximum, wraparound) return user_between(token, false, minimum, maximum, wraparound, 1) end function FRNG.Sim_GetApproxNormal(token, iterations) return user_normal(token, false, iterations, 1) end function FRNG.Sim_Shuffle(token, shuffle_table) return user_shuffle(token, false, shuffle_table, 1) end function FRNG.GetVersion() return {2, 0, 0} end rawset(_G,"FRNG",FRNG)