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 leading_zeroes = 32 if range ~= 0 then local remaining_range_bits = range 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 end local mask = 0xFFFFFFFF >> (leading_zeroes | 1) 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 for i=1,16 do generate_internal(output) end 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 "XRNG: Sim functions cannot be used in HUD hooks." or "XRNG: 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 "XRNG: invalid HUD state: " or "XRNG: invalid Sim state: " error(message .. tostring(token), err_level+1) end return state 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 maximum == minimum then error("XRNG: a range of 0 is invalid", err_level+1) elseif maximum < minimum and not wraparound then error("XRNG: 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("XRNG: 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("XRNG: 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("XRNG: 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("XRNG: 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("XRNG: 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 XRNG = {} function XRNG.Hud_Create(a, b) return user_create(true, a, b, 0) end function XRNG.Hud_Destroy(token) return user_destroy(true, token, 0) end function XRNG.Hud_GetFixed(token) return generate_internal(token_to_state(token, true, 1)) & 0xFFFF end function XRNG.Hud_GetByte(token) return generate_internal(token_to_state(token, true, 1)) & 0xFF end function XRNG.Hud_GetSigned(token) return (generate_internal(token_to_state(token, true, 1)) & 0xFF) - 128 end function XRNG.Hud_GetInt32(token) return generate_internal(token_to_state(token, true, 1)) end function XRNG.Hud_GetKey(token, range) return user_key(token, true, range, 0) end function XRNG.Hud_GetZeroToLimit(token, limit) return user_limit(token, true, limit, 0) end function XRNG.Hud_GetRange(token, minimum, maximum, wraparound) return user_between(token, true, minimum, maximum, wraparound, 0) end function XRNG.Hud_GetApproxNormal(token, iterations) return user_normal(token, true, iterations, 0) end function XRNG.Hud_Shuffle(token, shuffle_table) return user_shuffle(token, true, shuffle_table, 0) end function XRNG.Sim_Create(a, b) return user_create(false, a, b, 0) end function XRNG.Sim_Destroy(token) return user_destroy(false, token, 0) end function XRNG.Sim_GetFixed(token) return generate_internal(token_to_state(token, false, 1)) & 0xFFFF end function XRNG.Sim_GetByte(token) return generate_internal(token_to_state(token, false, 1)) & 0xFF end function XRNG.Sim_GetSigned(token) return (generate_internal(token_to_state(token, false, 1)) & 0xFF) - 128 end function XRNG.Sim_GetInt32(token) return generate_internal(token_to_state(token, false, 1)) end function XRNG.Sim_GetKey(token, range) return user_key(token, false, range, 0) end function XRNG.Sim_GetZeroToLimit(token, limit) return user_limit(token, false, limit, 0) end function XRNG.Sim_GetRange(token, minimum, maximum, wraparound) return user_between(token, false, minimum, maximum, wraparound, 0) end function XRNG.Sim_GetApproxNormal(token, iterations) return user_normal(token, false, iterations, 0) end function XRNG.Sim_Shuffle(token, shuffle_table) return user_shuffle(token, false, shuffle_table, 0) end rawset(_G,"XRNG",XRNG)