|
extends Node2D |
|
|
|
func round_to_dec(num, digit): |
|
return round(num * pow(10.0, digit)) / pow(10.0, digit) |
|
|
|
const ACTION_CLUES = [ |
|
"CLUE_ACTION_ROCK", |
|
"CLUE_ACTION_CRATE", |
|
"CLUE_ACTION_DASH", |
|
"CLUE_ACTION_MAGNETISM", |
|
"CLUE_ACTION_JUMP_3", |
|
"CLUE_ACTION_FACE_4_DIRECTIONS", |
|
"CLUE_ACTION_NIGHT", |
|
"CLUE_ACTION_MAP_3", |
|
"CLUE_ACTION_ITEM_3", |
|
] |
|
|
|
var locations: Array |
|
var kayleigh_loot_table = preload("res://data/loot_tables/chest_kayleigh_home.tres") |
|
var misc_loot_table = preload("res://data/loot_tables/chest_misc.tres") |
|
var station_loot_table = preload("res://data/loot_tables/chest_station.tres") |
|
var kayleigh = preload("res://data/characters/kayleigh.tres") |
|
var bootleg_house_table = preload("res://data/monster_spawn_profiles/harbourtown_bootleg_tutorial.tres") |
|
|
|
func generate_all_chests(n: int): |
|
var keys = CHESTS_TO_GENERATE.keys() |
|
var values = CHESTS_TO_GENERATE.values() |
|
var output = {} |
|
|
|
for index in CHESTS_TO_GENERATE.size(): |
|
var chest_def = values[index] |
|
|
|
var chest = GenTools.gen_chest( |
|
chest_def.get("loot_table", misc_loot_table), |
|
n, |
|
chest_def.get("key"), |
|
chest_def.get("loot_value", 100), |
|
chest_def.get("force_rarity_upgrade", false) |
|
) |
|
|
|
output[keys[index]] = chest |
|
|
|
return output |
|
|
|
func test_items(n: int): |
|
var results = generate_all_chests(n) |
|
|
|
var all_loot = [] |
|
|
|
for result in results.values(): |
|
all_loot += result |
|
|
|
var has_all_items = GenTools.does_chest_contain_sticker(all_loot, "Custom Starter") && GenTools.does_chest_contain_sticker(all_loot, "ITEM_TAPE_PLANT_NAME") # && does_chest_contain_sticker(all_loot, "ITEM_TAPE_LIGHTNING_NAME") |
|
|
|
return has_all_items |
|
|
|
func generate_seed(n: int): |
|
var arch_location = Random.new(Random.child_seed(n, "story_end_location")).choice(locations).clue_location |
|
var arch_ritual = Random.new(Random.child_seed(n, "clue_action")).choice(ACTION_CLUES) |
|
|
|
#if arch_location in DISALLOWED_MIRROR_LOCATIONS: |
|
# continue |
|
|
|
var seed_value = n #str(n).hash() |
|
var date = 0 |
|
var rand = Random.new(Random.child_seed(seed_value ^ (date * 12), "items")) |
|
|
|
SaveState.item_rand = rand |
|
var sirenade = GenTools.gen_character(kayleigh) |
|
# var katelly = gen_character(preload("res://data/characters/meredith.tres")) |
|
# var clocksly = gen_character(preload("res://data/characters/eugene.tres")) |
|
# var brushroom = gen_character(preload("res://data/characters/felix.tres")) |
|
|
|
var is_spit_relevant = GenTools.does_sticker_contain_attribute(sirenade.stickers[0], ["Spit", "Smack"]) |
|
|
|
if !is_spit_relevant: |
|
return false |
|
|
|
print(n, " (", arch_location, " - ", arch_ritual, "): ") |
|
for sticker in sirenade.stickers: |
|
if sticker.rarity > 0: |
|
GenTools.print_sticker(sticker, " Sirenade - ") #, str(n) + ": ") |
|
# for sticker in brushroom.stickers: |
|
# if sticker.rarity > 0: |
|
# print_sticker(sticker, " Brushroom - ") #, str(n) + ": ") |
|
|
|
var chest_results = generate_all_chests(n) |
|
var chest_result_keys = chest_results.keys() |
|
var chest_result_values = chest_results.values() |
|
for n in chest_results.size(): |
|
GenTools.print_chest(chest_result_values[n], " " + chest_result_keys[n] + " - ") |
|
|
|
return true |
|
|
|
var THREAD_COUNT = 10 |
|
var BATCH_SIZE = 1 |
|
|
|
var START_SEED = 2172531 |
|
var END_SEED = 2202532 |
|
|
|
var DISALLOWED_MIRROR_LOCATIONS = ["CLUE_OVERWORLD_-4_-1", "CLUE_OVERWORLD_-6_-3", "CLUE_OVERWORLD_0_-6", "CLUE_OVERWORLD_1_-6", "CLUE_OVERWORLD_7_-2"] |
|
|
|
var CHESTS_TO_GENERATE = { |
|
"Harbourtown Station Chest": { "key": "harbourtown_station_chest1", "loot_table": station_loot_table}, |
|
"Overworld 1, -1 Chest": { "key": "overworld_1_-1_chest" }, |
|
"Overworld 2, -6 Chest": { "key": "overworld_2_-6_chest" }, |
|
"Overworld 2, -3 Chest": { "key": "chest_overworld_2_-3" }, |
|
"Overworld 2, -4 Chest": { "key": "chest_overworld_2_-4" }, |
|
"Overworld -1, -6 Chest 1": { "key": "overworld_-1_-6_chest_1" }, |
|
"Overworld -1, -6 Chest 2": { "key": "overworld_-1_-6_chest_2" }, |
|
"Overworld -1, -7 Chest 1": { "key": "overworld_-1_-7_chest_1" }, |
|
"Overworld 0, -7 Chest": { "key": "chest_overworld_0_-7" }, |
|
"Kayleigh Chest": { "key": "chest_kayleigh_home", "loot_table": kayleigh_loot_table, "force_rarity_upgrade": true, "loot_value": 1000 } |
|
} |
|
var current_seed: int |
|
var has_alerted_end = false |
|
var seeds_with_required_items = [] |
|
var seeds_with_results = [] |
|
var threads = [] |
|
var threads_completed = 0 |
|
var start_time: int |
|
|
|
var index_mutex: Mutex |
|
var results_mutex: Mutex |
|
|
|
func _ready(): |
|
BattleMoves.setup() |
|
|
|
locations = Datatables.load("res://data/story_end_locations").table.values() |
|
|
|
current_seed = START_SEED |
|
|
|
start_time = OS.get_ticks_usec() |
|
|
|
index_mutex = Mutex.new() |
|
results_mutex = Mutex.new() |
|
|
|
for n in THREAD_COUNT: |
|
var thread = Thread.new() |
|
threads.push_back(thread) |
|
thread.start(self, "_thread_process") |
|
|
|
|
|
func _thread_process(): |
|
while true: |
|
index_mutex.lock() |
|
var index = current_seed |
|
current_seed += BATCH_SIZE |
|
index_mutex.unlock() |
|
|
|
if index > END_SEED: |
|
results_mutex.lock() |
|
threads_completed += 1 |
|
results_mutex.unlock() |
|
break |
|
|
|
for n in range(index, index + BATCH_SIZE): |
|
if test_items(n): |
|
results_mutex.lock() |
|
seeds_with_required_items.push_front(n) |
|
results_mutex.unlock() |
|
|
|
func _process(delta: float): |
|
var progress_pct = round_to_dec(((current_seed - START_SEED) as float / (END_SEED - START_SEED) as float) * 100, 2) |
|
$SeedResults/CurrentSeedLabel.text = "Current seed: " + str(current_seed) + " (" + str(progress_pct) + "%)" |
|
|
|
if seeds_with_required_items.size() > 0: |
|
var possible_seed = seeds_with_required_items.pop_front() |
|
if generate_seed(possible_seed): |
|
seeds_with_results.push_front(str(possible_seed)) |
|
$SeedResults/SeedsWithResultsLabel.text = "Valid seeds: " + PoolStringArray(seeds_with_results).join(", ") |
|
|
|
if threads_completed == THREAD_COUNT && seeds_with_required_items.size() == 0: |
|
var duration = OS.get_ticks_usec() - start_time |
|
var total_seeds = END_SEED - START_SEED |
|
var usec_per_seed = duration / total_seeds |
|
var seeds_per_sec = 1000000 / usec_per_seed |
|
print("Seed generation finished in ", (duration / 1000000), " seconds (", total_seeds, " seeds tried, avg ", usec_per_seed, " usec per seed / ", seeds_per_sec, " seeds per second)") |
|
|
|
for thread in threads: |
|
thread.wait_to_finish() |
|
|
|
threads.clear() |
|
set_process(false) |
|
|