Files
Bubberstation/code/game/objects/effects/spawners/random/random.dm
T
SpaceLoveSs13 fa2ab65f07 Missed mirrors (#28919)
Handful of missed mirrors (#3739)

* fix duplicate traits

* Adds a Contraband trait, and implements contraband as a mechanic to security bounties. (#84003)

This PR does a few things but centrally it's all centered around
mechanically enforcing what items are and are-not considered contraband
in-game.

Contraband items are visually indistinguishable from non-contraband. If
an item is Contraband, it can only be detected in two ways:
* After being scanned by an N-Spect scanner, which is a standard item
security item, assuming it still has a charge to do so.
* Via a scanner gate, which can now be upgraded with an N-spect scanner
to allow for it to scan a person and all their contents for contraband.

Contraband items are intended to be determined both logically and
through other relevant examine text. However, here's the short list of
items that are considered contraband, reserving the right to expand the
list.

<details>
  <summary>In hindsight it's kind of a long list.</summary>

* Items that have "contraband" or "illegal" in the name or description.
* Items that allow for the player to obtain other illegal items, that
are NOT particularly stealthy.
* This means that a syndicate uplink is NOT considered contraband, as
they're typically hidden on your person as something else.
* Stealth items under the syndicate uplink, the revolutionary flash, and
some mapped in dangerous items that can come from both syndicate and
company-aligned resources are not considered dangerous.
* Items that are purchased from cargo after emagging or switching to
extended cargo range.
* Items purchased FROM syndicate uplinks, the wizard knowledge scroll,
or other antagonist shops.
* Cursed artifacts/tools magically produced by cultists or heretics.
* Items purchased from the blackmarket.
* Items purchased from the contraband section of vending machines.
* Some drugs and overtly dangerous or criminal byproducts.

</details>

Well, primarily, this is an aid for in-game enforcement of space law.
Based on the length of the above list, we have a LONG, LONG list of
items in-game that are technically considered, in one way or another,
illegal to have on the station, and yet without either metaknowledge of
what those items are, or how they're used, security officers lack some
of the certainty of how to deal with these kinds of encounters.

Additionally to the knowledge aspect of this trait, security officers
may now receive a new civilian bounty to collect items that are
considered contraband, also giving them an incentive to look for and
confiscate contraband that's been found across the station while
upholding space law.

Security has a bounty for 3 different rechargers, and considering access
limitations, most security players aren't going to make this exchange,
so I've lowered the required amount down to 1.

Adjusted the N-spect scanner's description to match it's new
functionality.

The Civilian bounty TGUI now has an additional 1 point of padding to
make it feel less cramped.

https://github.com/tgstation/tgstation/assets/41715314/c3cd4752-b03a-4e0b-959e-1252fcc2369d

**Updated as of 6/19/2024:**
Additionally, some storage items will block the presence of contraband
when going through a contraband aligned scanning gate. These items
include the infiltrator modsuit core, storage implant, void cloak, the
aptly named smuggler's satchel, and the chameleon kit's backpack.

**Updated as of 6/23/2024:**
N-spect scanner now has contextual screentips.

**Updated as of 6/29/2024:**
Scanner gates are now available in all lathes that have a feature
specific to how scanner gates function. So, includes cargo (contraband),
security (weapons), and medbay (diseases).

Originally, this started out as a way to be able to provide more
in-character and in-flavor bounties for security officers, because they
suck! Most security bounties as they exist right now do the worst
possible things from all respective bounties:
* They detract away from a job's actual responsibilities as opposed to
working with them.
* They're best completed while sitting next to your lathe and running
items back to the bounty pad.
* They exist with such esoteric rarity of high quantity of items that
it's miserable to fulfil.

As a result, I started work on this as a framework to allow security
officers to be further incentivized to collect contraband across the
station, either as a result of the gamemode or just through routine
patrols across the station.

Implementing it as a learning tool for security as well just happened to
work out as an additional bonus, and having a function in-game allowing
newer or less experienced players to know if an item is considered
dangerous or conspicuous also works as a particularly good way to
provide information where a player may not know what they're up against.

If nothing else, this might be interesting to try, and if not, I'll just
snip out the QOL changes from it and we'll see how it goes.

Going forward, I am a bit hesitant about the contraband scanner gate
mode, and as such, will try working with the admin team to determine if
that's a good feature to keep around for game health, while hoping to
give it a chance in the fullness of time.

🆑
add: Items spawned via traitor uplinks or are known illegal contraband
on the station can now be scanned and identified as such by the N-spect
scanners in security. These only applies to overt traitor or antagonist
items, and "stealth" items will not be seen as such.
add: Scanner gates can now be upgraded by using an N-spect scanner on it
to unlock "contraband scanning" mode.
add: Security officers can now be offered a bounty to turn in pieces of
contraband.
add: Some stealthy storage items like storage implants, smuggler's
satchels, void cloaks, the infiltrator modsuit, and the chameleon
backpack will block the presence of contraband on your person when
placed inside.
qol: N-spect scanner contextual screentips.
balance: Recharger security bounties ask for a quantity of 1, down from
3.
qol: security, cargo, and medbay have access to scanner gate boards.
/🆑

---------



* Adds six new strange object powers! (#84775)

DESIGN CONCEPT: Strange Devices are at their best when they're odd tools
which can help a department out, with some strange drawbacks that make
them interesting and unique. Foam for the Janitor, Flashbang for
Security, Teleporter for tiders, Corgimaker for the chef. They're also
ambiguous enough that they can really be used by anyone for silly
hijinks.

Drink Dispenser: Creates a glass, then fills it up with a random drink.

Bioscrambler: After a noticeable warning, bioscrambles people nearby.
33% chance to be used up on use.

Recharger: Shocks you, but recharges one random item to max battery.

Hugger: Hugs everyone in range as if you had the friendly trait.

DImensional: Converts the surroundings to a random material-theme. Each
use increases cooldown by two seconds.

Disguiser: Drops your clothing to the ground and replaces it with a
delete-on-drop costume and a randomly assigned cardboard ID.

Removed an unused and unusable shock flag.

Removed an unused dumb ghost item.

Added a proc that returns a hex color with the # attached.

> DESIGN CONCEPT: Strange Devices are at their best when they're odd
tools which can help a department out, with some strange drawbacks that
make them interesting and unique. Foam for the Janitor, Flashbang for
Security, Teleporter for tiders, Corgimaker for the chef. They're also
ambiguous enough that they can really be used by anyone for silly
hijinks.

Request by ArcaneMusic! He wanted new abilities to go along with the new
sprites, and approved these.

> Removed an unused dumb ghost item.

please stop using costume subtypes for OP items. whats the damn point of
the subtype if youre just going to screw with it

> Added a proc that returns a hex color with the # attached.

idk why it didnt have this tbh

🆑
add: Adds six new strange object powers! Drink dispenser, bioscrambler,
recharger, hugger, dimensional, disguiser.
code: Removed some unused code and items, and added a proc that returns
a random #colorstring.
/🆑

* [NO GBP] the random spawner loot weight config is not an integer (#84814)

Sets `integer` to false.
Also a tidbit about the `skew_loot_weight` proc, though loot lists with
uneven weights all tend to add a value to all entries so it isn't an
issue.

The config isn't an integer.

N/A

* The techweb no longer erroneously refers to MODsuits as exosuits (#84800)

At some point, some of the techweb node descriptions were changed, so
that it referred to certain modsuits as exosuits. This just changes it
back.

The term "exosuit" is generally used for mechs, not modsuits. The
techweb descriptions should refer to modsuits as modsuits.
🆑
spellcheck: The techweb no longer erroneously refers to MODsuits as
exosuits.
/🆑

* Adds new hairstyle - Short Bangs 2 (#84804)

Adds a new hairstyle called Short Bangs 2.
The hairstyle is basically an edit of the existing double buns, except
the hair buns themselves are removed.

https://github.com/tgstation/tgstation/assets/66234359/38fe3b09-c42b-43e6-9e30-949428aab506

More customization, variety and character flavor is great. Double buns
itself is a good hairstyle but some may not like the hair buns out of
personal preference or that it can look weird on non-human species like
felinids.

🆑 Hardly3D
add: Added new hairstyle: Short Bangs 2
/🆑

* Offset render relays for non-offsetting planes to match highest matching render plane (#84184)

**Alternate title: "Fix blind people getting so blind they become deaf
when going down a flight of stairs"**

So 'bout half a week to a week ago I overheard a friend complaining
about blind people not seeing runechat on lower multi-z levels. Asked a
bit, apparently they'd reported this about half a year ago, and it's
still an issue.
So in my never-ending hubris I decided to just go and fix it!
Now, admittedly? I really _really_ do not get the rendering system we
use.
The simple options were right out: we can't allow the fullscreens plane
to be offset, as this causes issues with looking up/down, or disallow
runechat from being offset, which causes issues with runechat from other
levels.

After poking our very cool and smart rendering guy several times over
the course of the last week, this is what we got to:

We simply make the rendering relays for non-offsetting plane masters
point to the highest rendering plane that matches the target.
We do this by offsetting the rendering relays in place, by adjusting
their plane and layer values to match the new offset, with a new
`offset_relays_in_place(new_offset)` proc called in
`/datum/plane_master_group/proc/transform_lower_turfs(...)`.
Importantly, we compare the current layer values to what they should've
been, so we don't accidentally override relays with custom-set layers.

This fixes our issue (as tested on wawastation):
<details>
  <summary>Images</summary>

![image](https://github.com/tgstation/tgstation/assets/42909981/c6a10e04-dd08-4642-bc4d-d99ae5004a40)

![image](https://github.com/tgstation/tgstation/assets/42909981/740dc894-7495-4c35-b729-ffcc539ca928)

![image](https://github.com/tgstation/tgstation/assets/42909981/986433a7-e66e-408a-8e77-1f1eb89cb67c)

</details>

Fixes #80376.
🆑
fix: You can see runechat above fullscreen overlays on lower multi-z
levels again. Rejoice, blind players. Please report any weird rendering
layering issues.
/🆑

* illegal tech flag got changed

* Automatic changelog for PR #84003 [ci skip]

* Automatic changelog for PR #84775 [ci skip]

* Automatic changelog for PR #84800 [ci skip]

* Automatic changelog for PR #84804 [ci skip]

* Automatic changelog for PR #84184 [ci skip]

* Makes the smoking pipe sprite not give you a phantom stache. (#84898)

The smoking pipe currently gives you a phantom stache. Observe, note the
black background and know this character has no facial hair.

![image](https://github.com/tgstation/tgstation/assets/70115628/2939afa9-e4e4-4ee2-b38b-fc517e207d01)
I basically adjusted the pixels so it'd look better from different
directions.
This is the new look - approximately.

![image](https://github.com/tgstation/tgstation/assets/70115628/55e23d8e-2367-468a-94c2-9c5741f34762)
Smoking pipe is cool for RP but the sprite's fucked.
🆑
image: the smoking pipe's directional looks have been altered to make it
less ugly
/🆑

(cherry picked from commit c499c51bb3)

* Automatic changelog for PR #84898 [ci skip]

(cherry picked from commit 1e80a72dee)

* Revert "Automatic changelog for PR #84898 [ci skip]"

This reverts commit 1ddc7d43de30bb7ef029d1ddd39f86ded94e110c.

* Revert "Makes the smoking pipe sprite not give you a phantom stache. (#84898)"

This reverts commit b66b9d634e5f28e40e800586d4642468049767e6.

---------

Co-authored-by: FlufflesTheDog <piecopresident@gmail.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: carlarctg <53100513+carlarctg@users.noreply.github.com>
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
Co-authored-by: GPeckman <21979502+GPeckman@users.noreply.github.com>
Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com>
Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com>
Co-authored-by: orange man <61334995+comfyorange@users.noreply.github.com>
Co-authored-by: NewyearnewmeUwu <70115628+NewyearnewmeUwu@users.noreply.github.com>
Co-authored-by: SomeRandomOwl <2568378+SomeRandomOwl@users.noreply.github.com>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
2024-07-20 14:23:18 +05:30

176 lines
6.5 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
/// The pixel x/y divider offsets for spawn_loot_split (spaced 1 pixel apart by default)
var/spawn_loot_split_pixel_offsets = 2
/// 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
/// Whether items that cannot be spawned will be removed from the loot list. Keep it TRUE unless you've a good reason.
var/remove_if_cant_spawn = TRUE
/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(CONFIG_GET(number/random_loot_weight_modifier) != 1)
skew_loot_weights(loot, CONFIG_GET(number/random_loot_weight_modifier))
if(loot?.len)
var/loot_spawned = 0
var/pixel_divider = FLOOR(16 / spawn_loot_split_pixel_offsets, 1) // 16 pixels offsets is max that should be allowed in any direction
while((spawn_loot_count-loot_spawned) && loot.len)
var/lootspawn = pick_weight_recursive(loot)
if(!can_spawn(lootspawn))
if(remove_if_cant_spawn)
loot.Remove(lootspawn)
continue
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)
var/column = FLOOR(loot_spawned / pixel_divider, 1)
spawned_loot.pixel_x = spawn_loot_split_pixel_offsets * (loot_spawned % pixel_divider) + (column * spawn_loot_split_pixel_offsets)
spawned_loot.pixel_y = spawn_loot_split_pixel_offsets * (loot_spawned % pixel_divider)
loot_spawned++
///Levels out the weights of loot if lower than 1, or makes rarer spawns even more rare.
/obj/effect/spawner/random/proc/skew_loot_weights(list/loot_list, exponent)
///This helps keeping the modified weights more or less correct, since pick_weight doesn't appreciate decimals.
var/precision = 1
if(exponent < 1)
precision = round((1 - exponent) * 10) + 1
for(var/loot_type in loot_list)
if(islist(loot_type))
skew_loot_weights(loot_type, exponent)
var/loot_weight = loot_list[loot_type]
if(loot_weight <= 1)
if(exponent < 1)
loot_list[loot_type] = precision
continue
loot_list[loot_type] = round(loot_weight ** exponent * precision, 1)
/**
* 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 that are in view and have an unblocked line to them.
/obj/effect/spawner/random/proc/get_spawn_locations(radius)
var/list/scatter_locations = list()
if(!radius)
return scatter_locations
for(var/turf/turf_in_view in view(radius, get_turf(src)))
if(isclosedturf(turf_in_view) || (isgroundlessturf(turf_in_view) && !GET_TURF_BELOW(turf_in_view)))
continue
if(!has_unblocked_line(turf_in_view))
continue
scatter_locations += turf_in_view
return scatter_locations
/obj/effect/spawner/random/proc/has_unblocked_line(destination)
for(var/turf/potential_blockage as anything in get_line(get_turf(src), destination))
if(!potential_blockage.is_blocked_turf(exclude_mobs = TRUE))
continue
return FALSE
return TRUE
//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