mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-12 01:43:40 +00:00
* Allows languages to weight the likelihood of certain syllables, refactors certain code related to pick_weight() (#71275) ## About The Pull Request This PR does the following: - Defines a new proc in __HELPERS/_lists.dm called `pick_weight_recursive()`. This is the code from `/obj/effect/spawner/random/` that allows for nested weighted lists, moved to its own proc. - Replaces explicit code in spawners/random.dm with calls to `pick_weight_recursive()` where appropriate - Deletes the redundant (and barely used) proc `/obj/item/loot_table_maker/proc/pick_loot`, as this was equivalent to `pick_weight_recursive()` - Moves the global proc `fill_with_ones()` from spawners/random.dm to __HELPERS/_lists.dm - Replaces `pick()` in language syllable selection with `pick_weight_recursive()`, allowing languages to define syllable weights or use nested lists of syllables. - Reformats Galactic Common to use nested lists of syllables, allowing English and Chinese syllables to occur at equal frequency despite having different numbers of each. ## Why It's Good For The Game Allowing languages to define syllable weights and nested groups of syllables is a relatively small change that greatly expands what you can do with them. In addition to making Galactic Common look nicer in code, this change also allows for the easy creation of languages with highly uneven syllable distributions (including ultra-rare secret syllables, perhaps) or the quick creation of pidgin languages that combine multiple syllable sets. Using a new proc simplifies spawner code by reducing repetition. Making it global allows for other code to easily implement the same flexible and elegant system of nested lists that spawners already use. ## Changelog 🆑 refactor: defines a new global proc, pick_weight_recursive() code: languages can weight syllables, and galactic common's definition is easier to look at /🆑 Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com> * Allows languages to weight the likelihood of certain syllables, refactors certain code related to pick_weight() Co-authored-by: skylord-a52 <skylord-a52@users.noreply.github.com> Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com>
133 lines
4.6 KiB
Plaintext
133 lines
4.6 KiB
Plaintext
/**
|
|
* Base class for all random spawners.
|
|
*/
|
|
/obj/effect/spawner/random
|
|
icon = 'icons/effects/random_spawners.dmi'
|
|
icon_state = "loot"
|
|
layer = OBJ_LAYER
|
|
/// Stops persistent lootdrop spawns from being shoved into lockers
|
|
anchored = TRUE
|
|
/// A list of possible items to spawn e.g. list(/obj/item, /obj/structure, /obj/effect)
|
|
var/list/loot
|
|
/// The subtypes AND type to combine with the loot list
|
|
var/loot_type_path
|
|
/// The subtypes (this excludes the provided path) to combine with the loot list
|
|
var/loot_subtype_path
|
|
/// How many items will be spawned
|
|
var/spawn_loot_count = 1
|
|
/// If the same item can be spawned twice
|
|
var/spawn_loot_double = TRUE
|
|
/// Whether the items should be distributed to offsets 0,1,-1,2,-2,3,-3.. This overrides pixel_x/y on the spawner itself
|
|
var/spawn_loot_split = FALSE
|
|
/// Whether the spawner should spawn all the loot in the list
|
|
var/spawn_all_loot = FALSE
|
|
/// The chance for the spawner to create loot (ignores spawn_loot_count)
|
|
var/spawn_loot_chance = 100
|
|
/// Determines how big of a range (in tiles) we should scatter things in.
|
|
var/spawn_scatter_radius = 0
|
|
/// Whether the items should have a random pixel_x/y offset (maxium offset distance is ±16 pixels for x/y)
|
|
var/spawn_random_offset = FALSE
|
|
|
|
/obj/effect/spawner/random/Initialize(mapload)
|
|
. = ..()
|
|
spawn_loot()
|
|
|
|
///If the spawner has any loot defined, randomly picks some and spawns it. Does not cleanup the spawner.
|
|
/obj/effect/spawner/random/proc/spawn_loot(lootcount_override)
|
|
if(!prob(spawn_loot_chance))
|
|
return
|
|
|
|
var/list/spawn_locations = get_spawn_locations(spawn_scatter_radius)
|
|
var/spawn_loot_count = isnull(lootcount_override) ? src.spawn_loot_count : lootcount_override
|
|
|
|
if(spawn_all_loot)
|
|
spawn_loot_count = INFINITY
|
|
spawn_loot_double = FALSE
|
|
|
|
if(loot_type_path)
|
|
loot += typesof(loot_type_path)
|
|
|
|
if(loot_subtype_path)
|
|
loot += subtypesof(loot_subtype_path)
|
|
|
|
if(loot?.len)
|
|
var/loot_spawned = 0
|
|
while((spawn_loot_count-loot_spawned) && loot.len)
|
|
var/lootspawn = pick_weight_recursive(loot)
|
|
if(!spawn_loot_double)
|
|
loot.Remove(lootspawn)
|
|
if(lootspawn && (spawn_scatter_radius == 0 || spawn_locations.len))
|
|
var/turf/spawn_loc = loc
|
|
if(spawn_scatter_radius > 0)
|
|
spawn_loc = pick_n_take(spawn_locations)
|
|
|
|
var/atom/movable/spawned_loot = make_item(spawn_loc, lootspawn)
|
|
spawned_loot.setDir(dir)
|
|
|
|
if (!spawn_loot_split && !spawn_random_offset)
|
|
if (pixel_x != 0)
|
|
spawned_loot.pixel_x = pixel_x
|
|
if (pixel_y != 0)
|
|
spawned_loot.pixel_y = pixel_y
|
|
else if (spawn_random_offset)
|
|
spawned_loot.pixel_x = rand(-16, 16)
|
|
spawned_loot.pixel_y = rand(-16, 16)
|
|
else if (spawn_loot_split)
|
|
if (loot_spawned)
|
|
spawned_loot.pixel_x = spawned_loot.pixel_y = ((!(loot_spawned%2)*loot_spawned/2)*-1)+((loot_spawned%2)*(loot_spawned+1)/2*1)
|
|
loot_spawned++
|
|
|
|
/**
|
|
* Makes the actual item related to our spawner.
|
|
*
|
|
* spawn_loc - where are we spawning it?
|
|
* type_path_to_make - what are we spawning?
|
|
**/
|
|
/obj/effect/spawner/random/proc/make_item(spawn_loc, type_path_to_make)
|
|
return new type_path_to_make(spawn_loc)
|
|
|
|
///If the spawner has a spawn_scatter_radius set, this creates a list of nearby turfs available
|
|
/obj/effect/spawner/random/proc/get_spawn_locations(radius)
|
|
var/list/scatter_locations = list()
|
|
|
|
if(radius >= 0)
|
|
for(var/turf/turf_in_view in view(radius, get_turf(src)))
|
|
if(!turf_in_view.density)
|
|
scatter_locations += turf_in_view
|
|
|
|
return scatter_locations
|
|
|
|
//finds the probabilities of items spawning from a loot spawner's loot pool
|
|
/obj/item/loot_table_maker
|
|
icon = 'icons/effects/landmarks_static.dmi'
|
|
icon_state = "random_loot"
|
|
var/spawner_to_test = /obj/effect/spawner/random/maintenance //what lootdrop spawner to use the loot pool of
|
|
var/loot_count = 180 //180 is about how much maint loot spawns per map as of 11/14/2019
|
|
//result outputs
|
|
var/list/spawned_table //list of all items "spawned" and how many
|
|
var/list/stat_table //list of all items "spawned" and their occurrance probability
|
|
|
|
/obj/item/loot_table_maker/Initialize(mapload)
|
|
. = ..()
|
|
make_table()
|
|
|
|
/obj/item/loot_table_maker/attack_self(mob/user)
|
|
to_chat(user, "Loot pool re-rolled.")
|
|
make_table()
|
|
|
|
/obj/item/loot_table_maker/proc/make_table()
|
|
spawned_table = list()
|
|
stat_table = list()
|
|
var/obj/effect/spawner/random/spawner_to_table = new spawner_to_test
|
|
var/lootpool = spawner_to_table.loot
|
|
qdel(spawner_to_table)
|
|
for(var/i in 1 to loot_count)
|
|
var/loot_spawn = pick_weight_recursive(lootpool)
|
|
if(!(loot_spawn in spawned_table))
|
|
spawned_table[loot_spawn] = 1
|
|
else
|
|
spawned_table[loot_spawn] += 1
|
|
stat_table += spawned_table
|
|
for(var/item in stat_table)
|
|
stat_table[item] /= loot_count
|