diff --git a/bapi.dll b/bapi.dll index c85f3cad191..27d3d9104a2 100644 Binary files a/bapi.dll and b/bapi.dll differ diff --git a/code/modules/effects/map_effects/marker/mapmanip.dm b/code/modules/effects/map_effects/marker/mapmanip.dm index 76ad6bffd61..3686ead8e54 100644 --- a/code/modules/effects/map_effects/marker/mapmanip.dm +++ b/code/modules/effects/map_effects/marker/mapmanip.dm @@ -5,6 +5,22 @@ icon_state = "mapmanip_extract" pixel_x = -32 pixel_y = -32 + /// If set, it allows extract markers to have a shared name, even across submap operations, + /// eliminating submaps with the same name from the selection pool. + /// If null, ignored. + /// + /// Must be set in map, as mapmanip does not read code. + var/singleton_id = null + /// The higher the weight, the more likely the marker is to be selected. + /// Default is 1 if unset. + /// Weight must be 0 or positive. + /// + /// If specifically set to 0, the marker will never be selected, + /// unless, and only if, all the remaining markers have a weight of 0. + /// Or in other words, it'll be selected last. + /// + /// Must be set in map, as mapmanip does not read code. + var/weight = 1 /obj/effect/map_effect/marker/mapmanip/submap/insert name = "mapmanip marker, insert submap" diff --git a/html/changelogs/DreamySkrell-bapi-submap-weight.yml b/html/changelogs/DreamySkrell-bapi-submap-weight.yml new file mode 100644 index 00000000000..e813d7a1716 --- /dev/null +++ b/html/changelogs/DreamySkrell-bapi-submap-weight.yml @@ -0,0 +1,58 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: DreamySkrell + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Bapi mapmanip submap weight." diff --git a/rust/bapi/Cargo.toml b/rust/bapi/Cargo.toml index 03508df4090..d205cc83e8d 100644 --- a/rust/bapi/Cargo.toml +++ b/rust/bapi/Cargo.toml @@ -13,7 +13,7 @@ atomic_float = "1.0.0" bitflags = "2.5.0" byondapi = { git = "https://github.com/spacestation13/byondapi-rs", rev = "5afdd9863a0fc1d8d1d42dd2128c9978f54e12ca" } eyre = "0.6.12" -rand = { version = "0.8.6", features = ["small_rng"] } +rand = { version = "0.8.6", features = ["small_rng", "alloc"] } scc = "2.1.1" thread-priority = "1.1.0" diff --git a/rust/bapi/src/mapmanip/mod.rs b/rust/bapi/src/mapmanip/mod.rs index 183ef409091..b801b808523 100644 --- a/rust/bapi/src/mapmanip/mod.rs +++ b/rust/bapi/src/mapmanip/mod.rs @@ -12,8 +12,7 @@ use eyre::eyre; use eyre::Context; use eyre::ContextCompat; use itertools::Itertools; -use procgen::{MazegenHauberkSettings, mapmanip_mazegen_hauberk}; -use rand::prelude::IteratorRandom; +use procgen::{mapmanip_mazegen_hauberk, MazegenHauberkSettings}; use rand::seq::SliceRandom; use serde::{Deserialize, Serialize}; use tools::extract_submap; @@ -176,25 +175,54 @@ fn mapmanip_submap_extract_insert( } } + // shuffle the list + // avoids always giving a high weight submap to the first insert marker + marker_insert_coords.shuffle(&mut rand::thread_rng()); + // do all the extracts-inserts for insert_coord in marker_insert_coords { - // pick a submap - let (&extract_coord, &extract_prefab) = marker_lookup + // collect candidate submaps + let candidates: Vec<(Coord3, &Prefab)> = marker_lookup .iter() .filter(|(_, &prefab)| { !singleton_tags .contains(prefab.vars.get("singleton_id").unwrap_or(Constant::null())) }) - .choose(&mut rand::thread_rng()) - .wrap_err(format!( - "no extractions found for marker {marker_extract}, singletons={singleton_tags:?}" - ))?; + .map(|(&coord, &prefab)| (coord, prefab)) + .collect(); + + // try weighted selection; fall back to uniform selection if all weights are 0 + let (extract_coord, extract_prefab) = candidates + .choose_weighted(&mut rand::thread_rng(), |(_, prefab)| { + let weight = prefab + .vars + .get("weight") + .unwrap_or(&Constant::from(1)) + .to_int() + .unwrap_or(1); + weight.max(0) + }) + .ok() + .copied() + .or_else(|| candidates.choose(&mut rand::thread_rng()).copied()) + .wrap_err_with(|| { + format!("no extractions found for marker {marker_extract}, singletons={singleton_tags:?}") + })?; // if submaps should not be repeating, remove this one if !submaps_can_repeat { marker_lookup.remove(&extract_coord); } + // if singleton_id is present, add it to the list so it cannot be picked again + let singleton_id = extract_prefab + .vars + .get("singleton_id") + .unwrap_or(Constant::null()); + if !singleton_id.is_null() { + singleton_tags.push(singleton_id.clone()); + } + // extract that submap from the submap dmm let extracted = extract_submap(&submaps_map, extract_coord, submap_size) .wrap_err(format!("submap extraction failed; from {extract_coord}"))?; @@ -202,14 +230,6 @@ fn mapmanip_submap_extract_insert( // and insert the submap into the manipulated map insert_submap(&extracted, insert_coord, map) .wrap_err(format!("submap insertion failed; at {insert_coord}"))?; - - let singleton_id = extract_prefab - .vars - .get("singleton_id") - .unwrap_or(Constant::null()); - if !singleton_id.is_null() { - singleton_tags.push(singleton_id.clone()); - } } Ok(()) diff --git a/tools/ci/libbapi_ci.so b/tools/ci/libbapi_ci.so index cbf44f74677..50d546f1983 100644 Binary files a/tools/ci/libbapi_ci.so and b/tools/ci/libbapi_ci.so differ