From 00d1559b9553e5bff065a213e7ee885468f8a39f Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:29:04 +0300 Subject: [PATCH 01/55] [MIRROR] Fixes body collision causing a stun, despite a successful block. [MDB IGNORE] (#739) * Fixes body collision causing a stun, despite a successful block. (#79824) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: necromanceranne <40847847+necromanceranne@users.noreply.github.com> --- code/modules/mob/living/carbon/carbon.dm | 29 ++++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 786b663758f..6a34c7fd005 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -52,6 +52,7 @@ . = ..() var/hurt = TRUE var/extra_speed = 0 + var/oof_noise = FALSE //We smacked something with denisty, so play a noise if(throwingdatum.thrower != src) extra_speed = min(max(0, throwingdatum.speed - initial(throw_speed)), CARBON_MAX_IMPACT_SPEED_BONUS) @@ -66,19 +67,37 @@ take_bodypart_damage(5 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) else if(!iscarbon(hit_atom) && extra_speed) take_bodypart_damage(5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) + oof_noise = TRUE + if(iscarbon(hit_atom) && hit_atom != src) var/mob/living/carbon/victim = hit_atom + var/blocked = FALSE if(victim.movement_type & FLYING) return - if(hurt) - victim.take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) - take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) + if(!hurt) + return + + if(victim.check_block(src, 0, "[name]", LEAP_ATTACK)) + blocked = TRUE + + take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) + Paralyze(2 SECONDS) + oof_noise = TRUE + + if(blocked) + visible_message(span_danger("[src] crashes into [victim][extra_speed ? " really hard" : ""], but [victim] blocked the worst of it!"),\ + span_userdanger("You violently crash into [victim][extra_speed ? " extra hard" : ""], but [victim] managed to block the worst of it!")) + log_combat(src, victim, "crashed into and was blocked by") + return + else victim.Paralyze(2 SECONDS) - Paralyze(2 SECONDS) + victim.take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) visible_message(span_danger("[src] crashes into [victim][extra_speed ? " really hard" : ""], knocking them both over!"),\ span_userdanger("You violently crash into [victim][extra_speed ? " extra hard" : ""]!")) + log_combat(src, victim, "crashed into") + + if(oof_noise) playsound(src,'sound/weapons/punch1.ogg',50,TRUE) - log_combat(src, victim, "crashed into") //Throwing stuff /mob/living/carbon/proc/toggle_throw_mode() From cbfccecf02507315c5284b41767ba25598c7cab7 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:29:32 +0300 Subject: [PATCH 02/55] Automatic changelog for PR #739 [ci skip] --- html/changelogs/AutoChangeLog-pr-739.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-739.yml diff --git a/html/changelogs/AutoChangeLog-pr-739.yml b/html/changelogs/AutoChangeLog-pr-739.yml new file mode 100644 index 00000000000..eacb835f703 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-739.yml @@ -0,0 +1,4 @@ +author: "necromanceranne" +delete-after: True +changes: + - bugfix: "When you successfully block a body collision, it does something rather than nothing at all." \ No newline at end of file From 094d9840bd79aaee0cd1d6f8dec44c86aa75f686 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:30:55 +0300 Subject: [PATCH 03/55] [MIRROR] Reorganizes the plane master subtypes according to the will of the plane master master [MDB IGNORE] (#741) * Reorganizes the plane master subtypes according to the will of the plane master master (#79745) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Emmett Gaines --- .../rendering/plane_masters/camera_static.dm | 30 -- .../rendering/plane_masters/clickcatcher.dm | 20 - .../plane_masters/core_game_planes.dm | 122 ----- .../hud/rendering/plane_masters/default.dm | 15 - .../rendering/plane_masters/in_world_chat.dm | 20 - .../hud/rendering/plane_masters/lighting.dm | 44 -- .../hud/rendering/plane_masters/parallax.dm | 105 ---- .../hud/rendering/plane_masters/pipecrawl.dm | 15 - .../plane_masters/plane_master_subtypes.dm | 447 ++++++++++++++++++ .../plane_masters/simple_plane_masters.dm | 82 ---- tgstation.dme | 10 +- 11 files changed, 448 insertions(+), 462 deletions(-) delete mode 100644 code/_onclick/hud/rendering/plane_masters/camera_static.dm delete mode 100644 code/_onclick/hud/rendering/plane_masters/clickcatcher.dm delete mode 100644 code/_onclick/hud/rendering/plane_masters/core_game_planes.dm delete mode 100644 code/_onclick/hud/rendering/plane_masters/default.dm delete mode 100644 code/_onclick/hud/rendering/plane_masters/in_world_chat.dm delete mode 100644 code/_onclick/hud/rendering/plane_masters/lighting.dm delete mode 100644 code/_onclick/hud/rendering/plane_masters/parallax.dm delete mode 100644 code/_onclick/hud/rendering/plane_masters/pipecrawl.dm create mode 100644 code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm delete mode 100644 code/_onclick/hud/rendering/plane_masters/simple_plane_masters.dm diff --git a/code/_onclick/hud/rendering/plane_masters/camera_static.dm b/code/_onclick/hud/rendering/plane_masters/camera_static.dm deleted file mode 100644 index 4cb3436a7a4..00000000000 --- a/code/_onclick/hud/rendering/plane_masters/camera_static.dm +++ /dev/null @@ -1,30 +0,0 @@ -/atom/movable/screen/plane_master/camera_static - name = "Camera static" - documentation = "Holds camera static images. Usually only visible to people who can well, see static.\ -
We use images rather then vis contents because they're lighter on maptick, and maptick sucks butt." - plane = CAMERA_STATIC_PLANE - -/atom/movable/screen/plane_master/camera_static/show_to(mob/mymob) - . = ..() - if(!.) - return - var/datum/hud/our_hud = home.our_hud - if(isnull(our_hud)) - return - - // We'll hide the slate if we're not seeing through a camera eye - // This can call on a cycle cause we don't clear in hide_from - // Yes this is the best way of hooking into the hud, I hate myself too - RegisterSignal(our_hud, COMSIG_HUD_EYE_CHANGED, PROC_REF(eye_changed), override = TRUE) - eye_changed(our_hud, null, our_hud.mymob?.canon_client?.eye) - -/atom/movable/screen/plane_master/camera_static/proc/eye_changed(datum/hud/source, atom/old_eye, atom/new_eye) - SIGNAL_HANDLER - - if(!isaicamera(new_eye)) - if(!force_hidden) - hide_plane(source.mymob) - return - - if(force_hidden) - unhide_plane(source.mymob) diff --git a/code/_onclick/hud/rendering/plane_masters/clickcatcher.dm b/code/_onclick/hud/rendering/plane_masters/clickcatcher.dm deleted file mode 100644 index 8e581dc081c..00000000000 --- a/code/_onclick/hud/rendering/plane_masters/clickcatcher.dm +++ /dev/null @@ -1,20 +0,0 @@ -/atom/movable/screen/plane_master/clickcatcher - name = "Click Catcher" - documentation = "Contains the screen object we use as a backdrop to catch clicks on portions of the screen that would otherwise contain nothing else. \ -
Will always be below almost everything else" - plane = CLICKCATCHER_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - multiz_scaled = FALSE - critical = PLANE_CRITICAL_DISPLAY - -/atom/movable/screen/plane_master/clickcatcher/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, PROC_REF(offset_increased)) - offset_increased(SSmapping, 0, SSmapping.max_plane_offset) - -/atom/movable/screen/plane_master/clickcatcher/proc/offset_increased(datum/source, old_off, new_off) - SIGNAL_HANDLER - // We only want need the lowest level - // If my system better supported changing PM plane values mid op I'd do that, but I do NOT so - if(new_off > offset) - hide_plane(home?.our_hud?.mymob) diff --git a/code/_onclick/hud/rendering/plane_masters/core_game_planes.dm b/code/_onclick/hud/rendering/plane_masters/core_game_planes.dm deleted file mode 100644 index 89379070b35..00000000000 --- a/code/_onclick/hud/rendering/plane_masters/core_game_planes.dm +++ /dev/null @@ -1,122 +0,0 @@ -//-------------------- FLOOR PLANE -------------------- - -///Contains just the floor -/atom/movable/screen/plane_master/floor - name = "Floor" - documentation = "The well, floor. This is mostly used as a sorting mechanism, but it also lets us create a \"border\" around the game world plane, so its drop shadow will actually work." - plane = FLOOR_PLANE - render_relay_planes = list(RENDER_PLANE_GAME, LIGHT_MASK_PLANE) - -/atom/movable/screen/plane_master/transparent_floor - name = "Transparent Floor" - documentation = "Really just openspace, stuff that is a turf but has no color or alpha whatsoever.\ -
We use this to draw to just the light mask plane, cause if it's not there we get holes of blackness over openspace" - plane = TRANSPARENT_FLOOR_PLANE - render_relay_planes = list(LIGHT_MASK_PLANE) - // Needs to be critical or it uh, it'll look white - critical = PLANE_CRITICAL_DISPLAY|PLANE_CRITICAL_NO_RELAY - -/atom/movable/screen/plane_master/floor/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_FLOOR_LAYER, relay_color = GLOB.em_block_color) - -//-------------------- WALL PLANE -------------------- - -/atom/movable/screen/plane_master/wall - name = "Wall" - documentation = "Holds all walls. We render this onto the game world. Separate so we can use this + space and floor planes as a guide for where byond blackness is NOT." - plane = WALL_PLANE - render_relay_planes = list(RENDER_PLANE_GAME_WORLD, LIGHT_MASK_PLANE) - -/atom/movable/screen/plane_master/wall/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_WALL_LAYER, relay_color = GLOB.em_block_color) - -/atom/movable/screen/plane_master/wall_upper - name = "Upper wall" - documentation = "There are some walls that want to render above most things (mostly minerals since they shift over.\ -
We draw them to their own plane so we can hijack them for our emissive mask stuff" - plane = WALL_PLANE_UPPER - render_relay_planes = list(RENDER_PLANE_GAME_WORLD, LIGHT_MASK_PLANE) - -/atom/movable/screen/plane_master/wall_upper/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_WALL_LAYER, relay_color = GLOB.em_block_color) - -//-------------------- AREA PLANE -------------------- - -/atom/movable/screen/plane_master/area - name = "Area" - documentation = "Holds the areas themselves, which ends up meaning it holds any overlays/effects we apply to areas. NOT snow or rad storms, those go on above lighting" - plane = AREA_PLANE - -//-------------------- GAME PLANES -------------------- - -/atom/movable/screen/plane_master/game - name = "Lower game world" - documentation = "Exists mostly because of FOV shit. Basically, if you've just got a normal not ABOVE fov thing, and you don't want it masked, stick it here yeah?" - plane = GAME_PLANE - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - -/atom/movable/screen/plane_master/high_game - name = "High Game" - documentation = "Holds anything that wants to be displayed above the rest of the game plane, and doesn't want to be clickable. \ -
This includes atmos debug overlays, blind sound images, and mining scanners. \ -
Really only exists for its layering potential, we don't use this for any vfx" - plane = HIGH_GAME_PLANE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - -//-------------------- FOV PLANES -------------------- - -/atom/movable/screen/plane_master/game_world_fov_hidden - name = "lower game world fov hidden" - documentation = "If you want something to be hidden by fov, stick it on this plane. We're masked by the fov blocker plane, so the items on us can actually well, disappear." - plane = GAME_PLANE_FOV_HIDDEN - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - -/atom/movable/screen/plane_master/game_world_fov_hidden/Initialize(mapload, datum/hud/hud_owner) - . = ..() - add_filter("vision_cone", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(FIELD_OF_VISION_BLOCKER_RENDER_TARGET, offset), flags = MASK_INVERSE)) - -/atom/movable/screen/plane_master/field_of_vision_blocker - name = "Field of vision blocker" - documentation = "This is one of those planes that's only used as a filter. It masks out things that want to be hidden by fov.\ -
Literally just contains FOV images, or masks." - plane = FIELD_OF_VISION_BLOCKER_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_target = FIELD_OF_VISION_BLOCKER_RENDER_TARGET - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - render_relay_planes = list() - // We do NOT allow offsetting, because there's no case where you would want to block only one layer, at least currently - allows_offsetting = FALSE - start_hidden = TRUE - // We mark as multiz_scaled FALSE so transforms don't effect us, and we draw to the planes below us as if they were us. - // This is safe because we will ALWAYS be on the top z layer, so it DON'T MATTER - multiz_scaled = FALSE - -/atom/movable/screen/plane_master/field_of_vision_blocker/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - mirror_parent_hidden() - -/atom/movable/screen/plane_master/game_world_above - name = "Above game world" - documentation = "We need a place that's unmasked by fov that also draws above the upper game world fov hidden plane. I told you fov was hacky man." - plane = ABOVE_GAME_PLANE - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - -/atom/movable/screen/plane_master/game_world_upper - name = "Upper game world" - documentation = "Ok so fov is kinda fucky, because planes in byond serve both as effect groupings and as rendering orderers. Since that's true, we need a plane that we can stick stuff that draws above fov blocked stuff on." - plane = GAME_PLANE_UPPER - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - -/atom/movable/screen/plane_master/game_world_upper_fov_hidden - name = "Upper game world fov hidden" - documentation = "Just as we need a place to draw things \"above\" the hidden fov plane, we also need to be able to hide stuff that draws over the upper game plane." - plane = GAME_PLANE_UPPER_FOV_HIDDEN - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - -/atom/movable/screen/plane_master/game_world_upper_fov_hidden/Initialize(mapload, datum/hud/hud_owner) - . = ..() - // Dupe of the other hidden plane - add_filter("vision_cone", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(FIELD_OF_VISION_BLOCKER_RENDER_TARGET, offset), flags = MASK_INVERSE)) diff --git a/code/_onclick/hud/rendering/plane_masters/default.dm b/code/_onclick/hud/rendering/plane_masters/default.dm deleted file mode 100644 index f4f49f5bdd8..00000000000 --- a/code/_onclick/hud/rendering/plane_masters/default.dm +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Plane master that byond will by default draw to - * Shouldn't be used, exists to prevent people using plane 0 - * NOTE: If we used SEE_BLACKNESS on a map format that wasn't SIDE_MAP, this is where its darkness would land - * This would allow us to control it and do fun things. But we can't because side map doesn't support it, so this is just a stub - */ -/atom/movable/screen/plane_master/default - name = "Default" - documentation = "This is quite fiddly, so bear with me. By default (in byond) everything in the game is rendered onto plane 0. It's the default plane. \ -
But, because we've moved everything we control off plane 0, all that's left is stuff byond internally renders. \ -
What I'd like to do with this is capture byond blackness by giving mobs the SEE_BLACKNESS sight flag. \ -
But we CAN'T because SEE_BLACKNESS does not work with our rendering format. So I just eat it I guess" - plane = DEFAULT_PLANE - multiz_scaled = FALSE - start_hidden = TRUE // Doesn't DO anything, exists to hold this place diff --git a/code/_onclick/hud/rendering/plane_masters/in_world_chat.dm b/code/_onclick/hud/rendering/plane_masters/in_world_chat.dm deleted file mode 100644 index bc7d327b8fb..00000000000 --- a/code/_onclick/hud/rendering/plane_masters/in_world_chat.dm +++ /dev/null @@ -1,20 +0,0 @@ -/atom/movable/screen/plane_master/runechat - name = "Runechat" - documentation = "Holds runechat images, that text that pops up when someone say something. Uses a dropshadow to well, look nice." - plane = RUNECHAT_PLANE - render_relay_planes = list(RENDER_PLANE_NON_GAME) - -/atom/movable/screen/plane_master/runechat/show_to(mob/mymob) - . = ..() - if(!.) - return - remove_filter("AO") - if(istype(mymob) && mymob.canon_client?.prefs?.read_preference(/datum/preference/toggle/ambient_occlusion)) - add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA")) - -/atom/movable/screen/plane_master/balloon_chat - name = "Balloon chat" - documentation = "Holds ballon chat images, those little text bars that pop up for a second when you do some things. NOT runechat." - plane = BALLOON_CHAT_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_NON_GAME) diff --git a/code/_onclick/hud/rendering/plane_masters/lighting.dm b/code/_onclick/hud/rendering/plane_masters/lighting.dm deleted file mode 100644 index 2ac4139b78f..00000000000 --- a/code/_onclick/hud/rendering/plane_masters/lighting.dm +++ /dev/null @@ -1,44 +0,0 @@ -///Contains all turf lighting -/atom/movable/screen/plane_master/turf_lighting - name = "Turf Lighting" - documentation = "Contains all lighting drawn to turfs. Not so complex, draws directly onto the lighting plate." - plane = LIGHTING_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_LIGHTING) - blend_mode_override = BLEND_ADD - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - critical = PLANE_CRITICAL_DISPLAY - -/// This will not work through multiz, because of a byond bug with BLEND_MULTIPLY -/// Bug report is up, waiting on a fix -/atom/movable/screen/plane_master/o_light_visual - name = "Overlight light visual" - documentation = "Holds overlay lighting objects, or the sort of lighting that's a well, overlay stuck to something.\ -
Exists because lighting updating is really slow, and movement needs to feel smooth.\ -
We draw to the game plane, and mask out space for ourselves on the lighting plane so any color we have has the chance to display." - plane = O_LIGHTING_VISUAL_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_target = O_LIGHTING_VISUAL_RENDER_TARGET - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - blend_mode = BLEND_MULTIPLY - critical = PLANE_CRITICAL_DISPLAY - -/atom/movable/screen/plane_master/above_lighting - name = "Above lighting" - plane = ABOVE_LIGHTING_PLANE - documentation = "Anything on the game plane that needs a space to draw on that will be above the lighting plane.\ -
Mostly little alerts and effects, also sometimes contains things that are meant to look as if they glow." - -/** - * Handles emissive overlays and emissive blockers. - */ -/atom/movable/screen/plane_master/emissive - name = "Emissive" - documentation = "Holds things that will be used to mask the lighting plane later on. Masked by the Emissive Mask plane to ensure we don't emiss out under a wall.\ -
Relayed onto the Emissive render plane to do the actual masking of lighting, since we need to be transformed and other emissive stuff needs to be transformed too.\ -
Don't want to double scale now." - plane = EMISSIVE_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - render_relay_planes = list(EMISSIVE_RENDER_PLATE) - critical = PLANE_CRITICAL_DISPLAY diff --git a/code/_onclick/hud/rendering/plane_masters/parallax.dm b/code/_onclick/hud/rendering/plane_masters/parallax.dm deleted file mode 100644 index ee49ab17700..00000000000 --- a/code/_onclick/hud/rendering/plane_masters/parallax.dm +++ /dev/null @@ -1,105 +0,0 @@ -/atom/movable/screen/plane_master/parallax_white - name = "Parallax whitifier" - documentation = "Essentially a backdrop for the parallax plane. We're rendered just below it, so we'll be multiplied by its well, parallax.\ -
If you want something to look as if it has parallax on it, draw it to this plane." - plane = PLANE_SPACE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_GAME, LIGHT_MASK_PLANE) - critical = PLANE_CRITICAL_FUCKO_PARALLAX // goes funny when touched. no idea why I don't trust byond - -/atom/movable/screen/plane_master/parallax_white/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_SPACE_LAYER) - -///Contains space parallax -/atom/movable/screen/plane_master/parallax - name = "Parallax" - documentation = "Contains parallax, or to be more exact the screen objects that hold parallax.\ -
Note the BLEND_MULTIPLY. The trick here is how low our plane value is. Because of that, we draw below almost everything in the game.\ -
We abuse this to ensure we multiply against the Parallax whitifier plane, or space's plane. It's set to full white, so when you do the multiply you just get parallax out where it well, makes sense to be.\ -
Also notice that the parent parallax plane is mirrored down to all children. We want to support viewing parallax across all z levels at once." - plane = PLANE_SPACE_PARALLAX - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - blend_mode = BLEND_MULTIPLY - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - multiz_scaled = FALSE - -/atom/movable/screen/plane_master/parallax/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) - . = ..() - if(offset != 0) - // You aren't the source? don't change yourself - return - RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, PROC_REF(on_offset_increase)) - RegisterSignal(SSdcs, COMSIG_NARSIE_SUMMON_UPDATE, PROC_REF(narsie_modified)) - if(GLOB.narsie_summon_count >= 1) - narsie_start_midway(GLOB.narsie_effect_last_modified) // We assume we're on the start, so we can use this number - offset_increase(0, SSmapping.max_plane_offset) - -/atom/movable/screen/plane_master/parallax/proc/on_offset_increase(datum/source, old_offset, new_offset) - SIGNAL_HANDLER - offset_increase(old_offset, new_offset) - -/atom/movable/screen/plane_master/parallax/proc/offset_increase(old_offset, new_offset) - // Parallax will be mirrored down to any new planes that are added, so it will properly render across mirage borders - for(var/offset in old_offset to new_offset) - if(offset != 0) - // Overlay so we don't multiply twice, and thus fuck up our rendering - add_relay_to(GET_NEW_PLANE(plane, offset), BLEND_OVERLAY) - -// Hacky shit to ensure parallax works in perf mode -/atom/movable/screen/plane_master/parallax/outside_bounds(mob/relevant) - if(offset == 0) - remove_relay_from(GET_NEW_PLANE(RENDER_PLANE_GAME, 0)) - is_outside_bounds = TRUE // I'm sorry :( - return - // If we can't render, and we aren't the bottom layer, don't render us - // This way we only multiply against stuff that's not fullwhite space - var/atom/movable/screen/plane_master/parent_parallax = home.our_hud.get_plane_master(PLANE_SPACE_PARALLAX) - var/turf/viewing_turf = get_turf(relevant) - if(!viewing_turf || offset != GET_LOWEST_STACK_OFFSET(viewing_turf.z)) - parent_parallax.remove_relay_from(plane) - else - parent_parallax.add_relay_to(plane, BLEND_OVERLAY) - return ..() - -/atom/movable/screen/plane_master/parallax/inside_bounds(mob/relevant) - if(offset == 0) - add_relay_to(GET_NEW_PLANE(RENDER_PLANE_GAME, 0)) - is_outside_bounds = FALSE - return - // Always readd, just in case we lost it - var/atom/movable/screen/plane_master/parent_parallax = home.our_hud.get_plane_master(PLANE_SPACE_PARALLAX) - parent_parallax.add_relay_to(plane, BLEND_OVERLAY) - return ..() - -// Needs to handle rejoining on a lower z level, so we NEED to readd old planes -/atom/movable/screen/plane_master/parallax/check_outside_bounds() - // If we're outside bounds AND we're the 0th plane, we need to show cause parallax is hacked to hell - return offset != 0 && is_outside_bounds - -/// Starts the narsie animation midway, so we can catch up to everyone else quickly -/atom/movable/screen/plane_master/parallax/proc/narsie_start_midway(start_time) - var/time_elapsed = world.time - start_time - narsie_summoned_effect(max(16 SECONDS - time_elapsed, 0)) - -/// Starts the narsie animation, make us grey, then red -/atom/movable/screen/plane_master/parallax/proc/narsie_modified(datum/source, new_count) - SIGNAL_HANDLER - if(new_count >= 1) - narsie_summoned_effect(16 SECONDS) - else - narsie_unsummoned() - -/atom/movable/screen/plane_master/parallax/proc/narsie_summoned_effect(animate_time) - if(GLOB.narsie_summon_count >= 2) - var/static/list/nightmare_parallax = list(255,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, -130,0,0,0) - animate(src, color = nightmare_parallax, time = animate_time) - return - - var/static/list/grey_parallax = list(0.4,0.4,0.4,0, 0.4,0.4,0.4,0, 0.4,0.4,0.4,0, 0,0,0,1, -0.1,-0.1,-0.1,0) - // We're gonna animate ourselves grey - // Then, once it's done, about 40 seconds into the event itself, we're gonna start doin some shit. see below - animate(src, color = grey_parallax, time = animate_time) - -/atom/movable/screen/plane_master/parallax/proc/narsie_unsummoned() - animate(src, color = null, time = 8 SECONDS) diff --git a/code/_onclick/hud/rendering/plane_masters/pipecrawl.dm b/code/_onclick/hud/rendering/plane_masters/pipecrawl.dm deleted file mode 100644 index cb75135e1a4..00000000000 --- a/code/_onclick/hud/rendering/plane_masters/pipecrawl.dm +++ /dev/null @@ -1,15 +0,0 @@ -/atom/movable/screen/plane_master/pipecrawl - name = "Pipecrawl" - documentation = "Holds pipecrawl images generated during well, pipecrawling.\ -
Has a few effects and a funky color matrix designed to make things a bit more visually readable." - plane = PIPECRAWL_IMAGES_PLANE - start_hidden = TRUE - -/atom/movable/screen/plane_master/pipecrawl/Initialize(mapload, datum/hud/hud_owner) - . = ..() - // Makes everything on this plane slightly brighter - // Has a nice effect, makes thing stand out - color = list(1.2,0,0,0, 0,1.2,0,0, 0,0,1.2,0, 0,0,0,1, 0,0,0,0) - // This serves a similar purpose, I want the pipes to pop - add_filter("pipe_dropshadow", 1, drop_shadow_filter(x = -1, y= -1, size = 1, color = "#0000007A")) - mirror_parent_hidden() diff --git a/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm b/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm new file mode 100644 index 00000000000..8988b2f7f33 --- /dev/null +++ b/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm @@ -0,0 +1,447 @@ +/atom/movable/screen/plane_master/clickcatcher + name = "Click Catcher" + documentation = "Contains the screen object we use as a backdrop to catch clicks on portions of the screen that would otherwise contain nothing else. \ +
Will always be below almost everything else" + plane = CLICKCATCHER_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + multiz_scaled = FALSE + critical = PLANE_CRITICAL_DISPLAY + +/atom/movable/screen/plane_master/clickcatcher/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, PROC_REF(offset_increased)) + offset_increased(SSmapping, 0, SSmapping.max_plane_offset) + +/atom/movable/screen/plane_master/clickcatcher/proc/offset_increased(datum/source, old_off, new_off) + SIGNAL_HANDLER + // We only want need the lowest level + // If my system better supported changing PM plane values mid op I'd do that, but I do NOT so + if(new_off > offset) + hide_plane(home?.our_hud?.mymob) + +/atom/movable/screen/plane_master/parallax_white + name = "Parallax whitifier" + documentation = "Essentially a backdrop for the parallax plane. We're rendered just below it, so we'll be multiplied by its well, parallax.\ +
If you want something to look as if it has parallax on it, draw it to this plane." + plane = PLANE_SPACE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_GAME, LIGHT_MASK_PLANE) + critical = PLANE_CRITICAL_FUCKO_PARALLAX // goes funny when touched. no idea why I don't trust byond + +/atom/movable/screen/plane_master/parallax_white/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_SPACE_LAYER) + +///Contains space parallax +/atom/movable/screen/plane_master/parallax + name = "Parallax" + documentation = "Contains parallax, or to be more exact the screen objects that hold parallax.\ +
Note the BLEND_MULTIPLY. The trick here is how low our plane value is. Because of that, we draw below almost everything in the game.\ +
We abuse this to ensure we multiply against the Parallax whitifier plane, or space's plane. It's set to full white, so when you do the multiply you just get parallax out where it well, makes sense to be.\ +
Also notice that the parent parallax plane is mirrored down to all children. We want to support viewing parallax across all z levels at once." + plane = PLANE_SPACE_PARALLAX + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + blend_mode = BLEND_MULTIPLY + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + multiz_scaled = FALSE + +/atom/movable/screen/plane_master/parallax/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + if(offset != 0) + // You aren't the source? don't change yourself + return + RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, PROC_REF(on_offset_increase)) + RegisterSignal(SSdcs, COMSIG_NARSIE_SUMMON_UPDATE, PROC_REF(narsie_modified)) + if(GLOB.narsie_summon_count >= 1) + narsie_start_midway(GLOB.narsie_effect_last_modified) // We assume we're on the start, so we can use this number + offset_increase(0, SSmapping.max_plane_offset) + +/atom/movable/screen/plane_master/parallax/proc/on_offset_increase(datum/source, old_offset, new_offset) + SIGNAL_HANDLER + offset_increase(old_offset, new_offset) + +/atom/movable/screen/plane_master/parallax/proc/offset_increase(old_offset, new_offset) + // Parallax will be mirrored down to any new planes that are added, so it will properly render across mirage borders + for(var/offset in old_offset to new_offset) + if(offset != 0) + // Overlay so we don't multiply twice, and thus fuck up our rendering + add_relay_to(GET_NEW_PLANE(plane, offset), BLEND_OVERLAY) + +// Hacky shit to ensure parallax works in perf mode +/atom/movable/screen/plane_master/parallax/outside_bounds(mob/relevant) + if(offset == 0) + remove_relay_from(GET_NEW_PLANE(RENDER_PLANE_GAME, 0)) + is_outside_bounds = TRUE // I'm sorry :( + return + // If we can't render, and we aren't the bottom layer, don't render us + // This way we only multiply against stuff that's not fullwhite space + var/atom/movable/screen/plane_master/parent_parallax = home.our_hud.get_plane_master(PLANE_SPACE_PARALLAX) + var/turf/viewing_turf = get_turf(relevant) + if(!viewing_turf || offset != GET_LOWEST_STACK_OFFSET(viewing_turf.z)) + parent_parallax.remove_relay_from(plane) + else + parent_parallax.add_relay_to(plane, BLEND_OVERLAY) + return ..() + +/atom/movable/screen/plane_master/parallax/inside_bounds(mob/relevant) + if(offset == 0) + add_relay_to(GET_NEW_PLANE(RENDER_PLANE_GAME, 0)) + is_outside_bounds = FALSE + return + // Always readd, just in case we lost it + var/atom/movable/screen/plane_master/parent_parallax = home.our_hud.get_plane_master(PLANE_SPACE_PARALLAX) + parent_parallax.add_relay_to(plane, BLEND_OVERLAY) + return ..() + +// Needs to handle rejoining on a lower z level, so we NEED to readd old planes +/atom/movable/screen/plane_master/parallax/check_outside_bounds() + // If we're outside bounds AND we're the 0th plane, we need to show cause parallax is hacked to hell + return offset != 0 && is_outside_bounds + +/// Starts the narsie animation midway, so we can catch up to everyone else quickly +/atom/movable/screen/plane_master/parallax/proc/narsie_start_midway(start_time) + var/time_elapsed = world.time - start_time + narsie_summoned_effect(max(16 SECONDS - time_elapsed, 0)) + +/// Starts the narsie animation, make us grey, then red +/atom/movable/screen/plane_master/parallax/proc/narsie_modified(datum/source, new_count) + SIGNAL_HANDLER + if(new_count >= 1) + narsie_summoned_effect(16 SECONDS) + else + narsie_unsummoned() + +/atom/movable/screen/plane_master/parallax/proc/narsie_summoned_effect(animate_time) + if(GLOB.narsie_summon_count >= 2) + var/static/list/nightmare_parallax = list(255,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, -130,0,0,0) + animate(src, color = nightmare_parallax, time = animate_time) + return + + var/static/list/grey_parallax = list(0.4,0.4,0.4,0, 0.4,0.4,0.4,0, 0.4,0.4,0.4,0, 0,0,0,1, -0.1,-0.1,-0.1,0) + // We're gonna animate ourselves grey + // Then, once it's done, about 40 seconds into the event itself, we're gonna start doin some shit. see below + animate(src, color = grey_parallax, time = animate_time) + +/atom/movable/screen/plane_master/parallax/proc/narsie_unsummoned() + animate(src, color = null, time = 8 SECONDS) + +/atom/movable/screen/plane_master/gravpulse + name = "Gravpulse" + documentation = "Ok so this one's fun. Basically, we want to be able to distort the game plane when a grav annom is around.\ +
So we draw the pattern we want to use to this plane, and it's then used as a render target by a distortion filter on the game plane.\ +
Note the blend mode and lack of relay targets. This plane exists only to distort, it's never rendered anywhere." + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + plane = GRAVITY_PULSE_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + blend_mode = BLEND_ADD + render_target = GRAVITY_PULSE_RENDER_TARGET + render_relay_planes = list() + +///Contains just the floor +/atom/movable/screen/plane_master/floor + name = "Floor" + documentation = "The well, floor. This is mostly used as a sorting mechanism, but it also lets us create a \"border\" around the game world plane, so its drop shadow will actually work." + plane = FLOOR_PLANE + render_relay_planes = list(RENDER_PLANE_GAME, LIGHT_MASK_PLANE) + +/atom/movable/screen/plane_master/transparent_floor + name = "Transparent Floor" + documentation = "Really just openspace, stuff that is a turf but has no color or alpha whatsoever.\ +
We use this to draw to just the light mask plane, cause if it's not there we get holes of blackness over openspace" + plane = TRANSPARENT_FLOOR_PLANE + render_relay_planes = list(LIGHT_MASK_PLANE) + // Needs to be critical or it uh, it'll look white + critical = PLANE_CRITICAL_DISPLAY|PLANE_CRITICAL_NO_RELAY + +/atom/movable/screen/plane_master/floor/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_FLOOR_LAYER, relay_color = GLOB.em_block_color) + +/atom/movable/screen/plane_master/wall + name = "Wall" + documentation = "Holds all walls. We render this onto the game world. Separate so we can use this + space and floor planes as a guide for where byond blackness is NOT." + plane = WALL_PLANE + render_relay_planes = list(RENDER_PLANE_GAME_WORLD, LIGHT_MASK_PLANE) + +/atom/movable/screen/plane_master/wall/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_WALL_LAYER, relay_color = GLOB.em_block_color) + +/atom/movable/screen/plane_master/game + name = "Lower game world" + documentation = "Exists mostly because of FOV shit. Basically, if you've just got a normal not ABOVE fov thing, and you don't want it masked, stick it here yeah?" + plane = GAME_PLANE + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + +/atom/movable/screen/plane_master/game_world_fov_hidden + name = "lower game world fov hidden" + documentation = "If you want something to be hidden by fov, stick it on this plane. We're masked by the fov blocker plane, so the items on us can actually well, disappear." + plane = GAME_PLANE_FOV_HIDDEN + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + +/atom/movable/screen/plane_master/game_world_fov_hidden/Initialize(mapload, datum/hud/hud_owner) + . = ..() + add_filter("vision_cone", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(FIELD_OF_VISION_BLOCKER_RENDER_TARGET, offset), flags = MASK_INVERSE)) + +/atom/movable/screen/plane_master/field_of_vision_blocker + name = "Field of vision blocker" + documentation = "This is one of those planes that's only used as a filter. It masks out things that want to be hidden by fov.\ +
Literally just contains FOV images, or masks." + plane = FIELD_OF_VISION_BLOCKER_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_target = FIELD_OF_VISION_BLOCKER_RENDER_TARGET + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + render_relay_planes = list() + // We do NOT allow offsetting, because there's no case where you would want to block only one layer, at least currently + allows_offsetting = FALSE + start_hidden = TRUE + // We mark as multiz_scaled FALSE so transforms don't effect us, and we draw to the planes below us as if they were us. + // This is safe because we will ALWAYS be on the top z layer, so it DON'T MATTER + multiz_scaled = FALSE + +/atom/movable/screen/plane_master/field_of_vision_blocker/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + mirror_parent_hidden() + +/atom/movable/screen/plane_master/game_world_upper + name = "Upper game world" + documentation = "Ok so fov is kinda fucky, because planes in byond serve both as effect groupings and as rendering orderers. Since that's true, we need a plane that we can stick stuff that draws above fov blocked stuff on." + plane = GAME_PLANE_UPPER + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + +/atom/movable/screen/plane_master/wall_upper + name = "Upper wall" + documentation = "There are some walls that want to render above most things (mostly minerals since they shift over.\ +
We draw them to their own plane so we can hijack them for our emissive mask stuff" + plane = WALL_PLANE_UPPER + render_relay_planes = list(RENDER_PLANE_GAME_WORLD, LIGHT_MASK_PLANE) + +/atom/movable/screen/plane_master/wall_upper/Initialize(mapload, datum/hud/hud_owner, datum/plane_master_group/home, offset) + . = ..() + add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_WALL_LAYER, relay_color = GLOB.em_block_color) + +/atom/movable/screen/plane_master/game_world_upper_fov_hidden + name = "Upper game world fov hidden" + documentation = "Just as we need a place to draw things \"above\" the hidden fov plane, we also need to be able to hide stuff that draws over the upper game plane." + plane = GAME_PLANE_UPPER_FOV_HIDDEN + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + +/atom/movable/screen/plane_master/game_world_upper_fov_hidden/Initialize(mapload, datum/hud/hud_owner) + . = ..() + // Dupe of the other hidden plane + add_filter("vision_cone", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(FIELD_OF_VISION_BLOCKER_RENDER_TARGET, offset), flags = MASK_INVERSE)) + +/atom/movable/screen/plane_master/seethrough + name = "Seethrough" + documentation = "Holds the seethrough versions (done using image overrides) of large objects. Mouse transparent, so you can click through them." + plane = SEETHROUGH_PLANE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + start_hidden = TRUE + +/atom/movable/screen/plane_master/game_world_above + name = "Above game world" + documentation = "We need a place that's unmasked by fov that also draws above the upper game world fov hidden plane. I told you fov was hacky man." + plane = ABOVE_GAME_PLANE + render_relay_planes = list(RENDER_PLANE_GAME_WORLD) + +/** + * Plane master that byond will by default draw to + * Shouldn't be used, exists to prevent people using plane 0 + * NOTE: If we used SEE_BLACKNESS on a map format that wasn't SIDE_MAP, this is where its darkness would land + * This would allow us to control it and do fun things. But we can't because side map doesn't support it, so this is just a stub + */ +/atom/movable/screen/plane_master/default + name = "Default" + documentation = "This is quite fiddly, so bear with me. By default (in byond) everything in the game is rendered onto plane 0. It's the default plane. \ +
But, because we've moved everything we control off plane 0, all that's left is stuff byond internally renders. \ +
What I'd like to do with this is capture byond blackness by giving mobs the SEE_BLACKNESS sight flag. \ +
But we CAN'T because SEE_BLACKNESS does not work with our rendering format. So I just eat it I guess" + plane = DEFAULT_PLANE + multiz_scaled = FALSE + start_hidden = TRUE // Doesn't DO anything, exists to hold this place + +/atom/movable/screen/plane_master/area + name = "Area" + documentation = "Holds the areas themselves, which ends up meaning it holds any overlays/effects we apply to areas. NOT snow or rad storms, those go on above lighting" + plane = AREA_PLANE + +/atom/movable/screen/plane_master/massive_obj + name = "Massive object" + documentation = "Huge objects need to render above everything else on the game plane, otherwise they'd well, get clipped and look not that huge. This does that." + plane = MASSIVE_OBJ_PLANE + +/atom/movable/screen/plane_master/point + name = "Point" + documentation = "I mean like, what do you want me to say? Points draw over pretty much everything else, so they get their own plane. Remember we layer render relays to draw planes in their proper order on render plates." + plane = POINT_PLANE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + +///Contains all turf lighting +/atom/movable/screen/plane_master/turf_lighting + name = "Turf Lighting" + documentation = "Contains all lighting drawn to turfs. Not so complex, draws directly onto the lighting plate." + plane = LIGHTING_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_LIGHTING) + blend_mode_override = BLEND_ADD + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + critical = PLANE_CRITICAL_DISPLAY + +/// This will not work through multiz, because of a byond bug with BLEND_MULTIPLY +/// Bug report is up, waiting on a fix +/atom/movable/screen/plane_master/o_light_visual + name = "Overlight light visual" + documentation = "Holds overlay lighting objects, or the sort of lighting that's a well, overlay stuck to something.\ +
Exists because lighting updating is really slow, and movement needs to feel smooth.\ +
We draw to the game plane, and mask out space for ourselves on the lighting plane so any color we have has the chance to display." + plane = O_LIGHTING_VISUAL_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_target = O_LIGHTING_VISUAL_RENDER_TARGET + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + blend_mode = BLEND_MULTIPLY + critical = PLANE_CRITICAL_DISPLAY + +/atom/movable/screen/plane_master/above_lighting + name = "Above lighting" + plane = ABOVE_LIGHTING_PLANE + documentation = "Anything on the game plane that needs a space to draw on that will be above the lighting plane.\ +
Mostly little alerts and effects, also sometimes contains things that are meant to look as if they glow." + +/** + * Handles emissive overlays and emissive blockers. + */ +/atom/movable/screen/plane_master/emissive + name = "Emissive" + documentation = "Holds things that will be used to mask the lighting plane later on. Masked by the Emissive Mask plane to ensure we don't emiss out under a wall.\ +
Relayed onto the Emissive render plane to do the actual masking of lighting, since we need to be transformed and other emissive stuff needs to be transformed too.\ +
Don't want to double scale now." + plane = EMISSIVE_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + render_relay_planes = list(EMISSIVE_RENDER_PLATE) + critical = PLANE_CRITICAL_DISPLAY + +/atom/movable/screen/plane_master/pipecrawl + name = "Pipecrawl" + documentation = "Holds pipecrawl images generated during well, pipecrawling.\ +
Has a few effects and a funky color matrix designed to make things a bit more visually readable." + plane = PIPECRAWL_IMAGES_PLANE + start_hidden = TRUE + +/atom/movable/screen/plane_master/pipecrawl/Initialize(mapload, datum/hud/hud_owner) + . = ..() + // Makes everything on this plane slightly brighter + // Has a nice effect, makes thing stand out + color = list(1.2,0,0,0, 0,1.2,0,0, 0,0,1.2,0, 0,0,0,1, 0,0,0,0) + // This serves a similar purpose, I want the pipes to pop + add_filter("pipe_dropshadow", 1, drop_shadow_filter(x = -1, y= -1, size = 1, color = "#0000007A")) + mirror_parent_hidden() + +/atom/movable/screen/plane_master/camera_static + name = "Camera static" + documentation = "Holds camera static images. Usually only visible to people who can well, see static.\ +
We use images rather then vis contents because they're lighter on maptick, and maptick sucks butt." + plane = CAMERA_STATIC_PLANE + +/atom/movable/screen/plane_master/camera_static/show_to(mob/mymob) + . = ..() + if(!.) + return + var/datum/hud/our_hud = home.our_hud + if(isnull(our_hud)) + return + + // We'll hide the slate if we're not seeing through a camera eye + // This can call on a cycle cause we don't clear in hide_from + // Yes this is the best way of hooking into the hud, I hate myself too + RegisterSignal(our_hud, COMSIG_HUD_EYE_CHANGED, PROC_REF(eye_changed), override = TRUE) + eye_changed(our_hud, null, our_hud.mymob?.canon_client?.eye) + +/atom/movable/screen/plane_master/camera_static/proc/eye_changed(datum/hud/source, atom/old_eye, atom/new_eye) + SIGNAL_HANDLER + + if(!isaicamera(new_eye)) + if(!force_hidden) + hide_plane(source.mymob) + return + + if(force_hidden) + unhide_plane(source.mymob) + +/atom/movable/screen/plane_master/high_game + name = "High Game" + documentation = "Holds anything that wants to be displayed above the rest of the game plane, and doesn't want to be clickable. \ +
This includes atmos debug overlays, blind sound images, and mining scanners. \ +
Really only exists for its layering potential, we don't use this for any vfx" + plane = HIGH_GAME_PLANE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + +/atom/movable/screen/plane_master/ghost + name = "Ghost" + documentation = "Ghosts draw here, so they don't get mixed up in the visuals of the game world. Note, this is not not how we HIDE ghosts from people, that's done with invisible and see_invisible." + plane = GHOST_PLANE + render_relay_planes = list(RENDER_PLANE_NON_GAME) + +/atom/movable/screen/plane_master/fullscreen + name = "Fullscreen" + documentation = "Holds anything that applies to or above the full screen. \ +
Note, it's still rendered underneath hud objects, but this lets us control the order that things like death/damage effects render in." + plane = FULLSCREEN_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_NON_GAME) + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + allows_offsetting = FALSE + +/atom/movable/screen/plane_master/runechat + name = "Runechat" + documentation = "Holds runechat images, that text that pops up when someone say something. Uses a dropshadow to well, look nice." + plane = RUNECHAT_PLANE + render_relay_planes = list(RENDER_PLANE_NON_GAME) + +/atom/movable/screen/plane_master/runechat/show_to(mob/mymob) + . = ..() + if(!.) + return + remove_filter("AO") + if(istype(mymob) && mymob.canon_client?.prefs?.read_preference(/datum/preference/toggle/ambient_occlusion)) + add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA")) + +/atom/movable/screen/plane_master/balloon_chat + name = "Balloon chat" + documentation = "Holds ballon chat images, those little text bars that pop up for a second when you do some things. NOT runechat." + plane = BALLOON_CHAT_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_NON_GAME) + +/atom/movable/screen/plane_master/hud + name = "HUD" + documentation = "Contains anything that want to be rendered on the hud. Typically is just screen elements." + plane = HUD_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_NON_GAME) + allows_offsetting = FALSE + +/atom/movable/screen/plane_master/above_hud + name = "Above HUD" + documentation = "Anything that wants to be drawn ABOVE the rest of the hud. Typically close buttons and other elements that need to be always visible. Think preventing draggable action button memes." + plane = ABOVE_HUD_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_NON_GAME) + allows_offsetting = FALSE + +/atom/movable/screen/plane_master/splashscreen + name = "Splashscreen" + documentation = "Cinematics and the splash screen." + plane = SPLASHSCREEN_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_NON_GAME) + allows_offsetting = FALSE + +/atom/movable/screen/plane_master/escape_menu + name = "Escape Menu" + documentation = "Anything relating to the escape menu." + plane = ESCAPE_MENU_PLANE + appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR + render_relay_planes = list(RENDER_PLANE_MASTER) + allows_offsetting = FALSE diff --git a/code/_onclick/hud/rendering/plane_masters/simple_plane_masters.dm b/code/_onclick/hud/rendering/plane_masters/simple_plane_masters.dm deleted file mode 100644 index ea0ad21a773..00000000000 --- a/code/_onclick/hud/rendering/plane_masters/simple_plane_masters.dm +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Put plane masters that are just a simple type def in here, anything more complex should get its own file - */ - -/atom/movable/screen/plane_master/gravpulse - name = "Gravpulse" - documentation = "Ok so this one's fun. Basically, we want to be able to distort the game plane when a grav annom is around.\ -
So we draw the pattern we want to use to this plane, and it's then used as a render target by a distortion filter on the game plane.\ -
Note the blend mode and lack of relay targets. This plane exists only to distort, it's never rendered anywhere." - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - plane = GRAVITY_PULSE_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - blend_mode = BLEND_ADD - render_target = GRAVITY_PULSE_RENDER_TARGET - render_relay_planes = list() - -/atom/movable/screen/plane_master/seethrough - name = "Seethrough" - documentation = "Holds the seethrough versions (done using image overrides) of large objects. Mouse transparent, so you can click through them." - plane = SEETHROUGH_PLANE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - render_relay_planes = list(RENDER_PLANE_GAME_WORLD) - start_hidden = TRUE - -/atom/movable/screen/plane_master/massive_obj - name = "Massive object" - documentation = "Huge objects need to render above everything else on the game plane, otherwise they'd well, get clipped and look not that huge. This does that." - plane = MASSIVE_OBJ_PLANE - -/atom/movable/screen/plane_master/point - name = "Point" - documentation = "I mean like, what do you want me to say? Points draw over pretty much everything else, so they get their own plane. Remember we layer render relays to draw planes in their proper order on render plates." - plane = POINT_PLANE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - -/atom/movable/screen/plane_master/ghost - name = "Ghost" - documentation = "Ghosts draw here, so they don't get mixed up in the visuals of the game world. Note, this is not not how we HIDE ghosts from people, that's done with invisible and see_invisible." - plane = GHOST_PLANE - render_relay_planes = list(RENDER_PLANE_NON_GAME) - -/atom/movable/screen/plane_master/fullscreen - name = "Fullscreen" - documentation = "Holds anything that applies to or above the full screen. \ -
Note, it's still rendered underneath hud objects, but this lets us control the order that things like death/damage effects render in." - plane = FULLSCREEN_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_NON_GAME) - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - allows_offsetting = FALSE - -/atom/movable/screen/plane_master/hud - name = "HUD" - documentation = "Contains anything that want to be rendered on the hud. Typically is just screen elements." - plane = HUD_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_NON_GAME) - allows_offsetting = FALSE - -/atom/movable/screen/plane_master/above_hud - name = "Above HUD" - documentation = "Anything that wants to be drawn ABOVE the rest of the hud. Typically close buttons and other elements that need to be always visible. Think preventing draggable action button memes." - plane = ABOVE_HUD_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_NON_GAME) - allows_offsetting = FALSE - -/atom/movable/screen/plane_master/splashscreen - name = "Splashscreen" - documentation = "Cinematics and the splash screen." - plane = SPLASHSCREEN_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_NON_GAME) - allows_offsetting = FALSE - -/atom/movable/screen/plane_master/escape_menu - name = "Escape Menu" - documentation = "Anything relating to the escape menu." - plane = ESCAPE_MENU_PLANE - appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR - render_relay_planes = list(RENDER_PLANE_MASTER) - allows_offsetting = FALSE diff --git a/tgstation.dme b/tgstation.dme index 71bad6e81c2..4f06ab780c4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -674,15 +674,7 @@ #include "code\_onclick\hud\rendering\plane_master_group.dm" #include "code\_onclick\hud\rendering\render_plate.dm" #include "code\_onclick\hud\rendering\plane_masters\_plane_master.dm" -#include "code\_onclick\hud\rendering\plane_masters\camera_static.dm" -#include "code\_onclick\hud\rendering\plane_masters\clickcatcher.dm" -#include "code\_onclick\hud\rendering\plane_masters\core_game_planes.dm" -#include "code\_onclick\hud\rendering\plane_masters\default.dm" -#include "code\_onclick\hud\rendering\plane_masters\in_world_chat.dm" -#include "code\_onclick\hud\rendering\plane_masters\lighting.dm" -#include "code\_onclick\hud\rendering\plane_masters\parallax.dm" -#include "code\_onclick\hud\rendering\plane_masters\pipecrawl.dm" -#include "code\_onclick\hud\rendering\plane_masters\simple_plane_masters.dm" +#include "code\_onclick\hud\rendering\plane_masters\plane_master_subtypes.dm" #include "code\controllers\admin.dm" #include "code\controllers\controller.dm" #include "code\controllers\failsafe.dm" From 8d52efcbe457be6a256073c0079ab31279627598 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:33:25 +0300 Subject: [PATCH 04/55] [MIRROR] Makes the SC/FISHER a bit better - more range/accessibility/pacifist-usability [MDB IGNORE] (#744) * Makes the SC/FISHER a bit better - more range/accessibility/pacifist-usability (#79835) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Hatterhat <31829017+Hatterhat@users.noreply.github.com> Co-authored-by: Hatterhat --- code/modules/cargo/markets/market_items/weapons.dm | 2 +- code/modules/projectiles/ammunition/energy/special.dm | 3 ++- code/modules/projectiles/projectile/special/lightbreaker.dm | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/code/modules/cargo/markets/market_items/weapons.dm b/code/modules/cargo/markets/market_items/weapons.dm index 6115b1e1557..ee16daae7d5 100644 --- a/code/modules/cargo/markets/market_items/weapons.dm +++ b/code/modules/cargo/markets/market_items/weapons.dm @@ -72,4 +72,4 @@ price_min = CARGO_CRATE_VALUE * 2 price_max = CARGO_CRATE_VALUE * 4 stock_max = 1 - availability_prob = 50 + availability_prob = 75 diff --git a/code/modules/projectiles/ammunition/energy/special.dm b/code/modules/projectiles/ammunition/energy/special.dm index 9a733dbc47a..5a83a944e41 100644 --- a/code/modules/projectiles/ammunition/energy/special.dm +++ b/code/modules/projectiles/ammunition/energy/special.dm @@ -81,6 +81,7 @@ /obj/item/ammo_casing/energy/fisher projectile_type = /obj/projectile/energy/fisher - select_name = "light-buster" + select_name = "light disruptor" + harmful = FALSE e_cost = LASER_SHOTS(2, STANDARD_CELL_CHARGE * 0.5) fire_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg' // fwip fwip fwip fwip diff --git a/code/modules/projectiles/projectile/special/lightbreaker.dm b/code/modules/projectiles/projectile/special/lightbreaker.dm index fd7d3d89e7a..2be6d9e4470 100644 --- a/code/modules/projectiles/projectile/special/lightbreaker.dm +++ b/code/modules/projectiles/projectile/special/lightbreaker.dm @@ -4,7 +4,7 @@ damage = 0 damage_type = BRUTE armor_flag = BOMB - range = 14 + range = 21 projectile_phasing = PASSTABLE | PASSMOB | PASSMACHINE | PASSSTRUCTURE hitscan = TRUE var/disrupt_duration = 10 SECONDS From 4cdc29ab93773010375163ce4c1e538a084d246b Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:34:22 +0300 Subject: [PATCH 05/55] [MODULAR] Icemoon additions: mob naming potions and other minor improvements (#746) * Add icewalker mob renaming potion, pet health indicators on examine_more (with improved messaging) and glowshroom mycelium to hearth seed barrels * Modularise * Further modularisation changes * Fix overloaded proc * Avoid single-letter variables * Update modular_skyrat/modules/icemoon_additions/code/icecat_recipes.dm * Wrap anointing proc to avoid item state breaking on runtime --------- Co-authored-by: Ephemeralis Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- .../icemoon_underground_icewalker_lower.dmm | 1 + .../ashwalkers/code/effects/ash_rituals.dm | 2 +- .../icemoon_additions/code/icecat_recipes.dm | 66 +++++++++++++++++++ .../icemoon_additions/code/pet_commands.dm | 29 ++++++++ .../primitive_catgirls/code/spawner.dm | 1 + tgstation.dme | 2 + 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 modular_skyrat/modules/icemoon_additions/code/icecat_recipes.dm create mode 100644 modular_skyrat/modules/icemoon_additions/code/pet_commands.dm diff --git a/_maps/RandomRuins/IceRuins/skyrat/icemoon_underground_icewalker_lower.dmm b/_maps/RandomRuins/IceRuins/skyrat/icemoon_underground_icewalker_lower.dmm index 8ea8983ce52..4e5a3e21f19 100644 --- a/_maps/RandomRuins/IceRuins/skyrat/icemoon_underground_icewalker_lower.dmm +++ b/_maps/RandomRuins/IceRuins/skyrat/icemoon_underground_icewalker_lower.dmm @@ -1873,6 +1873,7 @@ /obj/item/seeds/tower{ pixel_y = -3 }, +/obj/item/seeds/glowshroom, /obj/item/seeds/poppy, /obj/item/seeds/reishi, /obj/item/seeds/reishi, diff --git a/modular_skyrat/modules/ashwalkers/code/effects/ash_rituals.dm b/modular_skyrat/modules/ashwalkers/code/effects/ash_rituals.dm index 7b38a565698..a4ca86c4f18 100644 --- a/modular_skyrat/modules/ashwalkers/code/effects/ash_rituals.dm +++ b/modular_skyrat/modules/ashwalkers/code/effects/ash_rituals.dm @@ -202,7 +202,7 @@ /mob/living/basic/mining/ice_whelp, /mob/living/basic/mining/lobstrosity, /mob/living/simple_animal/hostile/asteroid/polarbear, - /mob/living/simple_animal/hostile/asteroid/wolf, + /mob/living/basic/mining/wolf, ) new mob_type(success_rune.loc) diff --git a/modular_skyrat/modules/icemoon_additions/code/icecat_recipes.dm b/modular_skyrat/modules/icemoon_additions/code/icecat_recipes.dm new file mode 100644 index 00000000000..8467bb2f929 --- /dev/null +++ b/modular_skyrat/modules/icemoon_additions/code/icecat_recipes.dm @@ -0,0 +1,66 @@ +/obj/item/anointing_oil + name = "anointing bloodresin" + desc = "And so Helgar Knife-Arm spoke to the Hearth, and decreed that all of the Kin who gave name to beasts would do so with conquest and blood." + icon = 'icons/obj/medical/chemical.dmi' + icon_state = "potred" + throwforce = 0 + w_class = WEIGHT_CLASS_TINY + + var/being_used = FALSE + +/obj/item/anointing_oil/attack(mob/living/target_mob, mob/living/user, params) + if (!is_species(user, /datum/species/human/felinid/primitive)) + to_chat(user, span_warning("You have no idea what this disgusting concoction is used for.")) + return + if(being_used || !ismob(target_mob)) //originally this was going to check if the mob was friendly, but if an icecat wants to name some terror mob while it's tearing chunks out of them, why not? + return + if(target_mob.ckey) + to_chat(user, span_warning("You would never shame a creature so intelligent by not allowing it to choose its own name.")) + return + + if(try_anoint(target_mob, user)) + qdel(src) + else + being_used = FALSE + +/obj/item/anointing_oil/proc/try_anoint(mob/living/target_mob, mob/living/user) + being_used = TRUE + + var/new_name = sanitize_name(tgui_input_text(user, "Speak forth this beast's new name for all the Kin to hear.", "Input a name", target_mob.name, MAX_NAME_LEN)) + + if(!new_name || QDELETED(src) || QDELETED(target_mob) || new_name == target_mob.name || !target_mob.Adjacent(user)) + being_used = FALSE + return FALSE + + target_mob.visible_message(span_notice("[user] leans down and smears twinned streaks of glistening bloodresin upon [target_mob], then straightens up with ritual purpose...")) + user.say("Let the ice know you forevermore as +[new_name]+.") + + user.log_message("used [src] on [target_mob], renaming it to [new_name].", LOG_GAME) + + target_mob.name = new_name + + //give the stupid dog zoomies from getting named + if(istype(target_mob, /mob/living/basic/mining/wolf)) + target_mob.emote("awoo") + target_mob.emote("spin") + + return TRUE + +/obj/item/anointing_oil/examine(mob/user) + . = ..() + if(is_species(user, /datum/species/human/felinid/primitive)) + . += span_info("Using this on the local wildlife will allow you to give them a name.") + +/datum/crafting_recipe/anointing_oil + name = "Anointing Bloodresin" + category = CAT_MISC + + //recipe given to icecats as part of their spawner/team setting + always_available = FALSE + + reqs = list( + /datum/reagent/consumable/liquidgibs = 80, + /datum/reagent/blood = 20, + ) + + result = /obj/item/anointing_oil diff --git a/modular_skyrat/modules/icemoon_additions/code/pet_commands.dm b/modular_skyrat/modules/icemoon_additions/code/pet_commands.dm new file mode 100644 index 00000000000..42d202d572a --- /dev/null +++ b/modular_skyrat/modules/icemoon_additions/code/pet_commands.dm @@ -0,0 +1,29 @@ +/datum/component/obeys_commands/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examine_more)) + +/datum/component/obeys_commands/UnregisterFromParent() + . = ..() + UnregisterSignal(parent, COMSIG_ATOM_EXAMINE_MORE) + +/datum/component/obeys_commands/on_examine(mob/living/source, mob/user, list/examine_list) + . = ..() + . += span_italics("You can alt+click [source.p_them()] when adjacent to see available commands.") + . += span_italics("You can also examine [source.p_them()] closely to check on [source.p_their()] wounds. Many companions can be healed with sutures or creams!") + +/datum/component/obeys_commands/proc/on_examine_more(mob/living/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + if (IS_DEAD_OR_INCAP(source)) + return + if (!(user in source.ai_controller?.blackboard[BB_FRIENDS_LIST])) + return + + if (source.health < source.maxHealth*0.2) + examine_list += span_bolddanger("[source.p_They()] look[source.p_s()] severely injured.") + else if (source.health < source.maxHealth*0.5) + examine_list += span_danger("[source.p_They()] look[source.p_s()] moderately injured.") + else if (source.health < source.maxHealth*0.8) + examine_list += span_warning("[source.p_They()] look[source.p_s()] slightly injured.") + else + examine_list += span_notice("[source.p_They()] look[source.p_s()] to be in good condition.") diff --git a/modular_skyrat/modules/primitive_catgirls/code/spawner.dm b/modular_skyrat/modules/primitive_catgirls/code/spawner.dm index 2e2d9ec0d17..3bed64d3935 100644 --- a/modular_skyrat/modules/primitive_catgirls/code/spawner.dm +++ b/modular_skyrat/modules/primitive_catgirls/code/spawner.dm @@ -101,6 +101,7 @@ /datum/crafting_recipe/boneaxe, /datum/crafting_recipe/bonespear, /datum/crafting_recipe/bonedagger, + /datum/crafting_recipe/anointing_oil, ) /datum/antagonist/primitive_catgirl/Destroy() diff --git a/tgstation.dme b/tgstation.dme index 4f06ab780c4..985c341219b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7161,6 +7161,8 @@ #include "modular_skyrat\modules\hyposprays\code\hyposprays_II.dm" #include "modular_skyrat\modules\hyposprays\code\hypovials.dm" #include "modular_skyrat\modules\hyposprays\code\vending_hypospray.dm" +#include "modular_skyrat\modules\icemoon_additions\code\icecat_recipes.dm" +#include "modular_skyrat\modules\icemoon_additions\code\pet_commands.dm" #include "modular_skyrat\modules\ices_events\code\_ICES_globalvars.dm" #include "modular_skyrat\modules\ices_events\code\ICES_event_config.dm" #include "modular_skyrat\modules\ices_events\code\ICES_intensity_credits.dm" From 024e26b857f40a7514da72069e9675ae34e4699c Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:36:48 +0300 Subject: [PATCH 06/55] [MIRROR] Adds `UPSIDE_DOWN` movetype for negative gravity / makes Atrocinator affected by less things [MDB IGNORE] (#749) * Adds `UPSIDE_DOWN` movetype for negative gravity / makes Atrocinator affected by less things (#79785) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Ghom <42542238+Ghommie@ users.noreply.github.com> --- code/__DEFINES/_flags.dm | 5 ++++ code/__DEFINES/traits/declarations.dm | 2 +- code/__DEFINES/traits/sources.dm | 1 + code/_globalvars/bitfields.dm | 1 + code/_globalvars/traits/_traits.dm | 2 ++ code/_globalvars/traits/admin_tooling.dm | 1 + code/datums/components/acid.dm | 2 +- code/datums/components/caltrop.dm | 2 +- code/datums/components/chasm.dm | 2 +- code/datums/components/conveyor_movement.dm | 2 +- code/datums/components/slippery.dm | 2 +- code/datums/components/squashable.dm | 2 +- code/datums/components/squeak.dm | 2 +- code/datums/elements/immerse.dm | 12 ++++---- code/datums/status_effects/wound_effects.dm | 2 +- .../weather/weather_types/floor_is_lava.dm | 2 +- code/game/objects/effects/mines.dm | 2 +- code/game/objects/items/handcuffs.dm | 29 ++++++++++++++----- .../game/objects/items/stacks/sheets/glass.dm | 2 +- code/game/objects/items/syndie_spraycan.dm | 2 +- code/game/objects/structures/kitchen_spike.dm | 2 ++ code/game/objects/structures/railings.dm | 4 +-- code/game/objects/structures/tables_racks.dm | 2 +- code/game/turfs/open/_open.dm | 3 +- code/game/turfs/open/lava.dm | 4 +-- code/modules/assembly/mousetrap.dm | 2 +- code/modules/clothing/glasses/_glasses.dm | 2 +- .../mega_arachnid/mega_arachnid_abilities.dm | 2 +- .../space_fauna/meteor_heart/spine_traps.dm | 2 +- .../mob/living/carbon/carbon_movement.dm | 2 +- code/modules/mob/living/living.dm | 2 ++ code/modules/mod/modules/modules_maint.dm | 2 ++ code/modules/power/lighting/light_items.dm | 2 +- .../projectile/energy/net_snare.dm | 4 +-- 34 files changed, 71 insertions(+), 41 deletions(-) diff --git a/code/__DEFINES/_flags.dm b/code/__DEFINES/_flags.dm index e0b88066d7d..f5fc50004cd 100644 --- a/code/__DEFINES/_flags.dm +++ b/code/__DEFINES/_flags.dm @@ -163,6 +163,11 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define FLOATING (1<<3) /// When moving, will Cross() everything, but won't stop or Bump() anything. #define PHASING (1<<4) +/// The mob is walking on the ceiling. Or is generally just, upside down. +#define UPSIDE_DOWN (1<<5) + +/// Combination flag for movetypes which, for all intents and purposes, mean the mob is not touching the ground +#define MOVETYPES_NOT_TOUCHING_GROUND (FLYING|FLOATING|UPSIDE_DOWN) //Fire and Acid stuff, for resistance_flags #define LAVA_PROOF (1<<0) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index a614d1974df..33f0d900cc1 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -529,6 +529,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_MOVE_VENTCRAWLING "move_ventcrawling" #define TRAIT_MOVE_FLOATING "move_floating" #define TRAIT_MOVE_PHASING "move_phasing" +#define TRAIT_MOVE_UPSIDE_DOWN "move_upside_down" /// Disables the floating animation. See above. #define TRAIT_NO_FLOATING_ANIM "no-floating-animation" @@ -841,7 +842,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// changelings with this trait can no longer talk over the hivemind #define TRAIT_CHANGELING_HIVEMIND_MUTE "ling_mute" #define TRAIT_HULK "hulk" - /// Isn't attacked harmfully by blob structures #define TRAIT_BLOB_ALLY "blob_ally" diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm index 3ba0008acb2..6be8cdf3f8d 100644 --- a/code/__DEFINES/traits/sources.dm +++ b/code/__DEFINES/traits/sources.dm @@ -136,6 +136,7 @@ #define SPECIES_FLIGHT_TRAIT "species-flight" #define FROSTMINER_ENRAGE_TRAIT "frostminer-enrage" #define NO_GRAVITY_TRAIT "no-gravity" +#define NEGATIVE_GRAVITY_TRAIT "negative-gravity" /// A trait gained from a mob's leap action, like the leaper #define LEAPING_TRAIT "leaping" diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 27c6de53b53..796def0de16 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -283,6 +283,7 @@ DEFINE_BITFIELD(movement_type, list( "GROUND" = GROUND, "PHASING" = PHASING, "VENTCRAWLING" = VENTCRAWLING, + "UPSIDE_DOWN" = UPSIDE_DOWN, )) DEFINE_BITFIELD(obj_flags, list( diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index c373be5b149..d76376ded36 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -48,6 +48,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_MOVE_GROUND" = TRAIT_MOVE_GROUND, "TRAIT_MOVE_PHASING" = TRAIT_MOVE_PHASING, "TRAIT_MOVE_VENTCRAWLING" = TRAIT_MOVE_VENTCRAWLING, + "TRAIT_MOVE_UPSIDE_DOWN" = TRAIT_MOVE_UPSIDE_DOWN, "TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM, "TRAIT_NO_MANIFEST_CONTENTS_ERROR" = TRAIT_NO_MANIFEST_CONTENTS_ERROR, "TRAIT_NO_MISSING_ITEM_ERROR" = TRAIT_NO_MISSING_ITEM_ERROR, @@ -569,6 +570,7 @@ GLOBAL_LIST_INIT(movement_type_trait_to_flag, list( TRAIT_MOVE_VENTCRAWLING = VENTCRAWLING, TRAIT_MOVE_FLOATING = FLOATING, TRAIT_MOVE_PHASING = PHASING, + TRAIT_MOVE_UPSIDE_DOWN = UPSIDE_DOWN, )) GLOBAL_LIST_INIT(movement_type_addtrait_signals, set_movement_type_addtrait_signals()) diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index d5d19a25f39..388ea89cc7e 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -15,6 +15,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_MOVE_GROUND" = TRAIT_MOVE_GROUND, "TRAIT_MOVE_PHASING" = TRAIT_MOVE_PHASING, "TRAIT_MOVE_VENTCRAWLING" = TRAIT_MOVE_VENTCRAWLING, + "TRAIT_MOVE_UPSIDE_DOWN" = TRAIT_MOVE_UPSIDE_DOWN, "TRAIT_RUNECHAT_HIDDEN" = TRAIT_RUNECHAT_HIDDEN, "TRAIT_SNOWSTORM_IMMUNE" = TRAIT_SNOWSTORM_IMMUNE, "TRAIT_VOIDSTORM_IMMUNE" = TRAIT_VOIDSTORM_IMMUNE, diff --git a/code/datums/components/acid.dm b/code/datums/components/acid.dm index 1d9cf9e87d6..67be754c504 100644 --- a/code/datums/components/acid.dm +++ b/code/datums/components/acid.dm @@ -254,7 +254,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e if(!isliving(arrived)) return var/mob/living/crosser = arrived - if(crosser.movement_type & FLYING) + if(crosser.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return if(crosser.move_intent == MOVE_INTENT_WALK) return diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm index 45a9d1976c5..0ec866960e3 100644 --- a/code/datums/components/caltrop.dm +++ b/code/datums/components/caltrop.dm @@ -78,7 +78,7 @@ if((flags & CALTROP_IGNORE_WALKERS) && H.move_intent == MOVE_INTENT_WALK) return - if(H.movement_type & (FLOATING|FLYING)) //check if they are able to pass over us + if(H.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) //check if they are able to pass over us //gravity checking only our parent would prevent us from triggering they're using magboots / other gravity assisting items that would cause them to still touch us. return diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm index 18420016c54..f85ca347aa0 100644 --- a/code/datums/components/chasm.dm +++ b/code/datums/components/chasm.dm @@ -101,7 +101,7 @@ return CHASM_NOT_DROPPING if(is_type_in_typecache(dropped_thing, forbidden_types) || (!isliving(dropped_thing) && !isobj(dropped_thing))) return CHASM_NOT_DROPPING - if(dropped_thing.throwing || (dropped_thing.movement_type & (FLOATING|FLYING))) + if(dropped_thing.throwing || (dropped_thing.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) return CHASM_REGISTER_SIGNALS //Flies right over the chasm diff --git a/code/datums/components/conveyor_movement.dm b/code/datums/components/conveyor_movement.dm index 4439b08e0a7..d8affca3649 100644 --- a/code/datums/components/conveyor_movement.dm +++ b/code/datums/components/conveyor_movement.dm @@ -24,7 +24,7 @@ source.delay = speed //We use the default delay if(living_parent) var/mob/living/moving_mob = parent - if((moving_mob.movement_type & FLYING) && !moving_mob.stat) + if((moving_mob.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) && !moving_mob.stat) return MOVELOOP_SKIP_STEP var/atom/movable/moving_parent = parent if(moving_parent.anchored || !moving_parent.has_gravity()) diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm index 2119c8ad7e1..620f6baa816 100644 --- a/code/datums/components/slippery.dm +++ b/code/datums/components/slippery.dm @@ -161,7 +161,7 @@ if(HAS_TRAIT(turf, TRAIT_TURF_IGNORE_SLIPPERY)) return var/mob/living/victim = arrived - if((victim.movement_type & (FLYING | FLOATING))) + if(victim.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return if(can_slip_callback && !can_slip_callback.Invoke(holder, victim)) return diff --git a/code/datums/components/squashable.dm b/code/datums/components/squashable.dm index 8174127aeb3..86135faa7bb 100644 --- a/code/datums/components/squashable.dm +++ b/code/datums/components/squashable.dm @@ -54,7 +54,7 @@ return //Everything worked, we're done! if(isliving(crossing_movable)) var/mob/living/crossing_mob = crossing_movable - if(crossing_mob.mob_size > MOB_SIZE_SMALL && !(crossing_mob.movement_type & FLYING)) + if(crossing_mob.mob_size > MOB_SIZE_SMALL && !(crossing_mob.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) if(HAS_TRAIT(crossing_mob, TRAIT_PACIFISM)) crossing_mob.visible_message(span_notice("[crossing_mob] carefully steps over [parent_as_living]."), span_notice("You carefully step over [parent_as_living] to avoid hurting it.")) return diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm index af0686fd1eb..c5d42797ab4 100644 --- a/code/datums/components/squeak.dm +++ b/code/datums/components/squeak.dm @@ -98,7 +98,7 @@ var/obj/item/I = arrived if(I.item_flags & ABSTRACT) return - if(arrived.movement_type & (FLYING|FLOATING) || !arrived.has_gravity()) + if((arrived.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || !arrived.has_gravity()) return if(ismob(arrived) && !arrived.density) // Prevents 10 overlapping mice from making an unholy sound while moving return diff --git a/code/datums/elements/immerse.dm b/code/datums/elements/immerse.dm index 6449d8de1ad..1a3b37d6530 100644 --- a/code/datums/elements/immerse.dm +++ b/code/datums/elements/immerse.dm @@ -229,7 +229,7 @@ */ /datum/element/immerse/proc/try_immerse(atom/movable/movable, atom/movable/buckled) var/atom/movable/to_check = buckled || movable - if(!(to_check.movement_type & (FLYING|FLOATING)) && !movable.throwing) + if(!(to_check.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) && !movable.throwing) add_immerse_overlay(movable) if(!buckled) RegisterSignal(movable, COMSIG_MOVETYPE_FLAG_ENABLED, PROC_REF(on_move_flag_enabled)) @@ -243,7 +243,7 @@ */ /datum/element/immerse/proc/try_unimmerse(atom/movable/movable, atom/movable/buckled) var/atom/movable/to_check = buckled || movable - if(!(to_check.movement_type & (FLYING|FLOATING)) && !movable.throwing) + if(!(to_check.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) && !movable.throwing) remove_immerse_overlay(movable) if(!buckled) UnregisterSignal(movable, list(COMSIG_MOVETYPE_FLAG_ENABLED, COMSIG_MOVETYPE_FLAG_DISABLED, COMSIG_MOVABLE_POST_THROW, COMSIG_MOVABLE_THROW_LANDED)) @@ -256,7 +256,7 @@ ///Removes the overlay from mob and bucklees is flying. /datum/element/immerse/proc/on_move_flag_enabled(atom/movable/source, flag, old_movement_type) SIGNAL_HANDLER - if(!(flag & (FLYING|FLOATING)) || old_movement_type & (FLYING|FLOATING) || source.throwing) + if(!(flag & MOVETYPES_NOT_TOUCHING_GROUND) || (old_movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || source.throwing) return remove_immerse_overlay(source) for(var/mob/living/buckled_mob as anything in source.buckled_mobs) @@ -265,7 +265,7 @@ ///Works just like on_move_flag_enabled, except it only has to check that movable isn't flying /datum/element/immerse/proc/on_throw(atom/movable/source) SIGNAL_HANDLER - if(source.movement_type & (FLYING|FLOATING)) + if(source.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return remove_immerse_overlay(source) for(var/mob/living/buckled_mob as anything in source.buckled_mobs) @@ -274,7 +274,7 @@ ///Readds the overlay to the mob and bucklees if no longer flying. /datum/element/immerse/proc/on_move_flag_disabled(atom/movable/source, flag, old_movement_type) SIGNAL_HANDLER - if(!(flag & (FLYING|FLOATING)) || source.movement_type & (FLYING|FLOATING) || source.throwing) + if(!(flag & MOVETYPES_NOT_TOUCHING_GROUND) || (source.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || source.throwing) return add_immerse_overlay(source) for(var/mob/living/buckled_mob as anything in source.buckled_mobs) @@ -283,7 +283,7 @@ ///Works just like on_move_flag_disabled, except it only has to check that movable isn't flying /datum/element/immerse/proc/on_throw_landed(atom/movable/source) SIGNAL_HANDLER - if(source.movement_type & (FLYING|FLOATING)) + if(source.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return add_immerse_overlay(source) for(var/mob/living/buckled_mob as anything in source.buckled_mobs) diff --git a/code/datums/status_effects/wound_effects.dm b/code/datums/status_effects/wound_effects.dm index 6ec793c5672..f7d640a6d1c 100644 --- a/code/datums/status_effects/wound_effects.dm +++ b/code/datums/status_effects/wound_effects.dm @@ -67,7 +67,7 @@ /datum/status_effect/limp/proc/check_step(mob/whocares, OldLoc, Dir, forced) SIGNAL_HANDLER - if(!owner.client || owner.body_position == LYING_DOWN || !owner.has_gravity() || (owner.movement_type & FLYING) || forced || owner.buckled) + if(!owner.client || owner.body_position == LYING_DOWN || !owner.has_gravity() || (owner.movement_type & (FLYING|FLOATING)) || forced || owner.buckled) return // less limping while we have determination still diff --git a/code/datums/weather/weather_types/floor_is_lava.dm b/code/datums/weather/weather_types/floor_is_lava.dm index df4e9eec0f0..03ed0c68c31 100644 --- a/code/datums/weather/weather_types/floor_is_lava.dm +++ b/code/datums/weather/weather_types/floor_is_lava.dm @@ -39,7 +39,7 @@ for(var/obj/structure/structure_to_check in mob_turf) if(structure_to_check.density) return FALSE - if(mob_to_check.movement_type & (FLYING|FLOATING)) + if(mob_to_check.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return FALSE /datum/weather/floor_is_lava/weather_act(mob/living/victim) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index 1ea301a1427..0731cf8c0c6 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -71,7 +71,7 @@ return FALSE living_mob = on_who - if(living_mob?.incorporeal_move || on_who.movement_type & FLYING) + if(living_mob?.incorporeal_move || (on_who.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) return foot_on_mine ? IS_WEAKREF_OF(on_who, foot_on_mine) : FALSE //Only go boom if their foot was on the mine PRIOR to flying/phasing. You fucked up, you live with the consequences. return TRUE diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 5472f880755..45aed58c91c 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -380,7 +380,7 @@ . = ..() update_appearance() var/static/list/loc_connections = list( - COMSIG_ATOM_ENTERED = PROC_REF(spring_trap), + COMSIG_ATOM_ENTERED = PROC_REF(trap_stepped_on), ) AddElement(/datum/element/connect_loc, loc_connections) @@ -412,10 +412,23 @@ update_appearance() playsound(src, 'sound/effects/snap.ogg', 50, TRUE) -/obj/item/restraints/legcuffs/beartrap/proc/spring_trap(datum/source, atom/movable/target, thrown_at = FALSE) +/obj/item/restraints/legcuffs/beartrap/proc/trap_stepped_on(datum/source, atom/movable/entering, ...) SIGNAL_HANDLER + + spring_trap(entering) + +/** + * Tries to spring the trap on the target movable. + * + * This proc is safe to call without knowing if the target is valid or if the trap is armed. + * + * Does not trigger on tiny mobs. + * If ignore_movetypes is FALSE, does not trigger on floating / flying / etc. mobs. + */ +/obj/item/restraints/legcuffs/beartrap/proc/spring_trap(atom/movable/target, ignore_movetypes = FALSE) if(!armed || !isturf(loc) || !isliving(target)) return + var/mob/living/victim = target if(istype(victim.buckled, /obj/vehicle)) var/obj/vehicle/ridden_vehicle = victim.buckled @@ -424,12 +437,14 @@ ridden_vehicle.visible_message(span_danger("[ridden_vehicle] triggers \the [src].")) return - //don't close the trap if they're as small as a mouse, or not touching the ground - if(victim.mob_size <= MOB_SIZE_TINY || (!thrown_at && victim.movement_type & (FLYING|FLOATING))) + //don't close the trap if they're as small as a mouse + if(victim.mob_size <= MOB_SIZE_TINY) + return + if(!ignore_movetypes && (victim.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) return close_trap() - if(thrown_at) + if(ignore_movetypes) victim.visible_message(span_danger("\The [src] ensnares [victim]!"), \ span_userdanger("\The [src] ensnares you!")) else @@ -477,7 +492,7 @@ qdel(src) /obj/item/restraints/legcuffs/beartrap/energy/attack_hand(mob/user, list/modifiers) - spring_trap(null, user) + spring_trap(user) return ..() /obj/item/restraints/legcuffs/beartrap/energy/cyborg @@ -554,7 +569,7 @@ /obj/item/restraints/legcuffs/bola/energy/ensnare(atom/hit_atom) var/obj/item/restraints/legcuffs/beartrap/energy/cyborg/B = new (get_turf(hit_atom)) - B.spring_trap(null, hit_atom, TRUE) + B.spring_trap(hit_atom, ignore_movetypes = TRUE) qdel(src) /** diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index e198ff6121d..7a180bc5dbd 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -388,7 +388,7 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list( SIGNAL_HANDLER if(isliving(AM)) var/mob/living/L = AM - if(!(L.movement_type & (FLYING|FLOATING)) || L.buckled) + if(!(L.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || L.buckled) playsound(src, 'sound/effects/footstep/glass_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 30 : 50, TRUE) /obj/item/shard/plasma diff --git a/code/game/objects/items/syndie_spraycan.dm b/code/game/objects/items/syndie_spraycan.dm index 78ffb6a4772..deab6229a28 100644 --- a/code/game/objects/items/syndie_spraycan.dm +++ b/code/game/objects/items/syndie_spraycan.dm @@ -181,7 +181,7 @@ * * victim - whoever just slipped, point and laugh at them */ /obj/effect/decal/cleanable/traitor_rune/proc/slip(mob/living/victim) - if(victim.movement_type & FLYING) + if(victim.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return if (!victim.slip(slip_time, src, slip_flags)) return diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index 1b2816d73db..fd4daaeaa18 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -125,6 +125,7 @@ m180.Turn(180) animate(target, transform = m180, time = 3) target.pixel_y = target.base_pixel_y + PIXEL_Y_OFFSET_LYING + ADD_TRAIT(target, TRAIT_MOVE_UPSIDE_DOWN, REF(src)) /obj/structure/kitchenspike/user_unbuckle_mob(mob/living/buckled_mob, mob/user) if(buckled_mob != user) @@ -156,6 +157,7 @@ m180.Turn(180) animate(buckled_mob, transform = m180, time = 3) buckled_mob.pixel_y = buckled_mob.base_pixel_y + PIXEL_Y_OFFSET_LYING + REMOVE_TRAIT(buckled_mob, TRAIT_MOVE_UPSIDE_DOWN, REF(src)) /obj/structure/kitchenspike/deconstruct(disassembled = TRUE) if(disassembled) diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index fa12148d330..5d3c4aee07c 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -121,7 +121,7 @@ /obj/structure/railing/CanPass(atom/movable/mover, border_dir) . = ..() if(border_dir & dir) - return . || mover.throwing || mover.movement_type & (FLYING | FLOATING) + return . || mover.throwing || (mover.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return TRUE /obj/structure/railing/CanAStarPass(to_dir, datum/can_pass_info/pass_info) @@ -144,7 +144,7 @@ if (leaving.throwing) return - if (leaving.movement_type & (PHASING | FLYING | FLOATING)) + if (leaving.movement_type & (PHASING|MOVETYPES_NOT_TOUCHING_GROUND)) return if (leaving.move_force >= MOVE_FORCE_EXTREMELY_STRONG) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index c80e2da85d6..78357a5dd4a 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -450,7 +450,7 @@ check_break(M) /obj/structure/table/glass/proc/check_break(mob/living/M) - if(M.has_gravity() && M.mob_size > MOB_SIZE_SMALL && !(M.movement_type & FLYING)) + if(M.has_gravity() && M.mob_size > MOB_SIZE_SMALL && !(M.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) table_shatter(M) /obj/structure/table/glass/proc/table_shatter(mob/living/victim) diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index 657d94d5c5f..6b83427a7b2 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -285,7 +285,7 @@ return TRUE /turf/open/handle_slip(mob/living/carbon/slipper, knockdown_amount, obj/slippable, lube, paralyze_amount, force_drop) - if(slipper.movement_type & (FLYING | FLOATING)) + if(slipper.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return FALSE if(!has_gravity(src)) return FALSE @@ -446,4 +446,3 @@ playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) new /obj/structure/girder/tram(src) - diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index 567aa8710c7..3b382069f58 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -246,7 +246,7 @@ . = TRUE /turf/open/lava/proc/can_burn_stuff(atom/movable/burn_target) - if(burn_target.movement_type & (FLYING|FLOATING)) //you're flying over it. + if(burn_target.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) //you're flying over it. return LAVA_BE_IGNORING if(isobj(burn_target)) @@ -265,7 +265,7 @@ var/mob/living/burn_living = burn_target var/atom/movable/burn_buckled = burn_living.buckled if(burn_buckled) - if(burn_buckled.movement_type & (FLYING|FLOATING)) + if(burn_buckled.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return LAVA_BE_PROCESSING if(isobj(burn_buckled)) var/obj/burn_buckled_obj = burn_buckled diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index e706c6f7598..1f760e29b89 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -189,7 +189,7 @@ if(armed) if(ismob(AM)) var/mob/MM = AM - if(!(MM.movement_type & FLYING)) + if(!(MM.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) if(ishuman(AM)) var/mob/living/carbon/H = AM if(H.move_intent == MOVE_INTENT_RUN) diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 32e2a567f63..a176a84dfa4 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -296,7 +296,7 @@ return if(isliving(movable)) var/mob/living/crusher = movable - if(crusher.move_intent != MOVE_INTENT_WALK && (!(crusher.movement_type & (FLYING|FLOATING)) || crusher.buckled)) + if(crusher.move_intent != MOVE_INTENT_WALK && (!(crusher.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || crusher.buckled)) playsound(src, 'sound/effects/footstep/glass_step.ogg', 30, TRUE) visible_message(span_warning("[crusher] steps on [src], damaging it!")) take_damage(100, sound_effect = FALSE) diff --git a/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid_abilities.dm b/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid_abilities.dm index 6e8ff992891..d82812b62a3 100644 --- a/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid_abilities.dm +++ b/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid_abilities.dm @@ -22,7 +22,7 @@ if(!iscarbon(target) || blocked >= 100) return var/obj/item/restraints/legcuffs/beartrap/mega_arachnid/restraint = new(get_turf(target)) - restraint.spring_trap(null, target) + restraint.spring_trap(target) /obj/item/restraints/legcuffs/beartrap/mega_arachnid name = "fleshy restraints" diff --git a/code/modules/mob/living/basic/space_fauna/meteor_heart/spine_traps.dm b/code/modules/mob/living/basic/space_fauna/meteor_heart/spine_traps.dm index 4f7135b1deb..8ddcc1ed9e4 100644 --- a/code/modules/mob/living/basic/space_fauna/meteor_heart/spine_traps.dm +++ b/code/modules/mob/living/basic/space_fauna/meteor_heart/spine_traps.dm @@ -86,7 +86,7 @@ /// Called when something enters our turf, if it is a non-flying mob then give it a stab /obj/effect/temp_visual/thrusting_spines/proc/on_entered(datum/source, atom/movable/arrived) - if (!active || !isliving(arrived) || (arrived.movement_type & (FLYING | FLOATING))) + if (!active || !isliving(arrived) || (arrived.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) return if (!COOLDOWN_FINISHED(src, thrust_delay)) return diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index 82bda7c7cd4..d900706f102 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -1,5 +1,5 @@ /mob/living/carbon/slip(knockdown_amount, obj/slipped_on, lube_flags, paralyze, force_drop = FALSE) - if(movement_type & (FLYING | FLOATING)) + if(movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return FALSE if(!(lube_flags & SLIDE_ICE)) log_combat(src, (slipped_on || get_turf(src)), "slipped on the", null, ((lube_flags & SLIDE) ? "(SLIDING)" : null)) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index a42a0365bc5..b92bc08ceb7 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1241,6 +1241,7 @@ if(-INFINITY to NEGATIVE_GRAVITY) if(!istype(gravity_alert, /atom/movable/screen/alert/negative)) throw_alert(ALERT_GRAVITY, /atom/movable/screen/alert/negative) + ADD_TRAIT(src, TRAIT_MOVE_UPSIDE_DOWN, NEGATIVE_GRAVITY_TRAIT) var/matrix/flipped_matrix = transform flipped_matrix.b = -flipped_matrix.b flipped_matrix.e = -flipped_matrix.e @@ -1265,6 +1266,7 @@ if(istype(gravity_alert, /atom/movable/screen/alert/weightless)) REMOVE_TRAIT(src, TRAIT_MOVE_FLOATING, NO_GRAVITY_TRAIT) if(istype(gravity_alert, /atom/movable/screen/alert/negative)) + REMOVE_TRAIT(src, TRAIT_MOVE_UPSIDE_DOWN, NEGATIVE_GRAVITY_TRAIT) var/matrix/flipped_matrix = transform flipped_matrix.b = -flipped_matrix.b flipped_matrix.e = -flipped_matrix.e diff --git a/code/modules/mod/modules/modules_maint.dm b/code/modules/mod/modules/modules_maint.dm index f7b53eaa9f0..30889e4f982 100644 --- a/code/modules/mod/modules/modules_maint.dm +++ b/code/modules/mod/modules/modules_maint.dm @@ -288,6 +288,7 @@ RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, PROC_REF(check_upstairs)) RegisterSignal(mod.wearer, COMSIG_MOB_SAY, PROC_REF(on_talk)) ADD_TRAIT(mod.wearer, TRAIT_SILENT_FOOTSTEPS, MOD_TRAIT) + passtable_on(mod.wearer, MOD_TRAIT) check_upstairs() //todo at some point flip your screen around /obj/item/mod/module/atrocinator/on_deactivation(display_message = TRUE, deleting = FALSE) @@ -304,6 +305,7 @@ UnregisterSignal(mod.wearer, COMSIG_MOB_SAY) step_count = 0 REMOVE_TRAIT(mod.wearer, TRAIT_SILENT_FOOTSTEPS, MOD_TRAIT) + passtable_off(mod.wearer, MOD_TRAIT) var/turf/open/openspace/current_turf = get_turf(mod.wearer) if(istype(current_turf)) current_turf.zFall(mod.wearer, falling_from_move = TRUE) diff --git a/code/modules/power/lighting/light_items.dm b/code/modules/power/lighting/light_items.dm index 9f2bff9cdca..5e9df6ee432 100644 --- a/code/modules/power/lighting/light_items.dm +++ b/code/modules/power/lighting/light_items.dm @@ -116,7 +116,7 @@ if(!isliving(moving_atom)) return var/mob/living/moving_mob = moving_atom - if(!(moving_mob.movement_type & (FLYING|FLOATING)) || moving_mob.buckled) + if(!(moving_mob.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || moving_mob.buckled) playsound(src, 'sound/effects/footstep/glass_step.ogg', HAS_TRAIT(moving_mob, TRAIT_LIGHT_STEP) ? 30 : 50, TRUE) if(status == LIGHT_BURNED || status == LIGHT_OK) shatter(moving_mob) diff --git a/code/modules/projectiles/projectile/energy/net_snare.dm b/code/modules/projectiles/projectile/energy/net_snare.dm index c60c0c35d17..925096f6351 100644 --- a/code/modules/projectiles/projectile/energy/net_snare.dm +++ b/code/modules/projectiles/projectile/energy/net_snare.dm @@ -69,7 +69,7 @@ new/obj/item/restraints/legcuffs/beartrap/energy(get_turf(loc)) else if(iscarbon(target)) var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy(get_turf(target)) - B.spring_trap(null, target) + B.spring_trap(target) . = ..() /obj/projectile/energy/trap/on_range() @@ -88,7 +88,7 @@ qdel(src) if(iscarbon(target)) var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy/cyborg(get_turf(target)) - B.spring_trap(null, target) + B.spring_trap(target) QDEL_IN(src, 10) . = ..() From 95db2b59de61a5df48a46b7412461adbed0d107a Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:38:04 +0300 Subject: [PATCH 07/55] [MIRROR] Fixes cursed/bad luck initializing with the wrong amount of incidents [MDB IGNORE] (#751) * Fixes cursed/bad luck initializing with the wrong amount of incidents (#79846) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: lessthanthree <83487515+lessthnthree@users.noreply.github.com> --- code/datums/components/omen.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/omen.dm b/code/datums/components/omen.dm index f03f28b8d6a..56af8e6a9db 100644 --- a/code/datums/components/omen.dm +++ b/code/datums/components/omen.dm @@ -17,7 +17,7 @@ /// Base damage from negative events. Cursed take 25% of this damage. var/damage_mod = 1 -/datum/component/omen/Initialize(obj/vessel, incidents_left = 1, luck_mod, damage_mod) +/datum/component/omen/Initialize(obj/vessel, incidents_left, luck_mod, damage_mod) if(!isliving(parent)) return COMPONENT_INCOMPATIBLE From 995e1aae199bf84f93134ce9241f39faa0e58003 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:39:08 +0300 Subject: [PATCH 08/55] [MIRROR] Examining a human mob as an observer displays "Quirks", not "Traits" [MDB IGNORE] (#752) * Examining a human mob as an observer displays "Quirks", not "Traits" * Update examine.dm --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/modules/mob/living/carbon/human/examine.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 3de1c08d49c..b7b6456b775 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -464,7 +464,8 @@ . += "\[View general records\]" //SKYRAT EDIT ADDITION END else if(isobserver(user)) - . += span_info("Traits: [get_quirk_string(FALSE, CAT_QUIRK_ALL)]") + . += span_info("Quirks: [get_quirk_string(FALSE, CAT_QUIRK_ALL)]") + . += "" //SKYRAT EDIT ADDITION BEGIN - EXAMINE RECORDS if(isobserver(user) || user.mind?.can_see_exploitables || user.mind?.has_exploitables_override) From 2eabbe48c73724780d2a528174f294874093c9c1 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:41:47 +0300 Subject: [PATCH 09/55] [MIRROR] Increases CMO hypospray capacity + adds microdosing [MDB IGNORE] (#755) * Increases CMO hypospray capacity + adds microdosing (#79813) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Jay <19880843+AdmiralPancakes1@users.noreply.github.com> Co-authored-by: bumtickley00 --- code/modules/reagents/reagent_containers/hypospray.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 63648375045..0c9107ab19a 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -61,6 +61,8 @@ /obj/item/reagent_containers/hypospray/cmo + volume = 60 + possible_transfer_amounts = list(1,3,5) list_reagents = list(/datum/reagent/medicine/omnizine = 30) resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF From 2985a7771aff621fe015b19f5d8fa8b61ec3b955 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:42:35 +0300 Subject: [PATCH 10/55] [MIRROR] Minor fixes to mimesvsclowns ruin (Abandoned Mime Outpost) [MDB IGNORE] (#754) * Minor fixes to mimesvsclowns ruin (Abandoned Mime Outpost) (#79811) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Da Cool Boss <142358580+DaCoolBoss@users.noreply.github.com> --- .../RandomRuins/SpaceRuins/mimesvsclowns.dmm | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm b/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm index d7186f44776..6a7c71ad938 100644 --- a/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm +++ b/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm @@ -6,6 +6,11 @@ /area/ruin) "dI" = ( /obj/item/grown/bananapeel, +/obj/item/ammo_casing/a357/spent{ + dir = 9; + pixel_x = -13; + pixel_y = 10 + }, /turf/open/floor/iron/checker/airless, /area/ruin) "ef" = ( @@ -71,20 +76,21 @@ /obj/machinery/atmospherics/components/unary/passive_vent{ dir = 4 }, -/obj/item/ammo_casing/energy/c3dbullet{ - pixel_y = 10; - pixel_x = 115; - dir = 9 - }, /obj/effect/decal/cleanable/blood/gibs, /obj/machinery/light/small/broken/directional/south, +/obj/item/ammo_casing/a357/spent, /turf/open/floor/iron/checker/airless, /area/ruin) "uc" = ( -/obj/item/ammo_casing/energy/c3dbullet, /obj/effect/decal/cleanable/blood/footprints{ dir = 4 }, +/obj/item/ammo_casing/a357/spent{ + pixel_x = -5; + dir = 5; + pixel_y = 6 + }, +/obj/item/ammo_casing/a357/spent, /obj/item/gps/spaceruin, /turf/open/floor/plating/airless, /area/ruin) @@ -139,11 +145,6 @@ /turf/open/floor/iron/checker/airless, /area/ruin) "Ar" = ( -/obj/item/ammo_casing/energy/c3dbullet{ - dir = 5; - pixel_x = 59; - pixel_y = 6 - }, /obj/item/clothing/mask/gas/clown_hat{ pixel_y = 39 }, @@ -216,7 +217,6 @@ /area/ruin) "JK" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber, -/obj/item/ammo_casing/energy/c3dbullet, /obj/effect/decal/cleanable/blood/gibs/up, /turf/open/floor/plating/airless, /area/ruin) @@ -252,8 +252,8 @@ /area/ruin) "Pq" = ( /obj/machinery/light/broken/directional/north, -/obj/item/ammo_casing/energy/c3dbullet, /obj/structure/reagent_dispensers/watertank, +/obj/item/ammo_casing/a357/spent, /turf/open/floor/iron/checker/airless, /area/ruin) "Qb" = ( @@ -267,7 +267,6 @@ /turf/open/floor/iron/checker/airless, /area/ruin) "Vj" = ( -/obj/structure/grille, /obj/effect/spawner/structure/window/reinforced, /obj/effect/mapping_helpers/damaged_window, /obj/effect/decal/cleanable/blood/splatter/over_window, From 91646a2fb59d5bb7e957be9e0880e9841418fa76 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:42:42 +0300 Subject: [PATCH 11/55] Automatic changelog for PR #744 [ci skip] --- html/changelogs/AutoChangeLog-pr-744.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-744.yml diff --git a/html/changelogs/AutoChangeLog-pr-744.yml b/html/changelogs/AutoChangeLog-pr-744.yml new file mode 100644 index 00000000000..c49b081a12c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-744.yml @@ -0,0 +1,5 @@ +author: "Hatterhat" +delete-after: True +changes: + - balance: "The SC/FISHER disruptor pistol is now more likely to show up in black market uplinks." + - balance: "The SC/FISHER now has more range (21 tiles up from 14), and is usable by pacifists." \ No newline at end of file From 6d6b38d270add9d9ca198a88ebb45f0f1d4bf141 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:42:58 +0300 Subject: [PATCH 12/55] Automatic changelog for PR #746 [ci skip] --- html/changelogs/AutoChangeLog-pr-746.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-746.yml diff --git a/html/changelogs/AutoChangeLog-pr-746.yml b/html/changelogs/AutoChangeLog-pr-746.yml new file mode 100644 index 00000000000..9b1f67170d8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-746.yml @@ -0,0 +1,6 @@ +author: "yooriss" +delete-after: True +changes: + - rscadd: "Examining tamed companions of any type with shift double-click now gives a brief indication as to their overall health. This also includes a handy reminder on how to heal pets if they get injured." + - rscadd: "A new recipe for anointing bloodresin is now available exclusively for Primitive Demihumans, made from 80u liquid gibs and 20u of blood. Bloodresin invokes traditional rites of the Hearth to give names to worthy creatures. Using this in poor ways may displease the Gods. Woe upon your lineage." + - rscadd: "A single pack of glowshroom mycelium has been added to the Hearth's starting seed stores for the benefit of creative healers, shamans, and radiation enthusiasts." \ No newline at end of file From 81a2f9a9734e5d354316087b2eb0ea2e2759b0ea Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:43:21 +0300 Subject: [PATCH 13/55] Automatic changelog for PR #749 [ci skip] --- html/changelogs/AutoChangeLog-pr-749.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-749.yml diff --git a/html/changelogs/AutoChangeLog-pr-749.yml b/html/changelogs/AutoChangeLog-pr-749.yml new file mode 100644 index 00000000000..941c7daa96a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-749.yml @@ -0,0 +1,7 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "Atrocinating mobs will now behave more as you'd expect. Meaning they don't slip on wet patches, can't trigger bear traps / landmines / mouse traps, ignore conveyors, and can walk over tables and railings." + - bugfix: "Floating mobs are unaffected by conveyor belts, acid (on the ground), glass tables" + - bugfix: "Floating mobs won't squish stuff like roaches anymore" + - bugfix: "Fixes bear traps triggering on floating / flying mobs" \ No newline at end of file From 2e3f0a36696c04a59a3bee3fbccba2c1c9cd8fa4 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:43:47 +0300 Subject: [PATCH 14/55] [MIRROR] Makes heads on pikes render correctly. [MDB IGNORE] (#756) * Makes heads on pikes render correctly. (#79863) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: lizardqueenlexi <105025397+lizardqueenlexi@users.noreply.github.com> --- code/game/objects/structures/headpike.dm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm index 7731af947f0..b48cafc85d9 100644 --- a/code/game/objects/structures/headpike.dm +++ b/code/game/objects/structures/headpike.dm @@ -47,11 +47,11 @@ . = ..() if(!victim) return - var/mutable_appearance/MA = new() - MA.copy_overlays(victim) - MA.pixel_y = 12 - MA.pixel_x = pixel_x - . += victim + var/mutable_appearance/appearance = new() + appearance.copy_overlays(victim) + appearance.pixel_y = 12 + appearance.layer = layer + 0.1 + . += appearance /obj/structure/headpike/Exited(atom/movable/gone, direction) . = ..() From c3b080bbdfb5c5177bbee72839942662b6cf359b Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:43:49 +0300 Subject: [PATCH 15/55] Automatic changelog for PR #751 [ci skip] --- html/changelogs/AutoChangeLog-pr-751.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-751.yml diff --git a/html/changelogs/AutoChangeLog-pr-751.yml b/html/changelogs/AutoChangeLog-pr-751.yml new file mode 100644 index 00000000000..857e8c8a4f9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-751.yml @@ -0,0 +1,4 @@ +author: "LT3" +delete-after: True +changes: + - bugfix: "Cursed/bad luck omen will now stick with the player for more than 1 incident" \ No newline at end of file From 43dd17a36d488808b9b3ed15a8788f45000a625e Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:44:11 +0300 Subject: [PATCH 16/55] Automatic changelog for PR #752 [ci skip] --- html/changelogs/AutoChangeLog-pr-752.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-752.yml diff --git a/html/changelogs/AutoChangeLog-pr-752.yml b/html/changelogs/AutoChangeLog-pr-752.yml new file mode 100644 index 00000000000..4fb98d4e8d2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-752.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - spellcheck: "Examining a human mob as an observer displays \"Quirks\", not \"Traits\"" \ No newline at end of file From 59e267d10f1af2bfd1c5efed3ca4e3159626dd94 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:44:37 +0300 Subject: [PATCH 17/55] [MIRROR] Added "Bargonia" bar sign! [MDB IGNORE] (#757) * Added "Bargonia" bar sign! (#79565) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: DrAmazing343 <147954468+DrAmazing343@users.noreply.github.com> Co-authored-by: san7890 Co-authored-by: Ghom <42542238+Ghommie@ users.noreply.github.com> --- code/game/machinery/barsigns.dm | 6 ++++++ icons/obj/machines/barsigns.dmi | Bin 192453 -> 208388 bytes 2 files changed, 6 insertions(+) diff --git a/code/game/machinery/barsigns.dm b/code/game/machinery/barsigns.dm index 64b104b4007..cc90f3346f6 100644 --- a/code/game/machinery/barsigns.dm +++ b/code/game/machinery/barsigns.dm @@ -424,6 +424,12 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) desc = "Where every drink is masterfully crafted with industrial efficiency!" neon_color = "#ffffff" +/datum/barsign/bargonia + name = "Bargonia" + icon_state = "bargonia" + desc = "The warehouse yearns for a higher calling... so Supply has declared BARGONIA!" + neon_color = COLOR_WHITE + // Hidden signs list below this point /datum/barsign/hiddensigns diff --git a/icons/obj/machines/barsigns.dmi b/icons/obj/machines/barsigns.dmi index f3cfe8eaed92f4b80d67ff96aa111d9ac2b1122d..de55f7699812498df6a72cc3d8ebbffd4e52b719 100644 GIT binary patch literal 208388 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 M5C&Rh8um~A2lDDDCIA2c literal 192453 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Œk4!j{5oq4Yiz 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�q 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%0DbW0Qe{jDS-W~O#x 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 Date: Tue, 21 Nov 2023 23:45:01 +0300 Subject: [PATCH 18/55] Automatic changelog for PR #755 [ci skip] --- html/changelogs/AutoChangeLog-pr-755.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-755.yml diff --git a/html/changelogs/AutoChangeLog-pr-755.yml b/html/changelogs/AutoChangeLog-pr-755.yml new file mode 100644 index 00000000000..24569b28c51 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-755.yml @@ -0,0 +1,4 @@ +author: "Bumtickley00" +delete-after: True +changes: + - balance: "The CMO's hypospray now holds 60u, and can be set to inject smaller amounts of reagents" \ No newline at end of file From 9619a2db5362fa5f780bf52b64fea5e488dbf51a Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:45:54 +0300 Subject: [PATCH 19/55] Updates the modular hud.dmi to get two or three missing icons (Fixes missing Bitrunner hud) (#761) * Update hud.dmi * so long, gay bowser! Co-authored-by: OrionTheFox <76465278+OrionTheFox@users.noreply.github.com> --- code/__DEFINES/~skyrat_defines/atom_hud.dm | 1 - .../master_files/icons/mob/huds/hud.dmi | Bin 13934 -> 14291 bytes 2 files changed, 1 deletion(-) diff --git a/code/__DEFINES/~skyrat_defines/atom_hud.dm b/code/__DEFINES/~skyrat_defines/atom_hud.dm index 32862bfc7e4..b190157d0eb 100644 --- a/code/__DEFINES/~skyrat_defines/atom_hud.dm +++ b/code/__DEFINES/~skyrat_defines/atom_hud.dm @@ -1,6 +1,5 @@ //SR Security #define SECHUD_CORRECTIONS_OFFICER "hudcorrectionsofficer" -#define SECHUD_SECURITY_MEDIC "hudsecuritymedic" //SR Departmental Guards #define SECHUD_ENGINEERING_GUARD "hudengineeringguard" #define SECHUD_ORDERLY "hudorderly" diff --git a/modular_skyrat/master_files/icons/mob/huds/hud.dmi b/modular_skyrat/master_files/icons/mob/huds/hud.dmi index 3d81edc5f201a9a06befb18e040737903b498cf9..56163691900af0c58ce45cee47fa488de4e33239 100644 GIT binary patch literal 14291 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

-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 a3&1VLp6HuhYC0g`&+MYrg_85`5C0FY-VGN3 literal 13934 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 GPyQRgb4tAc From 428b8bbbe61891201c5b5d54b1da2793478f6163 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:46:30 +0300 Subject: [PATCH 20/55] Primitive storage overlays. (#762) * Update storage_structures.dm * Add files via upload Co-authored-by: xXPawnStarrXx <53197594+xXPawnStarrXx@users.noreply.github.com> --- .../code/storage_structures.dm | 8 ++++---- .../primitive_structures/icons/storage.dmi | Bin 906 -> 3187 bytes 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modular_skyrat/modules/primitive_structures/code/storage_structures.dm b/modular_skyrat/modules/primitive_structures/code/storage_structures.dm index 8c6f872c712..a9c1ce0b9fb 100644 --- a/modular_skyrat/modules/primitive_structures/code/storage_structures.dm +++ b/modular_skyrat/modules/primitive_structures/code/storage_structures.dm @@ -57,15 +57,15 @@ icon_state = "producebin" icon = 'modular_skyrat/modules/primitive_structures/icons/storage.dmi' resistance_flags = FLAMMABLE - visible_contents = FALSE base_build_path = /obj/machinery/smartfridge/producebin + contents_icon_state = "produce" use_power = NO_POWER_USE light_power = 0 idle_power_usage = 0 circuit = null has_emissive = FALSE can_atmos_pass = ATMOS_PASS_YES - visible_contents = FALSE + visible_contents = TRUE /obj/machinery/smartfridge/producebin/accept_check(obj/item/weapon) return (istype(weapon, /obj/item/food/grown)) @@ -88,15 +88,15 @@ icon_state = "seedshelf" icon = 'modular_skyrat/modules/primitive_structures/icons/storage.dmi' resistance_flags = FLAMMABLE - visible_contents = FALSE base_build_path = /obj/machinery/smartfridge/seedshelf + contents_icon_state = "seed" use_power = NO_POWER_USE light_power = 0 idle_power_usage = 0 circuit = null has_emissive = FALSE can_atmos_pass = ATMOS_PASS_YES - visible_contents = FALSE + visible_contents = TRUE /obj/machinery/smartfridge/seedshelf/accept_check(obj/item/weapon) return istype(weapon, /obj/item/seeds) diff --git a/modular_skyrat/modules/primitive_structures/icons/storage.dmi b/modular_skyrat/modules/primitive_structures/icons/storage.dmi index 2b71389146d898652b2d4f27f6f27da0172d912d..1c2c362632151fa314175e97b1133d3cf152cf9d 100644 GIT binary patch literal 3187 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 LSQ^*i2nqiMcGL#l literal 906 zcmV;519kj~P)V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5sW>AwCoR4_KR-o@i!&v&s2C_{$i<`AhY zzaTY_pwfb({FKt<)TB(pN{drdQ^0P;rBYeJ)z1YS1OO$VO)Uma^;7@=0)I(FK~zYI zwUxnc)G!c+lb~|O6DqFt%vM~xo=BY8_z8+wafDOvNULz=#6C7-JBjVYRYHMjW$91n z%S^_<-Ky4A67Z(lipHdh?nV$1Q#R2hphjY5oNH&g1OOiqG@Gdgu#pO*E&w$_%f!%* zC2B&gltR+a0L_s|0McgaTKNF4U-c=_Jva*31EvilARPb|UT53{#?byzM*-l&LwL&s zc-~EA(T9k0a3El>z9`fAnD-6LcZ}t=DVdrX|}W$U?U+-)UE4)NA1NCt_pm zNz~Z^3%v&Fr|&Ee4V%k1zYV!=*e1aaxc_o>2_J^D->HROS7^+;;d;IPx_k~hwb1K* zXqa#qhRY*S0CK&yh9t0dFwa1$%YgsL1W5Eh0BV{O!jy9T0$@3%o0xF#t&!`3H6CHy zSqRq1b-}GqKhY%^efjG9%yj{{{c&}3e?Odqy>neU53?1<^N{Hhpo10kcz5M`?bfQ+ z=vqKMT{D?3RHy)a!hF$Yx^Qb$HK6-Z({^UM&UZSzRDmR@cpIm>eBIY_=+ozk222PM zOIWb}zOO8c;AVcScoy?K|t`^?_k=CdZ+o4vi`M?cfj zY;WFqL}N=Y0pyz^P&^OI3Y+KQZ(Di^uszlVuxX9|3;^r-#Gw9W&i*H From e25332f11f5ffe54b01f6fca9366d471f79dc876 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:52:07 +0300 Subject: [PATCH 21/55] Automatic changelog for PR #754 [ci skip] --- html/changelogs/AutoChangeLog-pr-754.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-754.yml diff --git a/html/changelogs/AutoChangeLog-pr-754.yml b/html/changelogs/AutoChangeLog-pr-754.yml new file mode 100644 index 00000000000..bd0f359aed9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-754.yml @@ -0,0 +1,4 @@ +author: "DaCoolBoss" +delete-after: True +changes: + - bugfix: "Removed a duplicate grille from the abandoned mime outpost space ruin, and replaced the 'energy weapon lenses' with spent revolver rounds." \ No newline at end of file From 63b835ff77b4ed6e8e72cc38ed33d5f569e5d70f Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:52:31 +0300 Subject: [PATCH 22/55] Automatic changelog for PR #756 [ci skip] --- html/changelogs/AutoChangeLog-pr-756.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-756.yml diff --git a/html/changelogs/AutoChangeLog-pr-756.yml b/html/changelogs/AutoChangeLog-pr-756.yml new file mode 100644 index 00000000000..e55cb39ed13 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-756.yml @@ -0,0 +1,5 @@ +author: "lizardqueenlexi" +delete-after: True +changes: + - bugfix: "Heads impaled on spears now render in the correct place on the tip, instead of halfway down the shaft." + - bugfix: "Blind personnel are no longer able to magically see heads impaled on spears from a distance." \ No newline at end of file From f8ed7374249f921fca700edf7a37666a5c52b7f2 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Wed, 22 Nov 2023 00:32:25 +0300 Subject: [PATCH 23/55] Automatic changelog for PR #757 [ci skip] --- html/changelogs/AutoChangeLog-pr-757.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-757.yml diff --git a/html/changelogs/AutoChangeLog-pr-757.yml b/html/changelogs/AutoChangeLog-pr-757.yml new file mode 100644 index 00000000000..09f31b52d3b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-757.yml @@ -0,0 +1,4 @@ +author: "Jane" +delete-after: True +changes: + - rscadd: "Bargonia Bar Sign for Cargo Bar Enjoyers" \ No newline at end of file From 96865c30209d135850f2b642614db04602aec9fc Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Wed, 22 Nov 2023 00:41:55 +0300 Subject: [PATCH 24/55] Automatic changelog for PR #761 [ci skip] --- html/changelogs/AutoChangeLog-pr-761.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-761.yml diff --git a/html/changelogs/AutoChangeLog-pr-761.yml b/html/changelogs/AutoChangeLog-pr-761.yml new file mode 100644 index 00000000000..20eb4fcd84e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-761.yml @@ -0,0 +1,4 @@ +author: "OrionTheFox" +delete-after: True +changes: + - bugfix: "fixed a few missing/outdated HUD icons, including the Bitrunner's SecHUD icon, and switching the \"Suspected\" tag to match the color used on consoles" \ No newline at end of file From 9f3f6d6716657440752360e50b3aedd8871c720e Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:41:19 +0300 Subject: [PATCH 25/55] [MIRROR] Refactors Parrots into Basic Mobs (ft. Ben10Omintrix/Kobsamobsa) (#745) * [MIRROR] Refactors Parrots into Basic Mobs (ft. Ben10Omintrix/Kobsamobsa) [MDB IGNORE] (#25100) * Refactors Parrots into Basic Mobs (ft. Ben10Omintrix/Kobsamobsa) * UpdatePaths * Modular, cleanup, porting parrot commands into the new system * makes poly slightly less of a dick * Update parrot.dm * Update parrot.dm * Update tgstation.dme * Revert "Update tgstation.dme" This reverts commit a8b40c4aba524c271db02c271089664649dea1eb. * update paths --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: san7890 Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Iajret --- _maps/map_files/Birdshot/birdshot.dmm | 2 +- .../map_files/Deltastation/DeltaStation2.dmm | 2 +- .../map_files/IceBoxStation/IceBoxStation.dmm | 2 +- _maps/map_files/KiloStation2/KiloStation2.dmm | 2 +- _maps/map_files/MetaStation/MetaStation.dmm | 2 +- _maps/map_files/NSSJourney/NSSJourney.dmm | 2 +- _maps/map_files/NSVBlueshift/Blueshift.dmm | 2 +- _maps/map_files/NorthStar/north_star.dmm | 2 +- _maps/map_files/VoidRaptor/VoidRaptor.dmm | 2 +- _maps/map_files/tramstation/tramstation.dmm | 2 +- _maps/shuttles/emergency_hugcage.dmm | 2 +- _maps/shuttles/ruin_pirate_cutter.dmm | 2 +- _maps/virtual_domains/pirates.dmm | 2 +- code/__DEFINES/ai/pets.dm | 24 + .../signals_atom/signals_atom_movable.dm | 8 +- .../dcs/signals/signals_mob/signals_mob_ai.dm | 1 + .../signals/signals_mob/signals_mob_basic.dm | 7 + code/__DEFINES/traits/declarations.dm | 2 + code/_globalvars/phobias.dm | 2 +- .../subsystem/persistence/_persistence.dm | 5 +- .../basic_ai_behaviors/basic_attacking.dm | 11 + .../basic_ai_behaviors/unbuckle_mob.dm | 14 + code/datums/ai/generic/find_and_set.dm | 23 + code/datums/ai/generic/generic_behaviors.dm | 2 + code/datums/components/listen_and_repeat.dm | 88 ++ code/datums/components/supermatter_crystal.dm | 2 +- code/datums/diseases/parrotpossession.dm | 39 +- code/datums/elements/pet_bonus.dm | 1 + code/datums/memory/_memory.dm | 2 +- .../pirate/pirate_shuttle_equipment.dm | 4 +- .../traitor/objectives/kill_pet.dm | 2 +- code/modules/cargo/packs/livestock.dm | 4 +- code/modules/events/ghost_role/sentience.dm | 2 +- code/modules/events/holiday/halloween.dm | 6 +- code/modules/events/wizard/petsplosion.dm | 2 +- .../mob/living/basic/pets/parrot/_parrot.dm | 458 +++++++ .../parrot/parrot_ai/_parrot_controller.dm | 40 + .../parrot_ai/ghost_parrot_controller.dm | 37 + .../pets/parrot/parrot_ai/parrot_hoarding.dm | 74 ++ .../pets/parrot/parrot_ai/parrot_perching.dm | 78 ++ .../pets/parrot/parrot_ai/parroting_action.dm | 50 + .../living/basic/pets/parrot/parrot_items.dm | 60 + .../basic/pets/parrot/parrot_subtypes.dm | 14 + .../mob/living/basic/pets/parrot/poly.dm | 254 ++++ .../mob/living/carbon/human/human_defines.dm | 6 +- code/modules/mob/living/living.dm | 2 +- code/modules/mob/living/living_say.dm | 4 +- .../mob/living/simple_animal/parrot.dm | 1070 ----------------- code/modules/mob/transform_procs.dm | 2 +- code/modules/research/experimentor.dm | 2 +- code/modules/unit_tests/required_map_items.dm | 7 +- .../unit_tests/simple_animal_freeze.dm | 4 - .../traitor/objectives/kill_pet.dm | 2 +- .../modules/poly_commands/parrot.dm | 61 +- tgstation.dme | 12 +- .../Scripts/79762_simple_to_basic_parrots.txt | 5 + 56 files changed, 1347 insertions(+), 1172 deletions(-) create mode 100644 code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm create mode 100644 code/datums/components/listen_and_repeat.dm create mode 100644 code/modules/mob/living/basic/pets/parrot/_parrot.dm create mode 100644 code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm create mode 100644 code/modules/mob/living/basic/pets/parrot/parrot_ai/ghost_parrot_controller.dm create mode 100644 code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_hoarding.dm create mode 100644 code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm create mode 100644 code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm create mode 100644 code/modules/mob/living/basic/pets/parrot/parrot_items.dm create mode 100644 code/modules/mob/living/basic/pets/parrot/parrot_subtypes.dm create mode 100644 code/modules/mob/living/basic/pets/parrot/poly.dm delete mode 100644 code/modules/mob/living/simple_animal/parrot.dm create mode 100644 tools/UpdatePaths/Scripts/79762_simple_to_basic_parrots.txt diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index d2e8f5c89f7..2677923ac53 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -16109,7 +16109,7 @@ /obj/structure/chair/office/light{ dir = 4 }, -/mob/living/simple_animal/parrot/poly, +/mob/living/basic/parrot/poly, /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 0c73cb0f482..142e2ea32c7 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -34717,7 +34717,7 @@ /obj/structure/filingcabinet/chestdrawer, /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/machinery/newscaster/directional/north, -/mob/living/simple_animal/parrot/poly, +/mob/living/basic/parrot/poly, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/ce) "iDq" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 4c286912a63..db9b6bbba80 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -4597,7 +4597,7 @@ "bup" = ( /obj/structure/filingcabinet/chestdrawer, /obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/simple_animal/parrot/poly, +/mob/living/basic/parrot/poly, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/ce) "buv" = ( diff --git a/_maps/map_files/KiloStation2/KiloStation2.dmm b/_maps/map_files/KiloStation2/KiloStation2.dmm index beca1ca8175..25026c9cc6c 100644 --- a/_maps/map_files/KiloStation2/KiloStation2.dmm +++ b/_maps/map_files/KiloStation2/KiloStation2.dmm @@ -72595,7 +72595,7 @@ pixel_x = 12 }, /obj/item/radio/intercom/directional/east, -/mob/living/simple_animal/parrot/poly, +/mob/living/basic/parrot/poly, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/ce) "xjr" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index e6ba2a8dda4..bd142399404 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -3105,7 +3105,7 @@ "bdV" = ( /obj/structure/filingcabinet/chestdrawer, /obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/simple_animal/parrot/poly, +/mob/living/basic/parrot/poly, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/ce) "beo" = ( diff --git a/_maps/map_files/NSSJourney/NSSJourney.dmm b/_maps/map_files/NSSJourney/NSSJourney.dmm index c75e440de8d..88dc852d932 100644 --- a/_maps/map_files/NSSJourney/NSSJourney.dmm +++ b/_maps/map_files/NSSJourney/NSSJourney.dmm @@ -26469,7 +26469,7 @@ /obj/structure/filingcabinet/chestdrawer, /obj/structure/disposalpipe/segment, /obj/structure/cable, -/mob/living/simple_animal/parrot/poly, +/mob/living/basic/parrot/poly, /obj/effect/turf_decal/siding/thinplating{ dir = 8 }, diff --git a/_maps/map_files/NSVBlueshift/Blueshift.dmm b/_maps/map_files/NSVBlueshift/Blueshift.dmm index 6a2d5d1ab47..1f1c9541b5f 100644 --- a/_maps/map_files/NSVBlueshift/Blueshift.dmm +++ b/_maps/map_files/NSVBlueshift/Blueshift.dmm @@ -120550,7 +120550,7 @@ dir = 1 }, /obj/structure/filingcabinet/chestdrawer, -/mob/living/simple_animal/parrot/poly, +/mob/living/basic/parrot/poly, /obj/machinery/light_switch/directional/north, /turf/open/floor/iron/white/corner, /area/station/command/heads_quarters/ce) diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index 188d6cf2b4b..213928af553 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -6819,7 +6819,7 @@ /obj/machinery/computer/security/telescreen/engine{ name = "Engineering and atmospherics monitor" }, -/mob/living/simple_animal/parrot/poly, +/mob/living/basic/parrot/poly, /turf/open/floor/catwalk_floor/iron_dark, /area/station/command/heads_quarters/ce) "bIQ" = ( diff --git a/_maps/map_files/VoidRaptor/VoidRaptor.dmm b/_maps/map_files/VoidRaptor/VoidRaptor.dmm index 6d159c3afc7..c426ce32f48 100644 --- a/_maps/map_files/VoidRaptor/VoidRaptor.dmm +++ b/_maps/map_files/VoidRaptor/VoidRaptor.dmm @@ -35989,7 +35989,7 @@ /turf/open/floor/circuit/green, /area/station/ai_monitored/command/nuke_storage) "kmm" = ( -/mob/living/simple_animal/parrot/poly, +/mob/living/basic/parrot/poly, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/carpet/orange, diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 8b19e237ac4..7c7614177b7 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -47566,7 +47566,7 @@ }, /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, -/mob/living/simple_animal/parrot/poly, +/mob/living/basic/parrot/poly, /turf/open/floor/iron, /area/station/command/heads_quarters/ce) "pWt" = ( diff --git a/_maps/shuttles/emergency_hugcage.dmm b/_maps/shuttles/emergency_hugcage.dmm index 80211ed6092..fc474764401 100644 --- a/_maps/shuttles/emergency_hugcage.dmm +++ b/_maps/shuttles/emergency_hugcage.dmm @@ -31,7 +31,7 @@ /turf/open/floor/mineral/titanium/blue, /area/shuttle/escape) "dz" = ( -/mob/living/simple_animal/parrot/natural{ +/mob/living/basic/parrot{ melee_damage_upper = 5 }, /turf/open/floor/mineral/titanium/blue, diff --git a/_maps/shuttles/ruin_pirate_cutter.dmm b/_maps/shuttles/ruin_pirate_cutter.dmm index 7dd4be59ba7..77c4e37bc03 100644 --- a/_maps/shuttles/ruin_pirate_cutter.dmm +++ b/_maps/shuttles/ruin_pirate_cutter.dmm @@ -702,7 +702,7 @@ "Ry" = ( /obj/structure/rack, /obj/item/storage/bag/money/vault, -/mob/living/simple_animal/parrot{ +/mob/living/basic/parrot{ faction = list("pirate"); name = "Pegwing" }, diff --git a/_maps/virtual_domains/pirates.dmm b/_maps/virtual_domains/pirates.dmm index 952a8877d37..04be3d3a42d 100644 --- a/_maps/virtual_domains/pirates.dmm +++ b/_maps/virtual_domains/pirates.dmm @@ -801,7 +801,7 @@ /area/virtual_domain/fullbright) "Pz" = ( /obj/structure/table/wood, -/mob/living/simple_animal/parrot{ +/mob/living/basic/parrot{ name = "pepper" }, /turf/open/floor/carpet/blue, diff --git a/code/__DEFINES/ai/pets.dm b/code/__DEFINES/ai/pets.dm index b3ad67ecc06..e41c9ac0c3f 100644 --- a/code/__DEFINES/ai/pets.dm +++ b/code/__DEFINES/ai/pets.dm @@ -27,3 +27,27 @@ #define BB_FIND_MOM_TYPES "BB_find_mom_types" ///list of types of mobs we must ignore #define BB_IGNORE_MOM_TYPES "BB_ignore_mom_types" + +/// The current string that this parrot will repeat back to someone +#define BB_PARROT_REPEAT_STRING "BB_parrot_repeat_string" +/// The odds that this parrot will repeat back a string +#define BB_PARROT_REPEAT_PROBABILITY "BB_parrot_repeat_probability" +/// The odds that this parrot will choose another string to repeat +#define BB_PARROT_PHRASE_CHANGE_PROBABILITY "BB_parrot_phrase_change_probability" +/// A copy of the string buffer that we end the shift with. DO NOT ACCESS THIS DIRECTLY - YOU SHOULD USE THE COMPONENT IN MOST CASES +#define BB_EXPORTABLE_STRING_BUFFER_LIST "BB_parrot_repeat_string_buffer" +/// The types of perches we desire to use +#define BB_PARROT_PERCH_TYPES "BB_parrot_perch_types" +/// key that holds our perch target +#define BB_PERCH_TARGET "perch_target" +/// key that holds our theft item target +#define BB_HOARD_ITEM_TARGET "hoard_item_target" +/// key that holds the mob we will steal from +#define BB_THEFT_VICTIM "theft_victim" +/// key that holds the turf we will be hauling stolen items to +#define BB_HOARD_LOCATION "hoard_location" +/// key that holds the minimum range we must be from the hoard spot +#define BB_HOARD_LOCATION_RANGE "hoard_location_range" +/// key that holds items we arent interested in hoarding +#define BB_IGNORE_ITEMS "ignore_items" + diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm index d26dd4e8c86..b836c811667 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm @@ -47,13 +47,17 @@ #define COMSIG_MOVABLE_THROW_LANDED "movable_throw_landed" ///from base of atom/movable/on_changed_z_level(): (turf/old_turf, turf/new_turf, same_z_layer) #define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit" +///called before hearing a message from atom/movable/Hear(): +#define COMSIG_MOVABLE_PRE_HEAR "movable_pre_hear" + ///cancel hearing the message because we're doing something else presumably + #define COMSIG_MOVABLE_CANCEL_HEARING (1<<0) ///from base of atom/movable/Hear(): (proc args list(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range)) #define COMSIG_MOVABLE_HEAR "movable_hear" - //#define HEARING_MESSAGE 1 - (I'm pretty sure this is never really used and can be gutted) + #define HEARING_MESSAGE 1 #define HEARING_SPEAKER 2 #define HEARING_LANGUAGE 3 #define HEARING_RAW_MESSAGE 4 - //#define HEARING_RADIO_FREQ 5 + #define HEARING_RADIO_FREQ 5 #define HEARING_SPANS 6 #define HEARING_MESSAGE_MODE 7 #define HEARING_RANGE 8 diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm index 85630c8e8f0..a04b8e751a0 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm @@ -3,3 +3,4 @@ /// Signal sent when a blackboard key is cleared #define COMSIG_AI_BLACKBOARD_KEY_CLEARED(blackboard_key) "ai_blackboard_key_clear_[blackboard_key]" + diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_basic.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_basic.dm index 18c6c651435..8420a486417 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_basic.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_basic.dm @@ -5,3 +5,10 @@ ///from the ranged_attacks component for basic mobs: (mob/living/basic/firer, atom/target, modifiers) #define COMSIG_BASICMOB_POST_ATTACK_RANGED "basicmob_post_attack_ranged" + +/// Sent from /datum/ai_planning_subtree/parrot_as_in_repeat() : () +#define COMSIG_NEEDS_NEW_PHRASE "parrot_needs_new_phrase" + #define NO_NEW_PHRASE_AVAILABLE (1<<0) //! Cancel to try again later for when we actually get a new phrase + +/// Called whenever an animal is pet via the /datum/element/pet_bonus element: (mob/living/petter, modifiers) +#define COMSIG_ANIMAL_PET "animal_pet" diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 33f0d900cc1..6c774453782 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -83,6 +83,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NO_TRANSFORM "block_transformations" /// Tracks whether we're gonna be a baby alien's mummy. #define TRAIT_XENO_HOST "xeno_host" +/// This parrot is currently perched +#define TRAIT_PARROT_PERCHED "parrot_perched" /// This mob is immune to stun causing status effects and stamcrit. /// Prefer to use [/mob/living/proc/check_stun_immunity] over checking for this trait exactly. #define TRAIT_STUNIMMUNE "stun_immunity" diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm index 5bb8b4bf314..3aa6c41de4f 100644 --- a/code/_globalvars/phobias.dm +++ b/code/_globalvars/phobias.dm @@ -61,8 +61,8 @@ GLOBAL_LIST_INIT(phobia_mobs, list( "birds" = typecacheof(list( /mob/living/basic/chick, /mob/living/basic/chicken, + /mob/living/basic/parrot, /mob/living/basic/pet/penguin, - /mob/living/simple_animal/parrot, )), "conspiracies" = typecacheof(list( /mob/living/basic/drone, diff --git a/code/controllers/subsystem/persistence/_persistence.dm b/code/controllers/subsystem/persistence/_persistence.dm index c98be5d1c5a..565cf519d4b 100644 --- a/code/controllers/subsystem/persistence/_persistence.dm +++ b/code/controllers/subsystem/persistence/_persistence.dm @@ -62,8 +62,9 @@ SUBSYSTEM_DEF(persistence) ///Loads up Poly's speech buffer. /datum/controller/subsystem/persistence/proc/load_poly() - for(var/mob/living/simple_animal/parrot/poly/P in GLOB.alive_mob_list) - twitterize(P.speech_buffer, "polytalk") + for(var/mob/living/basic/parrot/poly/bird in GLOB.alive_mob_list) + var/list/list_to_read = bird.get_static_list_of_phrases() + twitterize(list_to_read, "polytalk") break //Who's been duping the bird?! /// Loads up the amount of times maps appeared to alter their appearance in voting and rotation. diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm index 21b141feff8..0f7fe6ef142 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm @@ -1,6 +1,8 @@ /datum/ai_behavior/basic_melee_attack action_cooldown = 0.2 SECONDS // We gotta check unfortunately often because we're in a race condition with nextmove behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + ///do we finish this action after hitting once? + var/terminate_after_action = FALSE /datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) . = ..() @@ -39,12 +41,21 @@ else basic_mob.melee_attack(target) + if(terminate_after_action) + finish_action(controller, TRUE, target_key) /datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key) . = ..() if(!succeeded) controller.clear_blackboard_key(target_key) +/datum/ai_behavior/basic_melee_attack/interact_once + terminate_after_action = TRUE + +/datum/ai_behavior/basic_melee_attack/interact_once/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key) + . = ..() + controller.clear_blackboard_key(target_key) + /datum/ai_behavior/basic_ranged_attack action_cooldown = 0.6 SECONDS behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm new file mode 100644 index 00000000000..d0fb7e3e8c7 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/unbuckle_mob.dm @@ -0,0 +1,14 @@ +/datum/ai_behavior/unbuckle_mob + +/datum/ai_behavior/unbuckle_mob/perform(seconds_per_tick, datum/ai_controller/controller) + . = ..() + + var/mob/living/living_pawn = controller.pawn + var/atom/movable/buckled_too = living_pawn.buckled + + if(isnull(buckled_too)) + finish_action(controller, FALSE) + return + + buckled_too.unbuckle_mob(living_pawn) + finish_action(controller, TRUE) diff --git a/code/datums/ai/generic/find_and_set.dm b/code/datums/ai/generic/find_and_set.dm index f54ba33e6e3..d368641ce0c 100644 --- a/code/datums/ai/generic/find_and_set.dm +++ b/code/datums/ai/generic/find_and_set.dm @@ -72,6 +72,16 @@ if(length(found)) return pick(found) +/// Like find_and_set/in_list, but we return the turf location of the item instead of the item itself. +/datum/ai_behavior/find_and_set/in_list/turf_location + +/datum/ai_behavior/find_and_set/in_list/turf_location/search_tactic(datum/ai_controller/controller, locate_paths, search_range) + . = ..() + if(isnull(.)) + return null + + return get_turf(.) + /** * Variant of find and set which returns an object which can be animated with a staff of change */ @@ -148,3 +158,16 @@ return pick(customers) return null + +/datum/ai_behavior/find_and_set/nearby_friends + action_cooldown = 2 SECONDS + +/datum/ai_behavior/find_and_set/nearby_friends/search_tactic(datum/ai_controller/controller, locate_path, search_range) + var/atom/friend = locate(/mob/living/carbon/human) in oview(search_range, controller.pawn) + + if(isnull(friend)) + return null + + var/mob/living/living_pawn = controller.pawn + var/potential_friend = living_pawn.faction.Find(REF(friend)) ? friend : null + return potential_friend diff --git a/code/datums/ai/generic/generic_behaviors.dm b/code/datums/ai/generic/generic_behaviors.dm index 4f816de4be3..962c8d141cd 100644 --- a/code/datums/ai/generic/generic_behaviors.dm +++ b/code/datums/ai/generic/generic_behaviors.dm @@ -299,6 +299,8 @@ /datum/ai_behavior/perform_speech /datum/ai_behavior/perform_speech/perform(seconds_per_tick, datum/ai_controller/controller, speech, speech_sound) + . = ..() + var/mob/living/living_pawn = controller.pawn if(!istype(living_pawn)) return diff --git a/code/datums/components/listen_and_repeat.dm b/code/datums/components/listen_and_repeat.dm new file mode 100644 index 00000000000..88a8644d262 --- /dev/null +++ b/code/datums/components/listen_and_repeat.dm @@ -0,0 +1,88 @@ +/// The maximum number of phrases we can store in our speech buffer +#define MAX_SPEECH_BUFFER_SIZE 500 +/// Tendency we have to ignore radio chatter +#define RADIO_IGNORE_CHANCE 10 + +/// Simple element that will deterministically set a value based on stuff that the source has heard and will then compel the source to repeat it. +/// Requires a valid AI Blackboard. +/datum/component/listen_and_repeat + /// List of things that we start out having in our speech buffer + var/list/desired_phrases = null + /// The AI Blackboard Key we assign the value to. + var/blackboard_key = null + /// Probability we speak + var/speech_probability = null + /// Probabiliy we switch our phrase + var/switch_phrase_probability = null + /// List of things that we've heard and will repeat. + var/list/speech_buffer = null + +/datum/component/listen_and_repeat/Initialize(list/desired_phrases, blackboard_key) + . = ..() + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + + if(!isnull(desired_phrases)) + LAZYADD(speech_buffer, desired_phrases) + + src.blackboard_key = blackboard_key + + RegisterSignal(parent, COMSIG_MOVABLE_PRE_HEAR, PROC_REF(on_hear)) + RegisterSignal(parent, COMSIG_NEEDS_NEW_PHRASE, PROC_REF(set_new_blackboard_phrase)) + RegisterSignal(parent, COMSIG_LIVING_WRITE_MEMORY, PROC_REF(on_write_memory)) + + ADD_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type) + +/datum/component/listen_and_repeat/Destroy(force, silent) + REMOVE_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type) + return ..() + +/// Called when we hear something. +/datum/component/listen_and_repeat/proc/on_hear(datum/source, list/passed_arguments) + SIGNAL_HANDLER + + var/message = passed_arguments[HEARING_RAW_MESSAGE] + var/speaker = passed_arguments[HEARING_SPEAKER] + var/over_radio = !!passed_arguments[HEARING_RADIO_FREQ] + if(speaker == source) // don't parrot ourselves + return + + if(over_radio && prob(RADIO_IGNORE_CHANCE)) + return + //SKYRAT EDIT ADDITION START - parrot commands + var/mob/living/basic/parrot/maybe_parrot = parent + if(!over_radio && istype(maybe_parrot)) + maybe_parrot.check_command(message, speaker) + // SKYRAT EDIT ADDITION END + + var/number_of_excess_strings = LAZYLEN(speech_buffer) - MAX_SPEECH_BUFFER_SIZE + if(number_of_excess_strings > 0) // only remove if we're overfull + for(var/i in 1 to number_of_excess_strings) + LAZYREMOVE(speech_buffer, pick(speech_buffer)) + + LAZYOR(speech_buffer, html_decode(message)) + +/// Called to set a new value for the blackboard key. +/datum/component/listen_and_repeat/proc/set_new_blackboard_phrase(datum/source) + SIGNAL_HANDLER + var/atom/movable/atom_source = source + var/datum/ai_controller/controller = atom_source.ai_controller + if(!LAZYLEN(speech_buffer)) + controller.clear_blackboard_key(blackboard_key) + return NO_NEW_PHRASE_AVAILABLE + + var/selected_phrase = pick(speech_buffer) + controller.set_blackboard_key(blackboard_key, selected_phrase) + +/// Exports all the speech buffer data to a dedicated blackboard key on the source. +/datum/component/listen_and_repeat/proc/on_write_memory(datum/source, dead, gibbed) + SIGNAL_HANDLER + var/atom/movable/atom_source = source + var/datum/ai_controller/controller = atom_source.ai_controller + if(LAZYLEN(speech_buffer)) // what? well whatever let's just move on + return + + controller.set_blackboard_key(BB_EXPORTABLE_STRING_BUFFER_LIST, speech_buffer.Copy()) + +#undef MAX_SPEECH_BUFFER_SIZE +#undef RADIO_IGNORE_CHANCE diff --git a/code/datums/components/supermatter_crystal.dm b/code/datums/components/supermatter_crystal.dm index 3138f07c5ec..15048ffff93 100644 --- a/code/datums/components/supermatter_crystal.dm +++ b/code/datums/components/supermatter_crystal.dm @@ -300,7 +300,7 @@ message_admins("[atom_source] has consumed [key_name_admin(consumed_mob)] [ADMIN_JMP(atom_source)].") atom_source.investigate_log("has consumed [key_name(consumed_mob)].", INVESTIGATE_ENGINE) consumed_mob.investigate_log("has been dusted by [atom_source].", INVESTIGATE_DEATHS) - if(istype(consumed_mob, /mob/living/simple_animal/parrot/poly)) // Dusting Poly creates a power surge + if(istype(consumed_mob, /mob/living/basic/parrot/poly)) // Dusting Poly creates a power surge force_event(/datum/round_event_control/supermatter_surge/poly, "Poly's revenge") notify_ghosts( "[consumed_mob] has been dusted by [atom_source]!", diff --git a/code/datums/diseases/parrotpossession.dm b/code/datums/diseases/parrotpossession.dm index 23f68e1a42f..bbe587b2a8d 100644 --- a/code/datums/diseases/parrotpossession.dm +++ b/code/datums/diseases/parrotpossession.dm @@ -13,24 +13,41 @@ severity = DISEASE_SEVERITY_MEDIUM infectable_biotypes = MOB_ORGANIC|MOB_UNDEAD|MOB_ROBOTIC|MOB_MINERAL bypasses_immunity = TRUE //2spook - var/mob/living/simple_animal/parrot/poly/ghost/parrot + ///chance we speak + var/speak_chance = 5 + ///controller we speak from + var/datum/ai_controller/basic_controller/parrot_controller /datum/disease/parrot_possession/stage_act(seconds_per_tick, times_fired) . = ..() - if(!.) + + if(!. || isnull(parrot_controller)) return - if(QDELETED(parrot) || parrot.loc != affected_mob) - cure() - return FALSE + var/potential_phrase = parrot_controller.blackboard[BB_PARROT_REPEAT_STRING] - if(length(parrot.speech_buffer) && SPT_PROB(parrot.speak_chance, seconds_per_tick)) // I'm not going to dive into polycode trying to adjust that probability. Enjoy doubled ghost parrot speach - affected_mob.say(pick(parrot.speech_buffer), forced = "parrot possession") + if(SPT_PROB(speak_chance, seconds_per_tick) && !isnull(potential_phrase)) + affected_mob.say(potential_phrase, forced = "parrot possession") /datum/disease/parrot_possession/cure() - if(parrot && parrot.loc == affected_mob) - parrot.forceMove(affected_mob.drop_location()) - affected_mob.visible_message(span_danger("[parrot] is violently driven out of [affected_mob]!"), span_userdanger("[parrot] bursts out of your chest!")) - ..() + var/atom/movable/inside_parrot = locate(/mob/living/basic/parrot/poly/ghost) in affected_mob + if(inside_parrot) + UnregisterSignal(inside_parrot, list(COMSIG_PREQDELETED, COMSIG_MOVABLE_MOVED)) + inside_parrot.forceMove(affected_mob.drop_location()) + affected_mob.visible_message( + span_danger("[inside_parrot] is violently driven out of [affected_mob]!"), + span_userdanger("[inside_parrot] bursts out of your chest!"), + ) + parrot_controller = null + return ..() + +/datum/disease/parrot_possession/proc/set_parrot(mob/living/parrot) + parrot_controller = parrot.ai_controller + RegisterSignals(parrot, list(COMSIG_PREQDELETED, COMSIG_MOVABLE_MOVED), PROC_REF(on_parrot_exit)) + +/datum/disease/parrot_possession/proc/on_parrot_exit(datum/source) + SIGNAL_HANDLER + UnregisterSignal(source, list(COMSIG_PREQDELETED, COMSIG_MOVABLE_MOVED)) + cure() diff --git a/code/datums/elements/pet_bonus.dm b/code/datums/elements/pet_bonus.dm index 41977da31c0..5ef8b515077 100644 --- a/code/datums/elements/pet_bonus.dm +++ b/code/datums/elements/pet_bonus.dm @@ -33,6 +33,7 @@ return new /obj/effect/temp_visual/heart(pet.loc) + SEND_SIGNAL(pet, COMSIG_ANIMAL_PET, petter, modifiers) if(emote_message && prob(33)) pet.manual_emote(emote_message) petter.add_mood_event("petting_bonus", moodlet, pet) diff --git a/code/datums/memory/_memory.dm b/code/datums/memory/_memory.dm index 2b3e250a3fb..dd571c85746 100644 --- a/code/datums/memory/_memory.dm +++ b/code/datums/memory/_memory.dm @@ -266,6 +266,7 @@ /mob/living/basic/morph, /mob/living/basic/mouse, /mob/living/basic/mushroom, + /mob/living/basic/parrot, /mob/living/basic/pet/dog/breaddog, /mob/living/basic/pet/dog/corgi, /mob/living/basic/pet/dog/pug, @@ -276,7 +277,6 @@ /mob/living/basic/stickman, /mob/living/basic/stickman/dog, /mob/living/simple_animal/hostile/megafauna/dragon/lesser, - /mob/living/simple_animal/parrot, /mob/living/simple_animal/pet/cat, /mob/living/simple_animal/pet/cat/cak, /obj/item/food/sausage/american, diff --git a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm index 3ea6488b2d4..7521ff15549 100644 --- a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm +++ b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm @@ -404,10 +404,10 @@ /datum/export/pirate/parrot cost = 2000 unit_name = "alive parrot" - export_types = list(/mob/living/simple_animal/parrot) + export_types = list(/mob/living/basic/parrot) /datum/export/pirate/parrot/find_loot() - for(var/mob/living/simple_animal/parrot/current_parrot in GLOB.alive_mob_list) + for(var/mob/living/basic/parrot/current_parrot in GLOB.alive_mob_list) var/turf/parrot_turf = get_turf(current_parrot) if(parrot_turf && is_station_level(parrot_turf.z)) return current_parrot diff --git a/code/modules/antagonists/traitor/objectives/kill_pet.dm b/code/modules/antagonists/traitor/objectives/kill_pet.dm index 8ea89cb44d0..01ab042f11b 100644 --- a/code/modules/antagonists/traitor/objectives/kill_pet.dm +++ b/code/modules/antagonists/traitor/objectives/kill_pet.dm @@ -24,7 +24,7 @@ ), JOB_CAPTAIN = /mob/living/basic/pet/fox/renault, JOB_CHIEF_MEDICAL_OFFICER = /mob/living/simple_animal/pet/cat/runtime, - JOB_CHIEF_ENGINEER = /mob/living/simple_animal/parrot/poly, + JOB_CHIEF_ENGINEER = /mob/living/basic/parrot/poly, JOB_QUARTERMASTER = list( /mob/living/basic/gorilla/cargorilla, /mob/living/basic/sloth/citrus, diff --git a/code/modules/cargo/packs/livestock.dm b/code/modules/cargo/packs/livestock.dm index ef9fb961823..942b1414cf9 100644 --- a/code/modules/cargo/packs/livestock.dm +++ b/code/modules/cargo/packs/livestock.dm @@ -6,13 +6,13 @@ name = "Bird Crate" desc = "Contains five expert telecommunication birds." cost = CARGO_CRATE_VALUE * 8 - contains = list(/mob/living/simple_animal/parrot) + contains = list(/mob/living/basic/parrot) crate_name = "parrot crate" /datum/supply_pack/critter/parrot/generate() . = ..() for(var/i in 1 to 4) - new /mob/living/simple_animal/parrot(.) + new /mob/living/basic/parrot(.) /datum/supply_pack/critter/butterfly name = "Butterflies Crate" diff --git a/code/modules/events/ghost_role/sentience.dm b/code/modules/events/ghost_role/sentience.dm index abc57d33a07..f33333ddb1b 100644 --- a/code/modules/events/ghost_role/sentience.dm +++ b/code/modules/events/ghost_role/sentience.dm @@ -7,6 +7,7 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list( /mob/living/basic/goat, /mob/living/basic/lizard, /mob/living/basic/mouse/brown/tom, + /mob/living/basic/parrot, /mob/living/basic/pet, /mob/living/basic/pig, /mob/living/basic/rabbit, @@ -16,7 +17,6 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list( /mob/living/basic/spider/giant/sgt_araneus, /mob/living/simple_animal/bot/secbot/beepsky, /mob/living/simple_animal/hostile/retaliate/goose/vomit, - /mob/living/simple_animal/parrot, /mob/living/simple_animal/pet, ))) diff --git a/code/modules/events/holiday/halloween.dm b/code/modules/events/holiday/halloween.dm index d52dd1b9c50..8eb29fa706c 100644 --- a/code/modules/events/holiday/halloween.dm +++ b/code/modules/events/holiday/halloween.dm @@ -18,9 +18,9 @@ for(var/mob/living/basic/pet/dog/corgi/ian/Ian in GLOB.mob_living_list) Ian.place_on_head(new /obj/item/bedsheet(Ian)) - for(var/mob/living/simple_animal/parrot/poly/Poly in GLOB.mob_living_list) - new /mob/living/simple_animal/parrot/poly/ghost(Poly.loc) - qdel(Poly) + for(var/mob/living/basic/parrot/poly/bird in GLOB.mob_living_list) + new /mob/living/basic/parrot/poly/ghost(bird.loc) + qdel(bird) /datum/round_event/spooky/announce(fake) priority_announce(pick("RATTLE ME BONES!","THE RIDE NEVER ENDS!", "A SKELETON POPS OUT!", "SPOOKY SCARY SKELETONS!", "CREWMEMBERS BEWARE, YOU'RE IN FOR A SCARE!") , "THE CALL IS COMING FROM INSIDE THE HOUSE") diff --git a/code/modules/events/wizard/petsplosion.dm b/code/modules/events/wizard/petsplosion.dm index a9664d8dd47..282dae5d33c 100644 --- a/code/modules/events/wizard/petsplosion.dm +++ b/code/modules/events/wizard/petsplosion.dm @@ -9,6 +9,7 @@ GLOBAL_LIST_INIT(petsplosion_candidates, typecacheof(list( /mob/living/basic/lizard, /mob/living/basic/mothroach, /mob/living/basic/mouse/brown/tom, + /mob/living/basic/parrot, /mob/living/basic/pet, /mob/living/basic/pig, /mob/living/basic/rabbit, @@ -17,7 +18,6 @@ GLOBAL_LIST_INIT(petsplosion_candidates, typecacheof(list( /mob/living/basic/snake, /mob/living/basic/spider/giant/sgt_araneus, /mob/living/simple_animal/hostile/retaliate/goose/vomit, - /mob/living/simple_animal/parrot, /mob/living/simple_animal/pet, ))) diff --git a/code/modules/mob/living/basic/pets/parrot/_parrot.dm b/code/modules/mob/living/basic/pets/parrot/_parrot.dm new file mode 100644 index 00000000000..42aa0884816 --- /dev/null +++ b/code/modules/mob/living/basic/pets/parrot/_parrot.dm @@ -0,0 +1,458 @@ +#define FORCED_SPEECH_COOLDOWN_DURATION 5 SECONDS + +GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list( + /datum/strippable_item/parrot_headset, +))) + + +/// Parrots! Klepto bastards that imitate your speech and hoard your shit. +/mob/living/basic/parrot + name = "parrot" + desc = "The parrot squawks, \"They're a Parrot! BAWWK!\"" + icon = 'icons/mob/simple/animal.dmi' + icon_state = "parrot_fly" + icon_living = "parrot_fly" + icon_dead = "parrot_dead" + density = FALSE + health = 80 + maxHealth = 80 + pass_flags = PASSTABLE | PASSMOB + + guaranteed_butcher_results = list(/obj/item/food/cracker = 1) + melee_damage_upper = 10 + melee_damage_lower = 5 + + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently moves aside" + response_disarm_simple = "gently move aside" + response_harm_continuous = "swats" + response_harm_simple = "swat" + combat_mode = TRUE //parrots now start "aggressive" since only player parrots will nuzzle. + attack_verb_continuous = "chomps" + attack_verb_simple = "chomp" + attack_vis_effect = ATTACK_EFFECT_BITE + friendly_verb_continuous = "grooms" + friendly_verb_simple = "groom" + mob_size = MOB_SIZE_SMALL + gold_core_spawnable = FRIENDLY_SPAWN + + ai_controller = /datum/ai_controller/basic_controller/parrot + + /// Icon we use while sitting + var/icon_sit = "parrot_sit" + + ///Headset for Poly to yell at engineers :) + var/obj/item/radio/headset/ears = null + + ///Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding. + var/obj/item/held_item = null + + /// The blackboard key we use to store the string we're repeating + var/speech_blackboard_key = BB_PARROT_REPEAT_STRING + /// The generic probability odds we have to do a speech-related action + var/speech_probability_rate = 5 + /// The generic probability odds we have to switch out our speech string + var/speech_shuffle_rate = 30 + + /// Contains all of the perches that parrots will generally sit on until something catches their eye. + var/static/list/desired_perches = typecacheof(list( + /obj/machinery/computer, + /obj/machinery/dna_scannernew, + /obj/machinery/nuclearbomb, + /obj/machinery/recharge_station, + /obj/machinery/smartfridge, + /obj/machinery/suit_storage_unit, + /obj/machinery/telecomms, + /obj/machinery/teleport, + /obj/structure/displaycase, + /obj/structure/filingcabinet, + /obj/structure/frame/computer, + )) + ///items we wont pick up + var/static/list/ignore_items = typecacheof(list(/obj/item/radio)) + + /// Food that Poly loves to eat (spoiler alert it's just crackers) + var/static/list/edibles = list( + /obj/item/food/cracker, + ) + + /// Tracks the times when we send a phrase through either being pet or attack to ensure it's not abused to flood + COOLDOWN_DECLARE(forced_speech_cooldown) + +/mob/living/basic/parrot/Initialize(mapload) + . = ..() + setup_headset() + update_speech_blackboards() + ai_controller.set_blackboard_key(BB_PARROT_PERCH_TYPES, desired_perches) + ai_controller.set_blackboard_key(BB_IGNORE_ITEMS, ignore_items) + AddElement(/datum/element/pet_bonus) // parrots will listen for the signal this element sends in order to say something in response to the pat + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/strippable, GLOB.strippable_parrot_items) + AddElement(/datum/element/simple_flying) + AddComponent(/datum/component/listen_and_repeat, desired_phrases = get_static_list_of_phrases(), blackboard_key = BB_PARROT_REPEAT_STRING) + AddComponent(\ + /datum/component/tameable,\ + food_types = edibles,\ + tame_chance = 100,\ + bonus_tame_chance = 0,\ + after_tame = CALLBACK(src, PROC_REF(tamed)),\ + ) + + RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attacking)) + RegisterSignal(src, COMSIG_MOB_CLICKON, PROC_REF(on_click)) + RegisterSignal(src, COMSIG_ATOM_ATTACKBY_SECONDARY, PROC_REF(on_attacked)) // this means we could have a peaceful interaction, like getting a cracker + RegisterSignal(src, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_injured)) // this means we got hurt and it's go time + RegisterSignal(src, COMSIG_ANIMAL_PET, PROC_REF(on_pet)) + RegisterSignal(src, COMSIG_KB_MOB_DROPITEM_DOWN, PROC_REF(drop_item_on_signal)) + +/mob/living/basic/parrot/Destroy() + // should have cleaned these up on death, but let's be super safe in case that didn't happen + if(!QDELETED(ears)) + QDEL_NULL(ears) + if(!QDELETED(held_item)) + QDEL_NULL(held_item) + return ..() + +/mob/living/basic/parrot/death(gibbed) + if(held_item) + held_item.forceMove(drop_location()) + held_item = null + + if(ears) + ears.forceMove(drop_location()) + ears = null + + if(!isnull(buckled)) + buckled.unbuckle_mob(src, force = TRUE) + buckled = null + pixel_x = base_pixel_x + pixel_y = base_pixel_y + + return ..() + +/mob/living/basic/parrot/examine(mob/user) + . = ..() + . += "It appears to [isnull(held_item) ? "not be holding anything." : "be holding \a [held_item]."]" + + if(stat != DEAD) + return + + if(HAS_MIND_TRAIT(user, TRAIT_NAIVE)) + . += pick( + "It seems tired and shagged out after a long squawk.", + "It seems to be pining for the fjords.", + "It's resting. It's a beautiful bird. Lovely plumage.", + ) + else + . += pick( + "This is a late parrot.", + "This is an ex-parrot.", + "This parrot is no more.", + ) + +/mob/living/basic/parrot/say_dead(message) + return // this is so flarped + +/mob/living/basic/parrot/get_status_tab_items() + . = ..() + . += "Held Item: [held_item]" + +/mob/living/basic/parrot/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) + if(stat != DEAD) // parrots have evolved to let them fly in space because fucking uhhhhhhhhhh + return TRUE + return ..() + +/mob/living/basic/parrot/radio(message, list/message_mods = list(), list/spans, language) //literally copied from human/radio(), but there's no other way to do this. at least it's better than it used to be. + . = ..() + if(. != NONE) + return + + if(message_mods[MODE_HEADSET]) + if(ears) + ears.talk_into(src, message, , spans, language, message_mods) + return ITALICS | REDUCE_RANGE + else if(message_mods[RADIO_EXTENSION] == MODE_DEPARTMENT) + if(ears) + ears.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods) + return ITALICS | REDUCE_RANGE + else if(message_mods[RADIO_EXTENSION] in GLOB.radiochannels) + if(ears) + ears.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods) + return ITALICS | REDUCE_RANGE + + return NONE + +/mob/living/basic/parrot/update_icon_state() + . = ..() + if(HAS_TRAIT(src, TRAIT_PARROT_PERCHED)) + icon_state = icon_sit + else + icon_state = icon_living + +/// Proc that we just use to see if we're rightclicking something for perch behavior or dropping the item we currently ahve +/mob/living/basic/parrot/proc/on_click(mob/living/basic/source, atom/target, params) + SIGNAL_HANDLER + if(!LAZYACCESS(params, RIGHT_CLICK) || !CanReach(target)) + return + if(start_perching(target) && !isnull(held_item)) + drop_held_item(gently = TRUE) + +/// Proc that handles sending the signal and returning a valid phrase to say. Will not do anything if we don't have a stat or if we're cliented. +/// Will return either a string or null. +/mob/living/basic/parrot/proc/get_phrase() + if(!isnull(client) || stat != CONSCIOUS) + return null + + if(!COOLDOWN_FINISHED(src, forced_speech_cooldown)) + return null + + var/return_value = SEND_SIGNAL(src, COMSIG_NEEDS_NEW_PHRASE) + if(return_value & NO_NEW_PHRASE_AVAILABLE) + return null + + COOLDOWN_START(src, forced_speech_cooldown, FORCED_SPEECH_COOLDOWN_DURATION) + return ai_controller.blackboard[BB_PARROT_REPEAT_STRING] + +/// Proc that listens for when a parrot is pet so we can dispatch a voice line. +/mob/living/basic/parrot/proc/on_pet(mob/living/basic/source, mob/living/petter, modifiers) + SIGNAL_HANDLER + var/return_value = get_phrase() + if(isnull(return_value)) + return + + INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, say), message = return_value, forced = "parrot oneliner on pet") + +/// Proc that ascertains the type of perch we're dealing with and starts the perching process. +/// Returns TRUE if we started perching, FALSE otherwise. +/mob/living/basic/parrot/proc/start_perching(atom/target) + if(HAS_TRAIT(src, TRAIT_PARROT_PERCHED)) + balloon_alert(src, "already perched!") + return FALSE + + if(ishuman(target)) + return perch_on_human(target) + + if(!is_type_in_typecache(target, desired_perches)) + return FALSE + + forceMove(get_turf(target)) + drop_held_item(gently = TRUE) // comfy :) + toggle_perched(perched = TRUE) + RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(after_move)) + return TRUE + +/mob/living/basic/parrot/proc/after_move(atom/source) + SIGNAL_HANDLER + + UnregisterSignal(src, COMSIG_MOVABLE_MOVED) + toggle_perched(perched = FALSE) + +/// Proc that will perch us on a human. Returns TRUE if we perched, FALSE otherwise. +/mob/living/basic/parrot/proc/perch_on_human(mob/living/carbon/human/target) + if(LAZYLEN(target.buckled_mobs) >= target.max_buckled_mobs) + balloon_alert(src, "can't perch on them!") + return FALSE + + forceMove(get_turf(target)) + if(!target.buckle_mob(src, TRUE)) + return FALSE + + to_chat(src, span_notice("You sit on [target]'s shoulder.")) + toggle_perched(perched = TRUE) + RegisterSignal(src, COMSIG_LIVING_SET_BUCKLED, PROC_REF(on_unbuckle)) + return TRUE + +/mob/living/basic/parrot/proc/on_unbuckle(mob/living/source, atom/movable/new_buckled) + SIGNAL_HANDLER + + if(new_buckled) + return + UnregisterSignal(src, COMSIG_LIVING_SET_BUCKLED) + toggle_perched(perched = FALSE) + +/mob/living/basic/parrot/proc/toggle_perched(perched) + if(!perched) + REMOVE_TRAIT(src, TRAIT_PARROT_PERCHED, TRAIT_GENERIC) + else + ADD_TRAIT(src, TRAIT_PARROT_PERCHED, TRAIT_GENERIC) + update_appearance(UPDATE_ICON_STATE) + +/// Master proc which will determine the intent of OUR attacks on an object and summon the relevant procs accordingly. +/// This is pretty much meant for players, AI will use the task-specific procs instead. +/mob/living/basic/parrot/proc/pre_attacking(mob/living/basic/source, atom/target) + SIGNAL_HANDLER + if(stat != CONSCIOUS) + return + + if(isitem(target) && steal_from_ground(target)) + return COMPONENT_HOSTILE_NO_ATTACK + + if(iscarbon(target) && steal_from_mob(target)) + return COMPONENT_HOSTILE_NO_ATTACK + +/// Picks up an item from the ground and puts it in our claws. Returns TRUE if we picked it up, FALSE otherwise. +/mob/living/basic/parrot/proc/steal_from_ground(obj/item/target) + if(!isnull(held_item)) + balloon_alert(src, "already holding something!") + return FALSE + + if(target.w_class > WEIGHT_CLASS_SMALL) + balloon_alert(src, "too big to pick up!") + return FALSE + + pick_up_item(target) + visible_message( + span_notice("[src] grabs [held_item]!"), + span_notice("You grab [held_item]!"), + span_hear("You hear the sounds of wings flapping furiously."), + ) + return TRUE + +/// Looks for an item that we can snatch and puts it in our claws. Returns TRUE if we picked it up, FALSE otherwise. +/mob/living/basic/parrot/proc/steal_from_mob(mob/living/carbon/victim) + if(!isnull(held_item)) + balloon_alert(src, "already holding something!") + return FALSE + + for(var/obj/item/stealable in victim.held_items) + if(stealable.w_class > WEIGHT_CLASS_SMALL) + continue + + if(!victim.temporarilyRemoveItemFromInventory(stealable)) + continue + + visible_message( + span_notice("[src] grabs [held_item] out of [victim]'s hand!"), + span_notice("You snag [held_item] out of [victim]'s hand!"), + span_hear("You hear the sounds of wings flapping furiously."), + ) + pick_up_item(stealable) + return TRUE + + return FALSE + +/// If we're right-clicked on with a cracker, we eat the cracker. +/mob/living/basic/parrot/proc/on_attacked(mob/living/basic/source, obj/item/thing, mob/living/attacker, params) + SIGNAL_HANDLER + if(!istype(thing, /obj/item/food/cracker)) // Poly wants a cracker + return + + consume_cracker(thing) // potential clash with the tameable element so we'll leave it to that to handle qdeling the cracker. + return COMPONENT_NO_AFTERATTACK + +/// Eats a cracker (or anything i guess). This would be nice to eventually fold into the basic_eating element but we do too much snowflake inventory code stuff for this to be reliable presently. +/// We don't qdel the item here, we assume the invoking proc will have handled that somehow. +/// Returns TRUE if we ate the thing. +/mob/living/basic/parrot/proc/consume_cracker(obj/item/thing) + to_chat(src, span_notice("[src] eagerly devours \the [thing].")) + if(!istype(thing, /obj/item/food/cracker)) + return TRUE // we still ate it + + if(health < maxHealth) + adjustBruteLoss(-10) + speech_probability_rate *= 1.27 + speech_shuffle_rate += 10 + update_speech_blackboards() + return TRUE + +/// Handles special behavior whenever we are injured. +/mob/living/basic/parrot/proc/on_injured(mob/living/basic/source, mob/living/attacker, attack_flags) + SIGNAL_HANDLER + if(!isnull(client) || stat == CONSCIOUS) + return + + drop_held_item(gently = FALSE) + + var/return_value = get_phrase() + if(isnull(return_value)) + return + + INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, say), message = return_value, forced = "parrot oneliner on attack") + +/// Handles picking up the item we're holding, done in its own proc because of a snowflake edge case we need to account for. No additional logic beyond that. +/// Returns TRUE if we picked it up, FALSE otherwise. +/mob/living/basic/parrot/proc/pick_up_item(obj/item/target) + if(istype(target, /obj/item/food/cracker)) + consume_cracker(target) + qdel(target) + return + + target.forceMove(src) + held_item = target + +/// Handles dropping items we're holding. Gently is a special modifier we can use for special interactions. +/mob/living/basic/parrot/proc/drop_held_item(gently = TRUE) + if(isnull(held_item)) + balloon_alert(src, "nothing to drop!") + return + + if(stat != CONSCIOUS) // don't gotta do shit + return + + if(!gently && isgrenade(held_item)) + var/obj/item/grenade/bomb = held_item + balloon_alert(src, "bombs away!") // you'll likely die too so we can get away with the `!` here + bomb.forceMove(drop_location()) + bomb.detonate() + return + + balloon_alert(src, "dropped item") + held_item.forceMove(drop_location()) + +/mob/living/basic/parrot/Exited(atom/movable/gone, direction) + . = ..() + if(gone != held_item) + return + held_item = null + +/mob/living/basic/parrot/vv_edit_var(var_name, vval) + . = ..() // give admins an easier time when it comes to fucking with poly + switch(var_name) + if(NAMEOF(src, speech_probability_rate)) + update_speech_blackboards() + if(NAMEOF(src, speech_shuffle_rate)) + update_speech_blackboards() + +/// Updates our speech blackboards mob-side to reflect the current speech on the controller to ensure everything is synchronized. +/mob/living/basic/parrot/proc/update_speech_blackboards() + ai_controller.set_blackboard_key(BB_PARROT_REPEAT_PROBABILITY, speech_probability_rate) + ai_controller.set_blackboard_key(BB_PARROT_PHRASE_CHANGE_PROBABILITY, speech_shuffle_rate) + +/// Will simply set up the headset for the parrot to use. Stub, implemented on subtypes. +/mob/living/basic/parrot/proc/setup_headset() + return + +/// Gets a static list of phrases we wish to pass to the element. +/mob/living/basic/parrot/proc/get_static_list_of_phrases() + var/static/list/default_phrases = list( + "BAWWWWK george mellons griffing me!", + "Cracker?", + "Hello!", + "Hi!", + ) + + return default_phrases + +/// Gets the available channels that this parrot has access to. Returns a list of the channels we can use. +/mob/living/basic/parrot/proc/get_available_channels() + var/list/returnable_list = list() + if(isnull(ears)) + return returnable_list + + var/list/headset_channels = ears.channels + for(var/channel in headset_channels) + returnable_list += GLOB.channel_tokens[channel] // will return something like ":e" or ":c" y'know + + return returnable_list + +/mob/living/basic/parrot/proc/tamed() + new /obj/effect/temp_visual/heart(drop_location()) + +/mob/living/basic/parrot/proc/drop_item_on_signal(mob/living/user) + SIGNAL_HANDLER + + drop_held_item() + return COMSIG_KB_ACTIVATED + +#undef FORCED_SPEECH_COOLDOWN_DURATION diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm new file mode 100644 index 00000000000..9b7ecd4af1d --- /dev/null +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/_parrot_controller.dm @@ -0,0 +1,40 @@ +/datum/ai_controller/basic_controller/parrot + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, + BB_HOARD_LOCATION_RANGE = 9, + ) + + ai_traits = STOP_MOVING_WHEN_PULLED + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk/parrot + + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/perch_on_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/hoard_items, + /datum/ai_planning_subtree/parrot_as_in_repeat, // always get a witty oneliner in when you can + ) + +/datum/idle_behavior/idle_random_walk/parrot + ///chance of us moving while perched + var/walk_chance_when_perched = 1 // SKYRAT EDIT CHANGE - More obedient poly ORIGINAL : var/walk_chance_when_perched = 5 + +/datum/idle_behavior/idle_random_walk/parrot/perform_idle_behavior(seconds_per_tick, datum/ai_controller/controller) + var/mob/living/living_pawn = controller.pawn + walk_chance = HAS_TRAIT(living_pawn, TRAIT_PARROT_PERCHED) ? walk_chance_when_perched : initial(walk_chance) + return ..() + +/datum/ai_behavior/travel_towards/and_drop + +/datum/ai_behavior/travel_towards/and_drop/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + var/mob/living/living_mob = controller.pawn + var/obj/drop_item = locate(/obj/item) in (living_mob.contents - typecache_filter_list(living_mob.contents, controller.blackboard[BB_IGNORE_ITEMS])) + drop_item?.forceMove(get_turf(living_mob)) + +/datum/ai_behavior/basic_melee_attack/interact_once/parrot + +/datum/ai_behavior/basic_melee_attack/interact_once/parrot/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + controller.set_blackboard_key(BB_ALWAYS_IGNORE_FACTION, FALSE) diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/ghost_parrot_controller.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/ghost_parrot_controller.dm new file mode 100644 index 00000000000..58bdef408a5 --- /dev/null +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/ghost_parrot_controller.dm @@ -0,0 +1,37 @@ +/// Used for ghost poly. +/datum/ai_controller/basic_controller/parrot/ghost + planning_subtrees = list( + /datum/ai_planning_subtree/parrot_as_in_repeat, + /datum/ai_planning_subtree/possess_humans, + /datum/ai_planning_subtree/hoard_items, + ) + +///subtree to possess humans +/datum/ai_planning_subtree/possess_humans + ///chance we go possess humans + var/possess_chance = 2 + +/datum/ai_planning_subtree/possess_humans/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + + if(controller.blackboard_key_exists(BB_PERCH_TARGET)) + controller.queue_behavior(/datum/ai_behavior/perch_on_target/haunt, BB_PERCH_TARGET) + return SUBTREE_RETURN_FINISH_PLANNING + + + if(!SPT_PROB(possess_chance, seconds_per_tick)) + if(ishuman(living_pawn.loc)) + return SUBTREE_RETURN_FINISH_PLANNING + return + + if(ishuman(living_pawn.loc)) + controller.set_blackboard_key(living_pawn.loc) + return + + controller.queue_behavior(/datum/ai_behavior/find_and_set/conscious_person, BB_PERCH_TARGET) + + +/datum/ai_behavior/perch_on_target/haunt + +/datum/ai_behavior/perch_on_target/haunt/check_human_conditions(mob/living/living_human) + return (living_human.stat != DEAD) diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_hoarding.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_hoarding.dm new file mode 100644 index 00000000000..7484cbfe675 --- /dev/null +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_hoarding.dm @@ -0,0 +1,74 @@ +///subtree to steal items +/datum/ai_planning_subtree/hoard_items + var/theft_chance = 5 + +/datum/ai_planning_subtree/hoard_items/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + + var/turf/myspace = controller.blackboard[BB_HOARD_LOCATION] + + if(isnull(myspace) || myspace.is_blocked_turf(source_atom = controller.pawn) || get_dist(myspace, controller.pawn) > controller.blackboard[BB_HOARD_LOCATION_RANGE]) + controller.queue_behavior(/datum/ai_behavior/find_and_set/hoard_location, BB_HOARD_LOCATION, /turf/open) + return + + //we have an item, go drop! + var/list/our_contents = living_pawn.contents - typecache_filter_list(living_pawn.contents, controller.blackboard[BB_IGNORE_ITEMS]) + if(length(our_contents)) + controller.queue_behavior(/datum/ai_behavior/travel_towards/and_drop, BB_HOARD_LOCATION) + return SUBTREE_RETURN_FINISH_PLANNING + + if(controller.blackboard_key_exists(BB_HOARD_ITEM_TARGET)) + controller.queue_behavior(/datum/ai_behavior/basic_melee_attack/interact_once, BB_HOARD_ITEM_TARGET, BB_TARGETING_STRATEGY) + return SUBTREE_RETURN_FINISH_PLANNING + + if(!SPT_PROB(theft_chance, seconds_per_tick)) + return + controller.queue_behavior(/datum/ai_behavior/find_and_set/hoard_item, BB_HOARD_ITEM_TARGET) + +/datum/ai_behavior/find_and_set/hoard_location + +/datum/ai_behavior/find_and_set/hoard_location/search_tactic(datum/ai_controller/controller, locate_path, search_range) + for(var/turf/open/candidate in oview(search_range, controller.pawn)) + if(isspaceturf(candidate) || isopenspaceturf(candidate)) + continue + if(candidate.is_blocked_turf(source_atom = controller.pawn)) + continue + return candidate + + return null + +/datum/ai_behavior/find_and_set/hoard_item + action_cooldown = 5 SECONDS + behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + +/datum/ai_behavior/find_and_set/hoard_item/search_tactic(datum/ai_controller/controller, locate_path, search_range) + if(!controller.blackboard_key_exists(BB_HOARD_LOCATION)) + return null + var/turf/nest_turf = controller.blackboard[BB_HOARD_LOCATION] + var/mob/living/living_pawn = controller.pawn + for(var/atom/potential_victim in oview(search_range, controller.pawn)) + if(is_type_in_typecache(potential_victim, controller.blackboard[BB_IGNORE_ITEMS])) + continue + if(potential_victim.loc == nest_turf) + continue + if(isitem(potential_victim)) + var/obj/item/item_steal = potential_victim + if(item_steal.w_class <= WEIGHT_CLASS_SMALL) + return potential_victim + if(!ishuman(potential_victim)) + continue + if(living_pawn.faction.Find(REF(potential_victim))) + continue //dont steal from friends + if(holding_valuable(controller, potential_victim)) + controller.set_blackboard_key(BB_ALWAYS_IGNORE_FACTION, TRUE) + return potential_victim + + return null + +/datum/ai_behavior/find_and_set/hoard_item/proc/holding_valuable(datum/ai_controller/controller, mob/living/human_target) + for(var/obj/item/potential_item in human_target.held_items) + if(is_type_in_typecache(potential_item, controller.blackboard[BB_IGNORE_ITEMS])) + continue + if(potential_item.w_class <= WEIGHT_CLASS_SMALL) + return TRUE + return FALSE diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm new file mode 100644 index 00000000000..1bb5c6fc960 --- /dev/null +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parrot_perching.dm @@ -0,0 +1,78 @@ +///subtree to perch on targets +/datum/ai_planning_subtree/perch_on_target + ///perchance... + var/perch_chance = 5 + ///chance we unbuckle + var/unperch_chance = 15 + + +/datum/ai_planning_subtree/perch_on_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/mob/living/living_pawn = controller.pawn + var/atom/buckled_too = living_pawn.buckled + + //do we have a current target or is chance to unbuckle has passed? then unbuckle! + if(buckled_too) + if((SPT_PROB(unperch_chance, seconds_per_tick) || controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET))) + controller.queue_behavior(/datum/ai_behavior/unbuckle_mob) + return + return SUBTREE_RETURN_FINISH_PLANNING + + //if we are perched, we can go find something else to perch too + var/final_chance = HAS_TRAIT(living_pawn, TRAIT_PARROT_PERCHED) ? unperch_chance : perch_chance + + if(!SPT_PROB(final_chance, seconds_per_tick) || controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) + return + + if(controller.blackboard_key_exists(BB_PERCH_TARGET)) + controller.queue_behavior(/datum/ai_behavior/perch_on_target, BB_PERCH_TARGET) + return SUBTREE_RETURN_FINISH_PLANNING + + //50 50 chance to look for an object, or a friend + if(prob(50)) + controller.queue_behavior(/datum/ai_behavior/find_and_set/nearby_friends, BB_PERCH_TARGET) + return + + controller.queue_behavior(/datum/ai_behavior/find_and_set/in_list, BB_PERCH_TARGET, controller.blackboard[BB_PARROT_PERCH_TYPES]) + +/// Parrot behavior that allows them to perch on a target. +/datum/ai_behavior/perch_on_target + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + +/datum/ai_behavior/perch_on_target/setup(datum/ai_controller/controller, target_key) + . = ..() + var/atom/target = controller.blackboard[target_key] + if(QDELETED(target)) + return FALSE + + set_movement_target(controller, target) + +/datum/ai_behavior/perch_on_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key) + . = ..() + var/atom/target = controller.blackboard[target_key] + if(QDELETED(target)) + finish_action(controller, FALSE, target_key) + return + + var/mob/living/basic/parrot/living_pawn = controller.pawn + + if(!ishuman(target)) + living_pawn.start_perching(target) + finish_action(controller, TRUE, target_key) + return + + if(!check_human_conditions(target)) + finish_action(controller, FALSE, target_key) + return + + living_pawn.start_perching(target) + finish_action(controller, TRUE, target_key) + +/datum/ai_behavior/perch_on_target/proc/check_human_conditions(mob/living/living_human) + if(living_human.stat == DEAD || LAZYLEN(living_human.buckled_mobs) >= living_human.max_buckled_mobs) + return FALSE + + return TRUE + +/datum/ai_behavior/perch_on_target/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + controller.clear_blackboard_key(target_key) diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm new file mode 100644 index 00000000000..d1488a60b3b --- /dev/null +++ b/code/modules/mob/living/basic/pets/parrot/parrot_ai/parroting_action.dm @@ -0,0 +1,50 @@ +/// When a parrot... parrots... +/datum/ai_planning_subtree/parrot_as_in_repeat + operational_datums = list(/datum/component/listen_and_repeat) + +/datum/ai_planning_subtree/parrot_as_in_repeat/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/atom/speaking_pawn = controller.pawn + + var/switch_up_probability = controller.blackboard[BB_PARROT_PHRASE_CHANGE_PROBABILITY] + if(SPT_PROB(switch_up_probability, seconds_per_tick) || isnull(controller.blackboard[BB_PARROT_REPEAT_STRING])) + if(SEND_SIGNAL(speaking_pawn, COMSIG_NEEDS_NEW_PHRASE) & NO_NEW_PHRASE_AVAILABLE) + return + + if(!SPT_PROB(controller.blackboard[BB_PARROT_REPEAT_PROBABILITY], seconds_per_tick)) + return + + var/potential_string = controller.blackboard[BB_PARROT_REPEAT_STRING] + if(isnull(potential_string)) + stack_trace("Parrot As In Repeat Subtree somehow is getting a null potential string while not getting `NO_NEW_PHRASE_AVAILABLE`!") + return + + controller.queue_behavior(/datum/ai_behavior/perform_speech/parrot, potential_string) + +/datum/ai_behavior/perform_speech/parrot + action_cooldown = 7.5 SECONDS // gets really annoying (moreso than usual) really fast otherwise + +/datum/ai_behavior/perform_speech/parrot/perform(seconds_per_tick, datum/ai_controller/controller, speech, speech_sound) + var/mob/living/basic/parrot/speaking_pawn = controller.pawn + var/list/available_channels = speaking_pawn.get_available_channels() + var/modified_speech = speech + var/use_radio = prob(50) // we might not even use the radio if we even have a channel + +#define HAS_CHANNEL_PREFIX (speech[1] in GLOB.department_radio_prefixes) && (copytext_char(speech, 2, 3) in GLOB.department_radio_keys) // determine if we need to crop the channel prefix + + if(!length(available_channels)) // might not even use the radio at all + if(HAS_CHANNEL_PREFIX) + modified_speech = copytext_char(speech, 3) + + else + if(HAS_CHANNEL_PREFIX) + modified_speech = "[use_radio ? pick(available_channels) : ""][copytext_char(speech, 3)]" + else + modified_speech = "[use_radio ? pick(available_channels) : ""][speech]" + + + speaking_pawn.say(modified_speech, forced = "AI Controller") + if(speech_sound) + playsound(speaking_pawn, speech_sound, 80, vary = TRUE) + finish_action(controller, TRUE) + +#undef HAS_CHANNEL_PREFIX diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_items.dm b/code/modules/mob/living/basic/pets/parrot/parrot_items.dm new file mode 100644 index 00000000000..c071bf7fdbe --- /dev/null +++ b/code/modules/mob/living/basic/pets/parrot/parrot_items.dm @@ -0,0 +1,60 @@ +/datum/strippable_item/parrot_headset + key = STRIPPABLE_ITEM_PARROT_HEADSET + +/datum/strippable_item/parrot_headset/get_item(atom/source) + var/mob/living/basic/parrot/poly/parrot_source = source + return istype(parrot_source) ? parrot_source.ears : null + +/datum/strippable_item/parrot_headset/try_equip(atom/source, obj/item/equipping, mob/user) + . = ..() + if (!.) + return FALSE + + if (!istype(equipping, /obj/item/radio/headset)) + to_chat(user, span_warning("[equipping] won't fit!")) + return FALSE + + return TRUE + +// There is no delay for putting a headset on a parrot. +/datum/strippable_item/parrot_headset/start_equip(atom/source, obj/item/equipping, mob/user) + return TRUE + +/datum/strippable_item/parrot_headset/finish_equip(atom/source, obj/item/equipping, mob/user) + var/obj/item/radio/headset/radio = equipping + if (!istype(radio)) + return + + var/mob/living/basic/parrot/parrot_source = source + if (!istype(parrot_source)) + return + + if (!user.transferItemToLoc(radio, source)) + return + + parrot_source.ears = radio + + to_chat(user, span_notice("You fit [radio] onto [source].")) + +/datum/strippable_item/parrot_headset/start_unequip(atom/source, mob/user) + . = ..() + if (!.) + return FALSE + + var/mob/living/basic/parrot/parrot_source = source + if (!istype(parrot_source)) + return + + if (parrot_source.stat == CONSCIOUS) + var/list/list_of_channels = parrot_source.get_available_channels() + parrot_source.say("[list_of_channels ? "[pick(list_of_channels)] " : null]BAWWWWWK LEAVE THE HEADSET BAWKKKKK!", forced = "attempted headset removal") + + return TRUE + +/datum/strippable_item/parrot_headset/finish_unequip(atom/source, mob/user) + var/mob/living/basic/parrot/parrot_source = source + if (!istype(parrot_source)) + return + + parrot_source.ears.forceMove(parrot_source.drop_location()) + parrot_source.ears = null diff --git a/code/modules/mob/living/basic/pets/parrot/parrot_subtypes.dm b/code/modules/mob/living/basic/pets/parrot/parrot_subtypes.dm new file mode 100644 index 00000000000..a0e8a4b5294 --- /dev/null +++ b/code/modules/mob/living/basic/pets/parrot/parrot_subtypes.dm @@ -0,0 +1,14 @@ +// this file is for parrots that aren't poly + +/// Parrot that will just randomly spawn with a headset. Nothing too special beyond that. +/mob/living/basic/parrot/headsetted + +/mob/living/basic/parrot/headsetted/setup_headset() + var/headset = pick( + /obj/item/radio/headset/headset_cargo, + /obj/item/radio/headset/headset_eng, + /obj/item/radio/headset/headset_med, + /obj/item/radio/headset/headset_sci, + /obj/item/radio/headset/headset_sec, + ) + ears = new headset(src) diff --git a/code/modules/mob/living/basic/pets/parrot/poly.dm b/code/modules/mob/living/basic/pets/parrot/poly.dm new file mode 100644 index 00000000000..ecd6e054609 --- /dev/null +++ b/code/modules/mob/living/basic/pets/parrot/poly.dm @@ -0,0 +1,254 @@ +/// Default poly, presumably died the last shift and has no special traits. +#define POLY_DEFAULT "default" +/// Poly has survived a number of rounds equivalent to the longest survival of his being. +#define POLY_LONGEST_SURVIVAL "longest_survival" +/// Poly has survived a number of rounds equivalent to the longest deathstreak of his being. +#define POLY_BEATING_DEATHSTREAK "longest_deathstreak" +/// Poly has only just survived a round, and is doing a consecutive one. +#define POLY_CONSECUTIVE_ROUND "consecutive_round" +/// haunt filter we apply to who we possess +#define POLY_POSSESS_FILTER +/// haunt filter color we apply to who we possess +#define POLY_POSSESS_GLOW "#522059" + +/// The classically famous compadre to the Chief Engineer, Poly. +/mob/living/basic/parrot/poly + name = "Poly" + desc = "Poly the Parrot. An expert on quantum cracker theory." + gold_core_spawnable = NO_SPAWN + speech_probability_rate = 13 + + /// Callback to save our memory at the end of the round. + var/datum/callback/roundend_callback = null + /// Did we write the memory to disk? + var/memory_saved = FALSE + /// How long has this bird been alive for? + var/rounds_survived = 0 + /// How long have we survived for at max? + var/longest_survival = 0 + /// How many rounds in a row have we been dead for? + var/longest_deathstreak = 0 + +/mob/living/basic/parrot/poly/Initialize(mapload) + . = ..() + + if(!memory_saved) + roundend_callback = CALLBACK(src, PROC_REF(Write_Memory)) + SSticker.OnRoundend(roundend_callback) + + REGISTER_REQUIRED_MAP_ITEM(1, 1) // every map needs a poly! + update_appearance() + + if(!SStts.tts_enabled) + return + + voice = pick(SStts.available_speakers) + if(SStts.pitch_enabled) + if(findtext(voice, "Woman")) + pitch = 12 // up-pitch by one octave + else + pitch = 24 // up-pitch by 2 octaves + else + voice_filter = "rubberband=pitch=1.5" // Use the filter to pitch up if we can't naturally pitch up. + +/mob/living/basic/parrot/poly/Destroy() + LAZYREMOVE(SSticker.round_end_events, roundend_callback) // we do the memory writing stuff on death, but this is important to yeet as fast as we can if we need to destroy + roundend_callback = null + return ..() + +/mob/living/basic/parrot/poly/death(gibbed) + if(HAS_TRAIT(src, TRAIT_DONT_WRITE_MEMORY)) + return ..() // Don't read memory either. + if(!memory_saved) + Write_Memory(TRUE) + var/special_status = determine_special_poly() + if(special_status == POLY_LONGEST_SURVIVAL || special_status == POLY_BEATING_DEATHSTREAK || prob(0.666)) + var/mob/living/basic/parrot/poly/ghost/specter = new(loc) + if(mind) + mind.transfer_to(specter) + else + specter.key = key + return ..() + +/mob/living/basic/parrot/poly/get_static_list_of_phrases() // there's only one poly, so there should only be one ongoing list of phrases. i guess + var/static/list/phrases_to_return = list() + if(length(phrases_to_return)) + return phrases_to_return + + phrases_to_return += read_memory() // must come first!!! + // now add some valuable lines every poly should have + phrases_to_return += list( + ":e Check the crystal, you chucklefucks!", + ":e OH GOD ITS ABOUT TO DELAMINATE CALL THE SHUTTLE", + ":e WHO TOOK THE DAMN MODSUITS?", + ":e Wire the solars, you lazy bums!", + "Poly wanna cracker!", + ) + switch(determine_special_poly()) + if(POLY_DEFAULT) + phrases_to_return += pick("...alive?", "This isn't parrot heaven!", "I live, I die, I live again!", "The void fades!") + if(POLY_LONGEST_SURVIVAL) + phrases_to_return += pick("...[longest_survival].", "The things I've seen!", "I have lived many lives!", "What are you before me?") + if(POLY_BEATING_DEATHSTREAK) + phrases_to_return += pick("What are you waiting for!", "Violence breeds violence!", "Blood! Blood!", "Strike me down if you dare!") + if(POLY_CONSECUTIVE_ROUND) + phrases_to_return += pick("...again?", "No, It was over!", "Let me out!", "It never ends!") + + return phrases_to_return + +/mob/living/basic/parrot/poly/update_desc() + . = ..() + switch(determine_special_poly()) + if(POLY_LONGEST_SURVIVAL) + desc += " Old as sin, and just as loud. Claimed to be [rounds_survived]." + if(POLY_BEATING_DEATHSTREAK) + desc += " The squawks of [-rounds_survived] dead parrots ring out in your ears..." + if(POLY_CONSECUTIVE_ROUND) + desc += " Over [rounds_survived] shifts without a \"terrible\" \"accident\"!" + +/mob/living/basic/parrot/poly/update_icon() + . = ..() + switch(determine_special_poly()) + if(POLY_LONGEST_SURVIVAL) + add_atom_colour("#EEEE22", FIXED_COLOUR_PRIORITY) + if(POLY_BEATING_DEATHSTREAK) + add_atom_colour("#BB7777", FIXED_COLOUR_PRIORITY) + +/// Reads the memory of the parrot, and updates the necessary variables. Returns a list of phrases to add to the parrot's speech buffer. +/mob/living/basic/parrot/poly/proc/read_memory() + RETURN_TYPE(/list) + var/list/returnable_list = list() + if(fexists("data/npc_saves/Poly.sav")) //legacy compatability to convert old format to new + var/savefile/legacy = new /savefile("data/npc_saves/Poly.sav") + legacy["phrases"] >> returnable_list + legacy["roundssurvived"] >> rounds_survived + legacy["longestsurvival"] >> longest_survival + legacy["longestdeathstreak"] >> longest_deathstreak + fdel("data/npc_saves/Poly.sav") + + else + var/json_file = file("data/npc_saves/Poly.json") + if(!fexists(json_file)) + return + var/list/json = json_decode(file2text(json_file)) + returnable_list = json["phrases"] + rounds_survived = json["roundssurvived"] + longest_survival = json["longestsurvival"] + longest_deathstreak = json["longestdeathstreak"] + + return returnable_list + +/// Determines the type of Poly we might have here based on the statistics we got from the memory. +/mob/living/basic/parrot/poly/proc/determine_special_poly() + if(rounds_survived == longest_survival) + return POLY_LONGEST_SURVIVAL + else if(rounds_survived == longest_deathstreak) + return POLY_BEATING_DEATHSTREAK + else if(rounds_survived > 0) + return POLY_CONSECUTIVE_ROUND + else + return POLY_DEFAULT + +/mob/living/basic/parrot/poly/Write_Memory(dead, gibbed) + . = ..() + if(!. || memory_saved) // if we die, no more memory + return FALSE + + if(!dead && (stat != DEAD)) + dead = FALSE + + var/file_path = "data/npc_saves/Poly.json" + var/list/file_data = list() + + var/list/exportable_speech_buffer = ai_controller.blackboard[BB_EXPORTABLE_STRING_BUFFER_LIST] // should have been populated when we sent the signal out on parent + if(!!length(exportable_speech_buffer)) + file_data["phrases"] = exportable_speech_buffer + + if(dead) + file_data["roundssurvived"] = min(rounds_survived - 1, 0) + file_data["longestsurvival"] = longest_survival + if(rounds_survived - 1 < longest_deathstreak) + file_data["longestdeathstreak"] = rounds_survived - 1 + else + file_data["longestdeathstreak"] = longest_deathstreak + else + + file_data["roundssurvived"] = max(rounds_survived, 0) + 1 + if(rounds_survived + 1 > longest_survival) + file_data["longestsurvival"] = rounds_survived + 1 + else + file_data["longestsurvival"] = longest_survival + file_data["longestdeathstreak"] = longest_deathstreak + + var/formatted_data +#if DM_VERSION >= 515 + formatted_data = json_encode(file_data, JSON_PRETTY_PRINT) +#else + formatted_data = json_encode(file_data) +#endif + + rustg_file_write(formatted_data, file_path) + memory_saved = TRUE + return TRUE + +/mob/living/basic/parrot/poly/setup_headset() + ears = new /obj/item/radio/headset/headset_eng(src) + +/mob/living/basic/parrot/poly/ghost + name = "The Ghost of Poly" + desc = "Doomed to squawk the Earth." + color = "#FFFFFF77" + status_flags = GODMODE + sentience_type = SENTIENCE_BOSS //This is so players can't mindswap into ghost poly to become a literal god + incorporeal_move = INCORPOREAL_MOVE_BASIC + butcher_results = list(/obj/item/ectoplasm = 1) + ai_controller = /datum/ai_controller/basic_controller/parrot/ghost + speech_probability_rate = 1 + +/mob/living/basic/parrot/poly/ghost/Initialize(mapload) + // block anything and everything that could possibly happen with writing memory for ghosts + memory_saved = TRUE + ADD_TRAIT(src, TRAIT_DONT_WRITE_MEMORY, INNATE_TRAIT) + RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + return ..() + +//we perch on human souls +/mob/living/basic/parrot/poly/ghost/perch_on_human(mob/living/carbon/human/target) + if(loc == target) //dismount + forceMove(get_turf(target)) + return FALSE + if(ishuman(loc)) + balloon_alert(src, "already possessing!") + return FALSE + forceMove(target) + return TRUE + +/mob/living/basic/parrot/poly/ghost/proc/on_moved(atom/movable/movable, atom/old_loc) + SIGNAL_HANDLER + + if(ishuman(old_loc)) + var/mob/living/unpossessed_human = old_loc + unpossessed_human.remove_filter(POLY_POSSESS_FILTER) + return + + if(!ishuman(loc)) + return + + var/mob/living/possessed_human = loc + possessed_human.add_filter(POLY_POSSESS_FILTER, 2, list("type" = "outline", "color" = POLY_POSSESS_GLOW, "size" = 2)) + var/filter = possessed_human.get_filter(POLY_POSSESS_FILTER) + + if(filter) + animate(filter, alpha = 200, time = 2 SECONDS, loop = -1) + animate(alpha = 60, time = 2 SECONDS) + + var/datum/disease/parrot_possession/on_possession = new /datum/disease/parrot_possession + on_possession.set_parrot(src) + possessed_human.ForceContractDisease(on_possession, make_copy = FALSE, del_on_fail = TRUE) + +#undef POLY_DEFAULT +#undef POLY_LONGEST_SURVIVAL +#undef POLY_BEATING_DEATHSTREAK +#undef POLY_CONSECUTIVE_ROUND +#undef POLY_POSSESS_FILTER +#undef POLY_POSSESS_GLOW diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index cfda7721da0..fcdc37fdbaa 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -73,7 +73,11 @@ var/list/datum/bioware/biowares /// What types of mobs are allowed to ride/buckle to this mob - var/static/list/can_ride_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot)) + var/static/list/can_ride_typecache = typecacheof(list( + /mob/living/basic/parrot, + /mob/living/carbon/human, + /mob/living/simple_animal/slime, + )) var/lastpuke = 0 var/account_id diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index b92bc08ceb7..6095638318d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1515,6 +1515,7 @@ /mob/living/basic/morph, /mob/living/basic/mouse, /mob/living/basic/mushroom, + /mob/living/basic/parrot, /mob/living/basic/pet/dog/breaddog, /mob/living/basic/pet/dog/corgi, /mob/living/basic/pet/dog/pug, @@ -1525,7 +1526,6 @@ /mob/living/basic/stickman, /mob/living/basic/stickman/dog, /mob/living/simple_animal/hostile/megafauna/dragon/lesser, - /mob/living/simple_animal/parrot, /mob/living/simple_animal/pet/cat, /mob/living/simple_animal/pet/cat/cak, ) diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm index 56d066cdcc0..50b4abf8035 100644 --- a/code/modules/mob/living/living_say.dm +++ b/code/modules/mob/living/living_say.dm @@ -255,7 +255,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( /mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range=0) - if(!GET_CLIENT(src)) + if((SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_HEAR, args) & COMSIG_MOVABLE_CANCEL_HEARING) || !GET_CLIENT(src)) return FALSE var/deaf_message @@ -536,7 +536,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( I.talk_into(src, message, , spans, language, message_mods) return ITALICS | REDUCE_RANGE - return 0 + return NONE /mob/living/say_mod(input, list/message_mods = list()) if(message_mods[WHISPER_MODE] == MODE_WHISPER) diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm deleted file mode 100644 index b02e8354da8..00000000000 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ /dev/null @@ -1,1070 +0,0 @@ -/* Parrots! - * Contains - * Defines - * Inventory (headset stuff) - * Attack responces - * AI - * Procs / Verbs (usable by players) - * Sub-types - * Hear & say (the things we do for gimmicks) - */ - -/* - * Defines - */ - -//Only a maximum of one action and one intent should be active at any given time. -//Actions -#define PARROT_PERCH (1<<0) //Sitting/sleeping, not moving -#define PARROT_SWOOP (1<<1) //Moving towards or away from a target -#define PARROT_WANDER (1<<2) //Moving without a specific target in mind - -//Intents -#define PARROT_STEAL (1<<3) //Flying towards a target to steal it/from it -#define PARROT_ATTACK (1<<4) //Flying towards a target to attack it -#define PARROT_RETURN (1<<5) //Flying towards its perch -#define PARROT_FLEE (1<<6) //Flying away from its attacker - - -/mob/living/simple_animal/parrot - name = "parrot" - desc = "The parrot squawks, \"They're a Parrot! BAWWK!\"" //' - icon = 'icons/mob/simple/animal.dmi' - icon_state = "parrot_fly" - icon_living = "parrot_fly" - icon_dead = "parrot_dead" - var/icon_sit = "parrot_sit" - density = FALSE - health = 80 - maxHealth = 80 - pass_flags = PASSTABLE | PASSMOB - - speak = list("Hi!","Hello!","Cracker?","BAWWWWK george mellons griffing me!") - speak_emote = list("squawks","says","yells") - emote_hear = list("squawks.","bawks!") - emote_see = list("flutters their wings.") - - speak_chance = 1 //1% (1 in 100) chance every tick; So about once per 150 seconds, assuming an average tick is 1.5s - turns_per_move = 5 - butcher_results = list(/obj/item/food/cracker = 1) - melee_damage_upper = 10 - melee_damage_lower = 5 - - response_help_continuous = "pets" - response_help_simple = "pet" - response_disarm_continuous = "gently moves aside" - response_disarm_simple = "gently move aside" - response_harm_continuous = "swats" - response_harm_simple = "swat" - stop_automated_movement = 1 - combat_mode = TRUE //parrots now start "aggressive" since only player parrots will nuzzle. - attack_verb_continuous = "chomps" - attack_verb_simple = "chomp" - attack_vis_effect = ATTACK_EFFECT_BITE - friendly_verb_continuous = "grooms" - friendly_verb_simple = "groom" - mob_size = MOB_SIZE_SMALL - gold_core_spawnable = FRIENDLY_SPAWN - - var/parrot_damage_upper = 10 - var/parrot_state = PARROT_WANDER //Hunt for a perch when created - var/parrot_sleep_max = 25 //The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in life() being run every single tick. - var/parrot_sleep_dur = 25 //Same as above, this is the var that physically counts down - var/parrot_dam_zone = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_ARM, BODY_ZONE_R_LEG) //For humans, select a bodypart to attack - - var/parrot_speed = 5 //"Delay in world ticks between movement." according to byond. Yeah, that's BS but it does directly affect movement. Higher number = slower. - var/parrot_lastmove = null //Updates/Stores position of the parrot while it's moving - var/parrot_stuck = 0 //If parrot_lastmove hasn't changed, this will increment until it reaches parrot_stuck_threshold - var/parrot_stuck_threshold = 10 //if this == parrot_stuck, it'll force the parrot back to wandering - - var/list/speech_buffer = list() - var/speech_shuffle_rate = 20 - var/list/available_channels = list() - - //Headset for Poly to yell at engineers :) - var/obj/item/radio/headset/ears = null - - //Wheter the Parrot should come with a headset - var/spawn_headset = TRUE - - //The thing the parrot is currently interested in. This gets used for items the parrot wants to pick up, mobs it wants to steal from, - //mobs it wants to attack or mobs that have attacked it - var/atom/movable/parrot_interest = null - - //Parrots will generally sit on their perch unless something catches their eye. - //These vars store their preffered perch and if they dont have one, what they can use as a perch - var/obj/parrot_perch = null - var/obj/desired_perches = list(/obj/structure/frame/computer, - /obj/structure/displaycase, - /obj/structure/filingcabinet, - /obj/machinery/teleport, - /obj/machinery/dna_scannernew, - /obj/machinery/telecomms, - /obj/machinery/nuclearbomb, - /obj/machinery/recharge_station, - /obj/machinery/smartfridge, - /obj/machinery/computer, - /obj/machinery/suit_storage_unit, - ) - - //Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding. - var/obj/item/held_item = null - - -/mob/living/simple_animal/parrot/Initialize(mapload) - . = ..() - parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var - - add_verb(src, list(/mob/living/simple_animal/parrot/proc/steal_from_ground, \ - /mob/living/simple_animal/parrot/proc/steal_from_mob, \ - /mob/living/simple_animal/parrot/verb/drop_held_item_player, \ - /mob/living/simple_animal/parrot/proc/perch_player, \ - /mob/living/simple_animal/parrot/proc/toggle_mode, - /mob/living/simple_animal/parrot/proc/perch_mob_player)) - - AddElement(/datum/element/strippable, GLOB.strippable_parrot_items) - AddElement(/datum/element/simple_flying) - if(!spawn_headset) - return - if(!ears) - var/headset = pick(/obj/item/radio/headset/headset_sec, \ - /obj/item/radio/headset/headset_eng, \ - /obj/item/radio/headset/headset_med, \ - /obj/item/radio/headset/headset_sci, \ - /obj/item/radio/headset/headset_cargo) - ears = new headset(src) - -/mob/living/simple_animal/parrot/Destroy() - QDEL_NULL(ears) - return ..() - -/mob/living/simple_animal/parrot/examine(mob/user) - . = ..() - if(stat != DEAD) - return - - if(HAS_MIND_TRAIT(user, TRAIT_NAIVE)) - . += pick( - "It seems tired and shagged out after a long squawk.", - "It seems to be pining for the fjords.", - "It's resting. It's a beautiful bird. Lovely plumage.", - ) - else - . += pick( - "This parrot is no more.", - "This is a late parrot.", - "This is an ex-parrot.", - ) - -/mob/living/simple_animal/parrot/death(gibbed) - if(held_item) - held_item.forceMove(drop_location()) - held_item = null - SSmove_manager.stop_looping(src) - - if(buckled) - buckled.unbuckle_mob(src,force=1) - buckled = null - pixel_x = base_pixel_x - pixel_y = base_pixel_y - - return ..() - - -/mob/living/simple_animal/parrot/get_status_tab_items() - . = ..() - . += "Held Item: [held_item]" - -// SKYRAT EDIT REMOVAL BEGIN - MOVED TO modular_skyrat/modules/poly_commands -/* -/mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range) - . = ..() - if(speaker != src && prob(50)) //Dont imitate ourselves - if(!radio_freq || prob(10)) - if(speech_buffer.len >= 500) - speech_buffer -= pick(speech_buffer) - speech_buffer |= html_decode(raw_message) - if(speaker == src && !client) //If a parrot squawks in the woods and no one is around to hear it, does it make a sound? This code says yes! - return message -*/ -// SKYRAT EDIT REMOVAL END - -/mob/living/simple_animal/parrot/radio(message, list/message_mods = list(), list/spans, language) //literally copied from human/radio(), but there's no other way to do this. at least it's better than it used to be. - . = ..() - if(.) - return - - if(message_mods[MODE_HEADSET]) - if(ears) - ears.talk_into(src, message, , spans, language, message_mods) - return ITALICS | REDUCE_RANGE - else if(message_mods[RADIO_EXTENSION] == MODE_DEPARTMENT) - if(ears) - ears.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods) - return ITALICS | REDUCE_RANGE - else if(message_mods[RADIO_EXTENSION] in GLOB.radiochannels) - if(ears) - ears.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods) - return ITALICS | REDUCE_RANGE - - return FALSE - -GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list( - /datum/strippable_item/parrot_headset, -))) - -/datum/strippable_item/parrot_headset - key = STRIPPABLE_ITEM_PARROT_HEADSET - -/datum/strippable_item/parrot_headset/get_item(atom/source) - var/mob/living/simple_animal/parrot/parrot_source = source - return istype(parrot_source) ? parrot_source.ears : null - -/datum/strippable_item/parrot_headset/try_equip(atom/source, obj/item/equipping, mob/user) - . = ..() - if (!.) - return FALSE - - if (!istype(equipping, /obj/item/radio/headset)) - to_chat(user, span_warning("[equipping] won't fit!")) - return FALSE - - return TRUE - -// There is no delay for putting a headset on a parrot. -/datum/strippable_item/parrot_headset/start_equip(atom/source, obj/item/equipping, mob/user) - return TRUE - -/datum/strippable_item/parrot_headset/finish_equip(atom/source, obj/item/equipping, mob/user) - var/obj/item/radio/headset/radio = equipping - if (!istype(radio)) - return - - var/mob/living/simple_animal/parrot/parrot_source = source - if (!istype(parrot_source)) - return - - if (!user.transferItemToLoc(radio, source)) - return - - parrot_source.ears = radio - - to_chat(user, span_notice("You fit [radio] onto [source].")) - - parrot_source.available_channels.Cut() - - for (var/channel in radio.channels) - var/channel_to_add - - switch (channel) - if (RADIO_CHANNEL_ENGINEERING) - channel_to_add = RADIO_TOKEN_ENGINEERING - if (RADIO_CHANNEL_COMMAND) - channel_to_add = RADIO_TOKEN_COMMAND - if (RADIO_CHANNEL_SECURITY) - channel_to_add = RADIO_TOKEN_SECURITY - if (RADIO_CHANNEL_SCIENCE) - channel_to_add = RADIO_TOKEN_SCIENCE - if (RADIO_CHANNEL_MEDICAL) - channel_to_add = RADIO_TOKEN_MEDICAL - if (RADIO_CHANNEL_SUPPLY) - channel_to_add = RADIO_TOKEN_SUPPLY - if (RADIO_CHANNEL_SERVICE) - channel_to_add = RADIO_TOKEN_SERVICE - - if (channel_to_add) - parrot_source.available_channels += channel_to_add - - if (radio.translate_binary) - parrot_source.available_channels.Add(MODE_TOKEN_BINARY) - -/datum/strippable_item/parrot_headset/start_unequip(atom/source, mob/user) - . = ..() - if (!.) - return FALSE - - var/mob/living/simple_animal/parrot/parrot_source = source - if (!istype(parrot_source)) - return - - if (!parrot_source.stat) - parrot_source.say("[parrot_source.available_channels.len ? "[pick(parrot_source.available_channels)] " : null]BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") - - return TRUE - -/datum/strippable_item/parrot_headset/finish_unequip(atom/source, mob/user) - var/mob/living/simple_animal/parrot/parrot_source = source - if (!istype(parrot_source)) - return - - parrot_source.ears.forceMove(parrot_source.drop_location()) - parrot_source.ears = null - -/* - * Attack responces - */ -//Humans, monkeys, aliens -/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/user, list/modifiers) - ..() - if(client) - return - if(!stat && user.combat_mode) - - icon_state = icon_living //It is going to be flying regardless of whether it flees or attacks - - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - set_parrot_interest(user) - parrot_state = PARROT_SWOOP //The parrot just got hit, it WILL move, now to pick a direction.. - - if(health > 30) //Let's get in there and squawk it up! - parrot_state |= PARROT_ATTACK - else - parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell! - drop_held_item(0) - if(stat != DEAD && !user.combat_mode) - handle_automated_speech(1) //assured speak/emote - return - -/mob/living/simple_animal/parrot/attack_paw(mob/living/carbon/human/user, list/modifiers) - return attack_hand(user, modifiers) - -//Simple animals -/mob/living/simple_animal/parrot/attack_animal(mob/living/simple_animal/user, list/modifiers) - . = ..() //goodbye immortal parrots - if(client) - return - - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - if(. > 0 && stat == CONSCIOUS) - set_parrot_interest(user) - parrot_state = PARROT_SWOOP | PARROT_ATTACK //Attack other animals regardless - icon_state = icon_living - -//Mobs with objects -/mob/living/simple_animal/parrot/attackby(obj/item/O, mob/living/user, params) - if(!stat && !client && !istype(O, /obj/item/stack/medical) && !istype(O, /obj/item/food/cracker)) - if(O.force) - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - set_parrot_interest(user) - parrot_state = PARROT_SWOOP - if(health > 30) //Let's get in there and squawk it up! - parrot_state |= PARROT_ATTACK - else - parrot_state |= PARROT_FLEE - icon_state = icon_living - drop_held_item(0) - else if(istype(O, /obj/item/food/cracker)) //Poly wants a cracker. - qdel(O) - if(health < maxHealth) - adjustBruteLoss(-10) - speak_chance *= 1.27 // 20 crackers to go from 1% to 100% - speech_shuffle_rate += 10 - to_chat(user, span_notice("[src] eagerly devours the cracker.")) - ..() - return - -//Bullets -/mob/living/simple_animal/parrot/bullet_act(obj/projectile/Proj) - . = ..() - if(!stat && !client) - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - set_parrot_interest(null) - parrot_state = PARROT_WANDER | PARROT_FLEE //Been shot and survived! RUN LIKE HELL! - //parrot_been_shot += 5 - icon_state = icon_living - drop_held_item(0) - -/mob/living/simple_animal/parrot/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) - if(!stat) //Birds can fly, fun fact. No I don't care that space doesn't have air. Space parrots bitch - return TRUE - return ..() -/* - * AI - Not really intelligent, but I'm calling it AI anyway. - */ -/mob/living/simple_animal/parrot/Life(seconds_per_tick = SSMOBS_DT, times_fired) - ..() - - //Sprite update for when a parrot gets pulled - if(pulledby && !stat && parrot_state != PARROT_WANDER) - if(buckled) - buckled.unbuckle_mob(src, TRUE) - buckled = null - icon_state = icon_living - parrot_state = PARROT_WANDER - pixel_x = initial(pixel_x) - pixel_y = initial(pixel_y) - return - - -//-----SPEECH - /* Parrot speech mimickry! - Phrases that the parrot Hear()s get added to speach_buffer. - Every once in a while, the parrot picks one of the lines from the buffer and replaces an element of the 'speech' list. */ -/mob/living/simple_animal/parrot/handle_automated_speech() - ..() - if(speech_buffer.len && prob(speech_shuffle_rate)) //shuffle out a phrase and add in a new one - if(speak.len) - speak.Remove(pick(speak)) - - speak.Add(pick(speech_buffer)) - - -/mob/living/simple_animal/parrot/handle_automated_movement() - if(!isturf(src.loc) || !(mobility_flags & MOBILITY_MOVE) || buckled) - return //If it can't move, dont let it move. (The buckled check probably isn't necessary thanks to canmove) - - if(client && stat == CONSCIOUS && parrot_state != icon_living) - icon_state = icon_living - -//-----SLEEPING - if(parrot_state == PARROT_PERCH) - if(parrot_perch && parrot_perch.loc != src.loc) //Make sure someone hasn't moved our perch on us - if(parrot_perch in view(src)) - parrot_state = PARROT_SWOOP | PARROT_RETURN - icon_state = icon_living - return - else - parrot_state = PARROT_WANDER - icon_state = icon_living - return - - parrot_sleep_dur-- - if(parrot_sleep_dur) //Zzz - return - - else - //This way we only call the stuff below once every [sleep_max] ticks. - parrot_sleep_dur = parrot_sleep_max - - //Cycle through message modes for the headset - if(speak.len) - var/list/newspeak = list() - - if(available_channels.len && src.ears) - for(var/possible_phrase in speak) - - //50/50 chance to not use the radio at all - var/useradio = 0 - if(prob(50)) - useradio = 1 - - if((possible_phrase[1] in GLOB.department_radio_prefixes) && (copytext_char(possible_phrase, 2, 3) in GLOB.department_radio_keys)) - possible_phrase = "[useradio?pick(available_channels):""][copytext_char(possible_phrase, 3)]" //crop out the channel prefix - else - possible_phrase = "[useradio?pick(available_channels):""][possible_phrase]" - - newspeak.Add(possible_phrase) - - else //If we have no headset or channels to use, dont try to use any! - for(var/possible_phrase in speak) - if((possible_phrase[1] in GLOB.department_radio_prefixes) && (copytext_char(possible_phrase, 2, 3) in GLOB.department_radio_keys)) - possible_phrase = copytext_char(possible_phrase, 3) //crop out the channel prefix - newspeak.Add(possible_phrase) - speak = newspeak - - //Search for item to steal - set_parrot_interest(search_for_item()) - if(parrot_interest) - manual_emote("looks in [parrot_interest]'s direction and takes flight.") - parrot_state = PARROT_SWOOP | PARROT_STEAL - icon_state = icon_living - return - -//-----WANDERING - This is basically a 'I dont know what to do yet' state - else if(parrot_state == PARROT_WANDER) - //Stop movement, we'll set it later - SSmove_manager.stop_looping(src) - set_parrot_interest(null) - - //Wander around aimlessly. This will help keep the loops from searches down - //and possibly move the mob into a new are in view of something they can use - if(prob(90)) - step(src, pick(GLOB.cardinals)) - return - - if(!held_item && !parrot_perch) //If we've got nothing to do.. look for something to do. - var/atom/movable/AM = search_for_perch_and_item() //This handles checking through lists so we know it's either a perch or stealable item - if(AM) - if(isitem(AM) || isliving(AM)) //If stealable item - set_parrot_interest(AM) - manual_emote("turns and flies towards [parrot_interest].") - parrot_state = PARROT_SWOOP | PARROT_STEAL - return - else //Else it's a perch - parrot_perch = AM - parrot_state = PARROT_SWOOP | PARROT_RETURN - return - return - - if(parrot_interest && (parrot_interest in view(src))) - parrot_state = PARROT_SWOOP | PARROT_STEAL - return - - if(parrot_perch && (parrot_perch in view(src))) - parrot_state = PARROT_SWOOP | PARROT_RETURN - return - - else //Have an item but no perch? Find one! - parrot_perch = search_for_perch() - if(parrot_perch) - parrot_state = PARROT_SWOOP | PARROT_RETURN - return -//-----STEALING - else if(parrot_state == (PARROT_SWOOP | PARROT_STEAL)) - SSmove_manager.stop_looping(src) - if(!parrot_interest || held_item) - parrot_state = PARROT_SWOOP | PARROT_RETURN - return - - if(!(parrot_interest in view(src))) - parrot_state = PARROT_SWOOP | PARROT_RETURN - return - - if(Adjacent(parrot_interest)) - - if(isliving(parrot_interest)) - steal_from_mob() - - else //This should ensure that we only grab the item we want, and make sure it's not already collected on our perch - if(!parrot_perch || parrot_interest.loc != parrot_perch.loc) - held_item = parrot_interest - parrot_interest.forceMove(src) - visible_message(span_notice("[src] grabs [held_item]!"), span_notice("You grab [held_item]!"), span_hear("You hear the sounds of wings flapping furiously.")) - - set_parrot_interest(null) - parrot_state = PARROT_SWOOP | PARROT_RETURN - return - - SSmove_manager.move_to(src, parrot_interest, 1, parrot_speed) - if(isStuck()) - return - - return - -//-----RETURNING TO PERCH - else if(parrot_state == (PARROT_SWOOP | PARROT_RETURN)) - SSmove_manager.stop_looping(src) - if(!parrot_perch || !isturf(parrot_perch.loc)) //Make sure the perch exists and somehow isn't inside of something else. - parrot_perch = null - parrot_state = PARROT_WANDER - return - - if(Adjacent(parrot_perch)) - forceMove(parrot_perch.loc) - drop_held_item() - parrot_state = PARROT_PERCH - icon_state = icon_sit - return - - SSmove_manager.move_to(src, parrot_perch, 1, parrot_speed) - if(isStuck()) - return - - return - -//-----FLEEING - else if(parrot_state == (PARROT_SWOOP | PARROT_FLEE)) - SSmove_manager.stop_looping(src) - if(!parrot_interest || !isliving(parrot_interest)) //Sanity - parrot_state = PARROT_WANDER - - SSmove_manager.move_away(src, parrot_interest, 1, parrot_speed) - if(isStuck()) - return - - return - -//-----ATTACKING - else if(parrot_state == (PARROT_SWOOP | PARROT_ATTACK)) - - //If we're attacking a nothing, an object, a turf or a ghost for some stupid reason, switch to wander - if(!parrot_interest || !isliving(parrot_interest)) - set_parrot_interest(null) - parrot_state = PARROT_WANDER - return - - var/mob/living/L = parrot_interest - if(melee_damage_upper == 0) - melee_damage_upper = parrot_damage_upper - set_combat_mode(TRUE) - - //If the mob is close enough to interact with - if(Adjacent(parrot_interest)) - - //If the mob we've been chasing/attacking dies or falls into crit, check for loot! - if(L.stat) - set_parrot_interest(null) - if(!held_item) - held_item = steal_from_ground() - if(!held_item) - held_item = steal_from_mob() //Apparently it's possible for dead mobs to hang onto items in certain circumstances. - if(parrot_perch in view(src)) //If we have a home nearby, go to it, otherwise find a new home - parrot_state = PARROT_SWOOP | PARROT_RETURN - else - parrot_state = PARROT_WANDER - return - - attack_verb_continuous = pick("claws at", "chomps") - attack_verb_simple = pick("claw at", "chomp") - L.attack_animal(src)//Time for the hurt to begin! - //Otherwise, fly towards the mob! - else - SSmove_manager.move_to(src, parrot_interest, 1, parrot_speed) - if(isStuck()) - return - - return -//-----STATE MISHAP - else //This should not happen. If it does lets reset everything and try again - SSmove_manager.stop_looping(src) - set_parrot_interest(null) - parrot_perch = null - drop_held_item() - parrot_state = PARROT_WANDER - return - -/* - * Procs - */ - -/mob/living/simple_animal/parrot/proc/set_parrot_interest(atom/movable/shiny) - if(parrot_interest) - UnregisterSignal(parrot_interest, COMSIG_QDELETING) - parrot_interest = shiny - if(parrot_interest) - RegisterSignal(parrot_interest, COMSIG_QDELETING, PROC_REF(shiny_deleted)) - -/mob/living/simple_animal/parrot/proc/shiny_deleted(datum/source) - SIGNAL_HANDLER - set_parrot_interest(null) - -/mob/living/simple_animal/parrot/proc/isStuck() - //Check to see if the parrot is stuck due to things like windows or doors or windowdoors - if(parrot_lastmove) - if(parrot_lastmove == src.loc) - if(parrot_stuck_threshold >= ++parrot_stuck) //If it has been stuck for a while, go back to wander. - parrot_state = PARROT_WANDER - parrot_stuck = 0 - parrot_lastmove = null - return TRUE - else - parrot_lastmove = null - else - parrot_lastmove = src.loc - return FALSE - -/mob/living/simple_animal/parrot/proc/search_for_item() - var/item - for(var/atom/movable/AM in view(src)) - //Skip items we already stole or are wearing or are too big - if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src) - continue - if(isitem(AM)) - var/obj/item/I = AM - if(I.w_class < WEIGHT_CLASS_SMALL) - item = I - else if(iscarbon(AM)) - var/mob/living/carbon/C = AM - for(var/obj/item/I in C.held_items) - if(I.w_class <= WEIGHT_CLASS_SMALL) - item = I - break - if(item) - if(!length(get_path_to(src, item))) // WHY DO WE DISREGARD THE PATH AHHHHHH - item = null - continue - return item - -/mob/living/simple_animal/parrot/proc/search_for_perch() - for(var/obj/O in view(src)) - for(var/path in desired_perches) - if(istype(O, path)) - return O - return null - -//This proc was made to save on doing two 'in view' loops seperatly -/mob/living/simple_animal/parrot/proc/search_for_perch_and_item() - for(var/atom/movable/AM in view(src)) - for(var/perch_path in desired_perches) - if(istype(AM, perch_path)) - return AM - - //Skip items we already stole or are wearing or are too big - if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src) - continue - - if(isitem(AM)) - var/obj/item/I = AM - if(I.w_class <= WEIGHT_CLASS_SMALL) - return I - - if(iscarbon(AM)) - var/mob/living/carbon/C = AM - for(var/obj/item/I in C.held_items) - if(I.w_class <= WEIGHT_CLASS_SMALL) - return C - return null - - -/* - * Verbs - These are actually procs, but can be used as verbs by player-controlled parrots. - */ -/mob/living/simple_animal/parrot/proc/steal_from_ground() - set name = "Steal from ground" - set category = "Parrot" - set desc = "Grabs a nearby item." - - if(stat) - return -1 - - if(held_item) - to_chat(src, span_warning("You are already holding [held_item]!")) - return 1 - - for(var/obj/item/I in view(1,src)) - //Make sure we're not already holding it and it's small enough - if(I.loc != src && I.w_class <= WEIGHT_CLASS_SMALL) - - //If we have a perch and the item is sitting on it, continue - if(!client && parrot_perch && I.loc == parrot_perch.loc) - continue - - held_item = I - I.forceMove(src) - visible_message(span_notice("[src] grabs [held_item]!"), span_notice("You grab [held_item]!"), span_hear("You hear the sounds of wings flapping furiously.")) - return held_item - - to_chat(src, span_warning("There is nothing of interest to take!")) - return 0 - -/mob/living/simple_animal/parrot/proc/steal_from_mob() - set name = "Steal from mob" - set category = "Parrot" - set desc = "Steals an item right out of a person's hand!" - - if(stat) - return -1 - - if(held_item) - to_chat(src, span_warning("You are already holding [held_item]!")) - return 1 - - var/obj/item/stolen_item = null - - for(var/mob/living/carbon/C in view(1,src)) - for(var/obj/item/I in C.held_items) - if(I.w_class <= WEIGHT_CLASS_SMALL) - stolen_item = I - break - - if(stolen_item) - C.transferItemToLoc(stolen_item, src, TRUE) - held_item = stolen_item - visible_message(span_notice("[src] grabs [held_item] out of [C]'s hand!"), span_notice("You snag [held_item] out of [C]'s hand!"), span_hear("You hear the sounds of wings flapping furiously.")) - return held_item - - to_chat(src, span_warning("There is nothing of interest to take!")) - return 0 - -/mob/living/simple_animal/parrot/verb/drop_held_item_player() - set name = "Drop held item" - set category = "Parrot" - set desc = "Drop the item you're holding." - - if(stat) - return - - src.drop_held_item() - - return - -/mob/living/simple_animal/parrot/proc/drop_held_item(drop_gently = 1) - set name = "Drop held item" - set category = "Parrot" - set desc = "Drop the item you're holding." - - if(stat) - return -1 - - if(!held_item) - if(src == usr) //So that other mobs won't make this message appear when they're bludgeoning you. - to_chat(src, span_warning("You have nothing to drop!")) - return 0 - - -//parrots will eat crackers instead of dropping them - if(istype(held_item, /obj/item/food/cracker) && (drop_gently)) - qdel(held_item) - held_item = null - if(health < maxHealth) - adjustBruteLoss(-10) - manual_emote("[src] eagerly downs the cracker.") - return 1 - - - if(!drop_gently) - if(isgrenade(held_item)) - var/obj/item/grenade/G = held_item - G.forceMove(drop_location()) - G.detonate() - to_chat(src, span_danger("You let go of [held_item]!")) - held_item = null - return 1 - - to_chat(src, span_notice("You drop [held_item].")) - - held_item.forceMove(drop_location()) - held_item = null - return 1 - -/mob/living/simple_animal/parrot/proc/perch_player() - set name = "Sit" - set category = "Parrot" - set desc = "Sit on a nice comfy perch." - - if(stat || !client) - return - - if(icon_state == icon_living) - for(var/atom/movable/AM in view(src,1)) - for(var/perch_path in desired_perches) - if(istype(AM, perch_path)) - src.forceMove(AM.loc) - icon_state = icon_sit - parrot_state = PARROT_PERCH - return - to_chat(src, span_warning("There is no perch nearby to sit on!")) - return - -/mob/living/simple_animal/parrot/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) - . = ..() - if(. && !stat && client && parrot_state == PARROT_PERCH) - parrot_state = PARROT_WANDER - icon_state = icon_living - pixel_x = initial(pixel_x) - pixel_y = initial(pixel_y) - -/mob/living/simple_animal/parrot/proc/perch_mob_player() - set name = "Sit on Human's Shoulder" - set category = "Parrot" - set desc = "Sit on a nice comfy human being!" - - if(stat || !client) - return - - if(!buckled) - for(var/mob/living/carbon/human/H in view(src,1)) - if(H.has_buckled_mobs() && H.buckled_mobs.len >= H.max_buckled_mobs) //Already has a parrot, or is being eaten by a slime - continue - perch_on_human(H) - return - to_chat(src, span_warning("There is nobody nearby that you can sit on!")) - else - icon_state = icon_living - parrot_state = PARROT_WANDER - if(buckled) - to_chat(src, span_notice("You are no longer sitting on [buckled]'s shoulder.")) - buckled.unbuckle_mob(src, TRUE) - buckled = null - pixel_x = initial(pixel_x) - pixel_y = initial(pixel_y) - -/* SKYRAT EDIT - MOVED TO modular_skyrat/modules/poly_commands/parrot.dm -/mob/living/simple_animal/parrot/proc/perch_on_human(mob/living/carbon/human/H) - if(!H) - return - forceMove(get_turf(H)) - if(H.buckle_mob(src, TRUE)) - pixel_y = 9 - pixel_x = pick(-8,8) //pick left or right shoulder - icon_state = icon_sit - parrot_state = PARROT_PERCH - to_chat(src, span_notice("You sit on [H]'s shoulder.")) -*/ - -/mob/living/simple_animal/parrot/proc/toggle_mode() - set name = "Toggle mode" - set category = "Parrot" - set desc = "Time to bear those claws!" - - if(stat || !client) - return - - if(combat_mode) - melee_damage_upper = 0 - set_combat_mode(FALSE) - else - melee_damage_upper = parrot_damage_upper - set_combat_mode(TRUE) - to_chat(src, span_notice("You will now [combat_mode ? "Harm" : "Help"] others.")) - return - -/mob/living/simple_animal/parrot/natural - spawn_headset = FALSE -/* - * Sub-types - */ -/mob/living/simple_animal/parrot/poly - name = "Poly" - desc = "Poly the Parrot. An expert on quantum cracker theory." - speak = list("Poly wanna cracker!", ":e Check the crystal, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN MODSUITS?",":e OH GOD ITS ABOUT TO DELAMINATE CALL THE SHUTTLE") - gold_core_spawnable = NO_SPAWN - speak_chance = 3 - - var/memory_saved = FALSE - var/rounds_survived = 0 - var/longest_survival = 0 - var/longest_deathstreak = 0 - - -/mob/living/simple_animal/parrot/poly/Initialize(mapload) - ears = new /obj/item/radio/headset/headset_eng(src) - if(SStts.tts_enabled) - voice = pick(SStts.available_speakers) - if(SStts.pitch_enabled) - if(findtext(voice, "Woman")) - pitch = 12 // up-pitch by one octave - else - pitch = 24 // up-pitch by 2 octaves - else - voice_filter = "rubberband=pitch=1.5" // Use the filter to pitch up if we can't naturally pitch up. - - available_channels = list(":e") - Read_Memory() - if(rounds_survived == longest_survival) - speak += pick("...[longest_survival].", "The things I've seen!", "I have lived many lives!", "What are you before me?") - desc += " Old as sin, and just as loud. Claimed to be [rounds_survived]." - speak_chance = 20 //His hubris has made him more annoying/easier to justify killing - add_atom_colour("#EEEE22", FIXED_COLOUR_PRIORITY) - else if(rounds_survived == longest_deathstreak) - speak += pick("What are you waiting for!", "Violence breeds violence!", "Blood! Blood!", "Strike me down if you dare!") - desc += " The squawks of [-rounds_survived] dead parrots ring out in your ears..." - add_atom_colour("#BB7777", FIXED_COLOUR_PRIORITY) - else if(rounds_survived > 0) - speak += pick("...again?", "No, It was over!", "Let me out!", "It never ends!") - desc += " Over [rounds_survived] shifts without a \"terrible\" \"accident\"!" - else - speak += pick("...alive?", "This isn't parrot heaven!", "I live, I die, I live again!", "The void fades!") - - . = ..() - - // Ensure 1 Poly exists - REGISTER_REQUIRED_MAP_ITEM(1, 1) - -/mob/living/simple_animal/parrot/poly/Life(seconds_per_tick = SSMOBS_DT, times_fired) - if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved) - Write_Memory(FALSE) - memory_saved = TRUE - ..() - -/mob/living/simple_animal/parrot/poly/death(gibbed) - if(HAS_TRAIT(src, TRAIT_DONT_WRITE_MEMORY)) - return ..() // Don't read memory either. - if(!memory_saved) - Write_Memory(TRUE) - if(rounds_survived == longest_survival || rounds_survived == longest_deathstreak || prob(0.666)) - var/mob/living/simple_animal/parrot/poly/ghost/G = new(loc) - if(mind) - mind.transfer_to(G) - else - G.key = key - return ..() - -/mob/living/simple_animal/parrot/poly/proc/Read_Memory() - if(fexists("data/npc_saves/Poly.sav")) //legacy compatability to convert old format to new - var/savefile/S = new /savefile("data/npc_saves/Poly.sav") - S["phrases"] >> speech_buffer - S["roundssurvived"] >> rounds_survived - S["longestsurvival"] >> longest_survival - S["longestdeathstreak"] >> longest_deathstreak - fdel("data/npc_saves/Poly.sav") - else - var/json_file = file("data/npc_saves/Poly.json") - if(!fexists(json_file)) - return - var/list/json = json_decode(file2text(json_file)) - speech_buffer = json["phrases"] - rounds_survived = json["roundssurvived"] - longest_survival = json["longestsurvival"] - longest_deathstreak = json["longestdeathstreak"] - if(!islist(speech_buffer)) - speech_buffer = list() - -/mob/living/simple_animal/parrot/poly/Write_Memory(dead, gibbed) - . = ..() - if(!.) - return - var/json_file = file("data/npc_saves/Poly.json") - var/list/file_data = list() - if(islist(speech_buffer)) - file_data["phrases"] = speech_buffer - if(dead) - file_data["roundssurvived"] = min(rounds_survived - 1, 0) - file_data["longestsurvival"] = longest_survival - if(rounds_survived - 1 < longest_deathstreak) - file_data["longestdeathstreak"] = rounds_survived - 1 - else - file_data["longestdeathstreak"] = longest_deathstreak - else - file_data["roundssurvived"] = max(rounds_survived, 0) + 1 - if(rounds_survived + 1 > longest_survival) - file_data["longestsurvival"] = rounds_survived + 1 - else - file_data["longestsurvival"] = longest_survival - file_data["longestdeathstreak"] = longest_deathstreak - fdel(json_file) - WRITE_FILE(json_file, json_encode(file_data)) - -/mob/living/simple_animal/parrot/poly/ghost - name = "The Ghost of Poly" - desc = "Doomed to squawk the Earth." - color = "#FFFFFF77" - speak_chance = 20 - status_flags = GODMODE - sentience_type = SENTIENCE_BOSS //This is so players can't mindswap into ghost poly to become a literal god - incorporeal_move = INCORPOREAL_MOVE_BASIC - butcher_results = list(/obj/item/ectoplasm = 1) - -/mob/living/simple_animal/parrot/poly/ghost/Initialize(mapload) - memory_saved = TRUE //At this point nothing is saved - . = ..() - -/mob/living/simple_animal/parrot/poly/ghost/handle_automated_speech() - if(ismob(loc)) - return - ..() - -/mob/living/simple_animal/parrot/poly/ghost/handle_automated_movement() - if(isliving(parrot_interest)) - if(!ishuman(parrot_interest)) - set_parrot_interest(null) - else if(parrot_state == (PARROT_SWOOP | PARROT_ATTACK) && Adjacent(parrot_interest)) - SSmove_manager.move_to(src, parrot_interest, 0, parrot_speed) - Possess(parrot_interest) - ..() - -/mob/living/simple_animal/parrot/poly/ghost/proc/Possess(mob/living/carbon/human/H) - if(!ishuman(H)) - return - var/datum/disease/parrot_possession/P = new - P.parrot = src - forceMove(H) - H.ForceContractDisease(P, FALSE) - set_parrot_interest(null) - H.visible_message(span_danger("[src] dive bombs into [H]'s chest and vanishes!"), span_userdanger("[src] dive bombs into your chest, vanishing! This can't be good!")) - -#undef PARROT_PERCH -#undef PARROT_SWOOP -#undef PARROT_WANDER -#undef PARROT_STEAL -#undef PARROT_ATTACK -#undef PARROT_RETURN -#undef PARROT_FLEE diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 790f9312ea1..6136f8c8189 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -398,7 +398,7 @@ return TRUE if(ispath(MP, /mob/living/basic/bear)) return TRUE - if(ispath(MP, /mob/living/simple_animal/parrot)) + if(ispath(MP, /mob/living/basic/parrot)) return TRUE //Parrots are no longer unfinished! -Nodrak //Not in here? Must be untested! diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index 3acfe8f5294..17c425c4e2f 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -641,10 +641,10 @@ /mob/living/basic/crab, /mob/living/basic/lizard, /mob/living/basic/mouse, + /mob/living/basic/parrot, /mob/living/basic/pet/dog/corgi, /mob/living/basic/pet/dog/pug, /mob/living/basic/pet/fox, - /mob/living/simple_animal/parrot/natural, /mob/living/simple_animal/pet/cat, ) for(var/counter in 1 to rand(1, 25)) diff --git a/code/modules/unit_tests/required_map_items.dm b/code/modules/unit_tests/required_map_items.dm index 39930afd822..5cbef645391 100644 --- a/code/modules/unit_tests/required_map_items.dm +++ b/code/modules/unit_tests/required_map_items.dm @@ -15,10 +15,11 @@ /datum/unit_test/required_map_items/proc/setup_expected_types() expected_types += subtypesof(/obj/item/stamp/head) expected_types += subtypesof(/obj/machinery/computer/department_orders) - expected_types += /obj/machinery/computer/communications - expected_types += /mob/living/carbon/human/species/monkey/punpun + + expected_types += /mob/living/basic/parrot/poly expected_types += /mob/living/basic/pet/dog/corgi/ian - expected_types += /mob/living/simple_animal/parrot/poly + expected_types += /mob/living/carbon/human/species/monkey/punpun + expected_types += /obj/machinery/computer/communications expected_types += /obj/machinery/drone_dispenser /datum/unit_test/required_map_items/Run() diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index dcba0cd69db..1a8b4561140 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -92,10 +92,6 @@ /mob/living/simple_animal/hostile/retaliate/goose/vomit, /mob/living/simple_animal/hostile/vatbeast, /mob/living/simple_animal/hostile/zombie, - /mob/living/simple_animal/parrot, - /mob/living/simple_animal/parrot/natural, - /mob/living/simple_animal/parrot/poly, - /mob/living/simple_animal/parrot/poly/ghost, /mob/living/simple_animal/pet, /mob/living/simple_animal/pet/cat, /mob/living/simple_animal/pet/cat/_proc, diff --git a/modular_skyrat/master_files/code/modules/antagonists/traitor/objectives/kill_pet.dm b/modular_skyrat/master_files/code/modules/antagonists/traitor/objectives/kill_pet.dm index b3486f40ba7..c6bcd6ed585 100644 --- a/modular_skyrat/master_files/code/modules/antagonists/traitor/objectives/kill_pet.dm +++ b/modular_skyrat/master_files/code/modules/antagonists/traitor/objectives/kill_pet.dm @@ -7,7 +7,7 @@ ), JOB_CAPTAIN = /mob/living/basic/pet/fox/renault, JOB_CHIEF_MEDICAL_OFFICER = /mob/living/simple_animal/pet/cat/runtime, - JOB_CHIEF_ENGINEER = /mob/living/simple_animal/parrot/poly, + JOB_CHIEF_ENGINEER = /mob/living/basic/parrot/poly, JOB_QUARTERMASTER = list( /mob/living/basic/sloth/citrus, /mob/living/basic/sloth/paperwork, diff --git a/modular_skyrat/modules/poly_commands/parrot.dm b/modular_skyrat/modules/poly_commands/parrot.dm index f522edf7da1..3fe164cc6ef 100644 --- a/modular_skyrat/modules/poly_commands/parrot.dm +++ b/modular_skyrat/modules/poly_commands/parrot.dm @@ -1,47 +1,19 @@ -#define PARROT_PERCH (1<<0) //Sitting/sleeping, not moving -#define PARROT_SWOOP (1<<1) //Moving towards or away from a target -#define PARROT_WANDER (1<<2) //Moving without a specific target in mind - /* * Parrot commands: Made modular */ -/mob/living/simple_animal/parrot +/mob/living/basic/parrot /// Whether the parrot is on a human's shoulder or not - var/buckled_to_human = FALSE - -/mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range) - . = ..() - if(check_command(raw_message, speaker)) - return - if(speaker != src && prob(50)) //Dont imitate ourselves - if(!radio_freq || prob(10)) - if(speech_buffer.len >= 500) - speech_buffer -= pick(speech_buffer) - speech_buffer |= html_decode(raw_message) - if(speaker == src && !client) //If a parrot squawks in the woods and no one is around to hear it, does it make a sound? This code says yes! - return raw_message - -/mob/living/simple_animal/parrot/proc/perch_on_human(mob/living/carbon/human/human_target) - if(!human_target) - return - forceMove(get_turf(human_target)) - if(human_target.buckle_mob(src, TRUE)) - pixel_y = 9 - pixel_x = pick(-8,8) //pick left or right shoulder - icon_state = icon_sit - parrot_state = PARROT_PERCH - buckled_to_human = TRUE - to_chat(src, span_notice("You sit on [human_target]'s shoulder.")) + var/buckled_to_human /* * Parrot commands: new code */ -/mob/living/simple_animal/parrot/proc/check_command() +/mob/living/basic/parrot/proc/check_command(message, speaker) return FALSE // Simply return false for non-Poly parrots -/mob/living/simple_animal/parrot/poly/check_command(message, speaker) +/mob/living/basic/parrot/poly/check_command(message, speaker) var/mob/living/carbon/human/human_target = speaker if(!istype(human_target)) return FALSE @@ -58,8 +30,13 @@ else return FALSE -/mob/living/simple_animal/parrot/poly/proc/command_perch(mob/living/carbon/human/human_target) - if (!buckled) +/mob/living/basic/parrot/toggle_perched(perched) + . = ..() + if(!perched) + buckled_to_human = FALSE + +/mob/living/basic/parrot/poly/proc/command_perch(mob/living/carbon/human/human_target) + if(!buckled) buckled_to_human = FALSE if(LAZYLEN(human_target.buckled_mobs) >= human_target.max_buckled_mobs) return @@ -70,26 +47,18 @@ manual_emote("tilts their head at [human_target], before bawking loudly and staying put.") return manual_emote("obediently hops up onto [human_target]'s shoulder, spreading their wings for a moment before settling down.") - perch_on_human(human_target) + if(start_perching(human_target)) + buckled_to_human = TRUE -/mob/living/simple_animal/parrot/poly/proc/command_hop_off(mob/living/carbon/human/human_target) - if (!buckled) +/mob/living/basic/parrot/poly/proc/command_hop_off(mob/living/carbon/human/human_target) + if(!buckled) buckled_to_human = FALSE if(!buckled_to_human || !buckled) manual_emote("gives [human_target] a confused look, squawking softly.") return - icon_state = icon_living - parrot_state = PARROT_WANDER if(buckled) to_chat(src, span_notice("You are no longer sitting on [human_target].")) buckled.unbuckle_mob(src, TRUE) manual_emote("squawks and hops off of [human_target], flying away.") - buckled = null - buckled_to_human = FALSE - pixel_x = initial(pixel_x) - pixel_y = initial(pixel_y) -#undef PARROT_PERCH -#undef PARROT_SWOOP -#undef PARROT_WANDER diff --git a/tgstation.dme b/tgstation.dme index 985c341219b..221b05cffe8 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -946,6 +946,7 @@ #include "code\datums\ai\basic_mobs\basic_ai_behaviors\targeting.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\tipped_reaction.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\travel_towards.dm" +#include "code\datums\ai\basic_mobs\basic_ai_behaviors\unbuckle_mob.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\ventcrawling.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\wounded_targeting.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\write_on_paper.dm" @@ -1171,6 +1172,7 @@ #include "code\datums\components\life_link.dm" #include "code\datums\components\light_eater.dm" #include "code\datums\components\ling_decoy_brain.dm" +#include "code\datums\components\listen_and_repeat.dm" #include "code\datums\components\lock_on_cursor.dm" #include "code\datums\components\lockable_storage.dm" #include "code\datums\components\magnet.dm" @@ -4686,6 +4688,15 @@ #include "code\modules\mob\living\basic\pets\dog\corgi.dm" #include "code\modules\mob\living\basic\pets\dog\dog_subtypes.dm" #include "code\modules\mob\living\basic\pets\dog\strippable_items.dm" +#include "code\modules\mob\living\basic\pets\parrot\_parrot.dm" +#include "code\modules\mob\living\basic\pets\parrot\parrot_items.dm" +#include "code\modules\mob\living\basic\pets\parrot\parrot_subtypes.dm" +#include "code\modules\mob\living\basic\pets\parrot\poly.dm" +#include "code\modules\mob\living\basic\pets\parrot\parrot_ai\_parrot_controller.dm" +#include "code\modules\mob\living\basic\pets\parrot\parrot_ai\ghost_parrot_controller.dm" +#include "code\modules\mob\living\basic\pets\parrot\parrot_ai\parrot_hoarding.dm" +#include "code\modules\mob\living\basic\pets\parrot\parrot_ai\parrot_perching.dm" +#include "code\modules\mob\living\basic\pets\parrot\parrot_ai\parroting_action.dm" #include "code\modules\mob\living\basic\ruin_defender\flesh.dm" #include "code\modules\mob\living\basic\ruin_defender\living_floor.dm" #include "code\modules\mob\living\basic\ruin_defender\skeleton.dm" @@ -4935,7 +4946,6 @@ #include "code\modules\mob\living\silicon\robot\robot_say.dm" #include "code\modules\mob\living\simple_animal\animal_defense.dm" #include "code\modules\mob\living\simple_animal\damage_procs.dm" -#include "code\modules\mob\living\simple_animal\parrot.dm" #include "code\modules\mob\living\simple_animal\simple_animal.dm" #include "code\modules\mob\living\simple_animal\bot\bot.dm" #include "code\modules\mob\living\simple_animal\bot\bot_announcement.dm" diff --git a/tools/UpdatePaths/Scripts/79762_simple_to_basic_parrots.txt b/tools/UpdatePaths/Scripts/79762_simple_to_basic_parrots.txt new file mode 100644 index 00000000000..2f2e9c19a0f --- /dev/null +++ b/tools/UpdatePaths/Scripts/79762_simple_to_basic_parrots.txt @@ -0,0 +1,5 @@ +/mob/living/simple_animal/parrot : /mob/living/basic/parrot{@OLD} +/mob/living/simple_animal/parrot/natural : /mob/living/basic/parrot{@OLD} +/mob/living/simple_animal/parrot/poly : /mob/living/basic/parrot/poly{@OLD} + + From 6541b0d8a42c82ac250c4f2239d4f6a10108461f Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Wed, 22 Nov 2023 01:41:41 +0300 Subject: [PATCH 26/55] Automatic changelog for PR #745 [ci skip] --- html/changelogs/AutoChangeLog-pr-745.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-745.yml diff --git a/html/changelogs/AutoChangeLog-pr-745.yml b/html/changelogs/AutoChangeLog-pr-745.yml new file mode 100644 index 00000000000..d7977979f16 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-745.yml @@ -0,0 +1,5 @@ +author: "san7890 and Ben10Omintrix/Kobsamobsa" +delete-after: True +changes: + - refactor: "Parrots (including Poly) have undergone a massive refactor, please report any bugs or unexpected behavior that you may encounter." + - qol: "Left-clicking a parrot with a cracker will tame it, right-clicking a parrot with a cracker will now feed it the cracker." \ No newline at end of file From 266cdfcc875047a6a2b523f891b314b7c6422147 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:40:19 +0300 Subject: [PATCH 27/55] [MIRROR] Poly speech/memory fix. [MDB IGNORE] (#750) * Poly speech/memory fix. (#79851) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: shwb1 Co-authored-by: san7890 Co-authored-by: Iajret --- code/modules/mob/living/basic/pets/parrot/poly.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/basic/pets/parrot/poly.dm b/code/modules/mob/living/basic/pets/parrot/poly.dm index ecd6e054609..42c3061bdd6 100644 --- a/code/modules/mob/living/basic/pets/parrot/poly.dm +++ b/code/modules/mob/living/basic/pets/parrot/poly.dm @@ -129,7 +129,7 @@ else var/json_file = file("data/npc_saves/Poly.json") if(!fexists(json_file)) - return + return list() var/list/json = json_decode(file2text(json_file)) returnable_list = json["phrases"] rounds_survived = json["roundssurvived"] From a029d30732e42031a720130733a88e179054c137 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:43:36 +0300 Subject: [PATCH 28/55] [MIRROR] Fixes the recycler's missing dir variable (#753) * [MIRROR] Fixes the recycler's missing dir variable [MDB IGNORE] (#25153) * Update MetaStation.dmm --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Fazzie <84548101+EuSouAFazer@users.noreply.github.com> Co-authored-by: Iajret --- _maps/map_files/MetaStation/MetaStation.dmm | 516 ++++++++++---------- 1 file changed, 259 insertions(+), 257 deletions(-) diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index bd142399404..cf996d4b8e1 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -152,6 +152,14 @@ "adp" = ( /turf/closed/wall, /area/station/hallway/primary/starboard) +"adz" = ( +/obj/structure/closet/secure_closet/engineering_chief, +/obj/machinery/airalarm/directional/east, +/obj/structure/cable, +/obj/item/storage/briefcase/secure, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/command/heads_quarters/ce) "adD" = ( /obj/effect/spawner/random/structure/closet_maintenance, /obj/effect/spawner/random/maintenance, @@ -3102,12 +3110,6 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/fore/lesser) -"bdV" = ( -/obj/structure/filingcabinet/chestdrawer, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/basic/parrot/poly, -/turf/open/floor/iron/dark, -/area/station/command/heads_quarters/ce) "beo" = ( /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 4 @@ -3312,6 +3314,17 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/iron/dark, /area/station/security/execution/education) +"bhv" = ( +/obj/effect/landmark/blobstart, +/obj/machinery/camera/directional/north{ + c_tag = "Security - Evidence Storage" + }, +/obj/structure/secure_safe/directional/north{ + name = "evidence safe" + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/security/evidence) "bhM" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -7406,6 +7419,14 @@ /obj/item/hand_labeler, /turf/open/floor/wood, /area/station/command/heads_quarters/hop) +"cKW" = ( +/obj/structure/secure_safe/directional/north, +/obj/machinery/camera/directional/north{ + c_tag = "Chief Engineer's Office" + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/command/heads_quarters/ce) "cLa" = ( /obj/structure/weightmachine, /obj/effect/turf_decal/tile/dark_red/half/contrasted, @@ -7466,19 +7487,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/port) -"cMc" = ( -/obj/machinery/recharger{ - pixel_x = 2; - pixel_y = 3 - }, -/obj/structure/secure_safe/directional/east, -/obj/structure/table/wood, -/obj/item/flashlight/lamp/green{ - pixel_x = -12; - pixel_y = 5 - }, -/turf/open/floor/wood, -/area/station/command/heads_quarters/hop) "cMd" = ( /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible, /turf/open/floor/iron, @@ -7683,6 +7691,22 @@ /obj/structure/window/spawner/directional/south, /turf/open/floor/iron, /area/station/engineering/atmos) +"cQz" = ( +/obj/structure/table/glass, +/obj/machinery/light_switch/directional/north, +/obj/item/storage/briefcase/secure{ + pixel_x = 3; + pixel_y = 5 + }, +/obj/item/storage/medkit/regular{ + pixel_x = -3; + pixel_y = -3 + }, +/obj/effect/turf_decal/tile/blue/anticorner/contrasted{ + dir = 1 + }, +/turf/open/floor/iron/white, +/area/station/command/heads_quarters/cmo) "cQQ" = ( /obj/machinery/meter, /obj/machinery/atmospherics/pipe/smart/manifold/purple/visible{ @@ -8395,20 +8419,6 @@ /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"ddy" = ( -/obj/structure/rack, -/obj/item/storage/briefcase{ - pixel_x = -3; - pixel_y = 2 - }, -/obj/item/storage/briefcase/secure{ - pixel_x = 2; - pixel_y = -2 - }, -/obj/item/taperecorder, -/obj/item/clothing/glasses/sunglasses, -/turf/open/floor/wood, -/area/station/service/lawoffice) "ddK" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -10749,6 +10759,12 @@ /obj/effect/mapping_helpers/turn_off_lights_with_lightswitch, /turf/open/floor/iron, /area/station/cargo/warehouse) +"dXs" = ( +/obj/structure/secure_safe/directional/north{ + name = "armory safe A" + }, +/turf/open/floor/iron/dark, +/area/station/ai_monitored/security/armory) "dXA" = ( /obj/structure/closet/crate/trashcart, /obj/effect/spawner/random/contraband/prison, @@ -11180,6 +11196,19 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) +"eey" = ( +/obj/machinery/firealarm/directional/west, +/obj/structure/rack, +/obj/item/storage/briefcase{ + pixel_x = -3; + pixel_y = 2 + }, +/obj/item/storage/briefcase/secure{ + pixel_x = 2; + pixel_y = -2 + }, +/turf/open/floor/iron/grimy, +/area/station/security/detectives_office) "eeT" = ( /obj/machinery/vending/hydroseeds{ slogan_delay = 700 @@ -11292,6 +11321,14 @@ /obj/machinery/door/firedoor, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"egp" = ( +/obj/item/storage/briefcase/secure, +/obj/structure/table/wood, +/obj/item/folder/blue, +/obj/item/storage/briefcase/secure, +/obj/item/assembly/flash/handheld, +/turf/open/floor/wood, +/area/station/command/heads_quarters/hop) "egs" = ( /obj/effect/spawner/random/maintenance/two, /obj/structure/rack, @@ -12879,6 +12916,15 @@ "eKP" = ( /turf/closed/wall/r_wall, /area/station/science/ordnance/freezerchamber) +"eLa" = ( +/obj/structure/table/wood, +/obj/item/storage/briefcase/secure{ + desc = "A large briefcase with a digital locking system, and the Nanotrasen logo emblazoned on the sides."; + name = "\improper Nanotrasen-brand secure briefcase exhibit"; + pixel_y = 2 + }, +/turf/open/floor/carpet, +/area/station/command/corporate_showroom) "eLb" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -14076,14 +14122,6 @@ /obj/effect/spawner/random/maintenance/three, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"fhz" = ( -/obj/structure/secure_safe/directional/north, -/obj/machinery/camera/directional/north{ - c_tag = "Chief Engineer's Office" - }, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/command/heads_quarters/ce) "fhA" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -14192,19 +14230,6 @@ }, /turf/open/floor/iron/white/smooth_large, /area/station/medical/medbay/central) -"fiI" = ( -/obj/machinery/firealarm/directional/west, -/obj/structure/rack, -/obj/item/storage/briefcase{ - pixel_x = -3; - pixel_y = 2 - }, -/obj/item/storage/briefcase/secure{ - pixel_x = 2; - pixel_y = -2 - }, -/turf/open/floor/iron/grimy, -/area/station/security/detectives_office) "fiK" = ( /obj/structure/table/glass, /obj/item/clothing/gloves/latex, @@ -15032,15 +15057,6 @@ }, /turf/open/floor/iron, /area/station/engineering/break_room) -"fze" = ( -/obj/structure/secure_safe/hos{ - pixel_x = 36; - pixel_y = 28 - }, -/obj/machinery/status_display/evac/directional/north, -/obj/structure/cable, -/turf/open/floor/carpet, -/area/station/command/heads_quarters/hos) "fzi" = ( /obj/effect/turf_decal/trimline/neutral/filled/corner{ dir = 4 @@ -16533,6 +16549,15 @@ /obj/machinery/power/apc/auto_name/directional/east, /turf/open/floor/iron/white, /area/station/security/prison/visit) +"gem" = ( +/obj/structure/table, +/obj/item/storage/briefcase/secure{ + pixel_x = -7; + pixel_y = 12 + }, +/obj/effect/spawner/random/engineering/flashlight, +/turf/open/floor/iron/dark, +/area/station/security/office) "gen" = ( /obj/structure/table/glass, /obj/item/folder/blue{ @@ -16579,17 +16604,6 @@ }, /turf/open/floor/iron, /area/station/service/hydroponics/garden) -"gfc" = ( -/obj/structure/table/wood, -/obj/machinery/light_switch/directional/west, -/obj/item/storage/briefcase/secure{ - pixel_x = -2; - pixel_y = 4 - }, -/obj/item/storage/lockbox/medal, -/obj/structure/window/reinforced/spawner/directional/south, -/turf/open/floor/wood, -/area/station/command/heads_quarters/captain/private) "gfe" = ( /obj/effect/decal/cleanable/cobweb/cobweb2, /obj/structure/table, @@ -17449,6 +17463,17 @@ }, /turf/open/floor/iron, /area/station/service/janitor) +"guO" = ( +/obj/structure/table/wood, +/obj/machinery/light_switch/directional/west, +/obj/item/storage/briefcase/secure{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/storage/lockbox/medal, +/obj/structure/window/reinforced/spawner/directional/south, +/turf/open/floor/wood, +/area/station/command/heads_quarters/captain/private) "guR" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -17729,6 +17754,19 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/maintenance/aft/greater) +"gAk" = ( +/obj/machinery/recharger{ + pixel_x = 2; + pixel_y = 3 + }, +/obj/structure/secure_safe/directional/east, +/obj/structure/table/wood, +/obj/item/flashlight/lamp/green{ + pixel_x = -12; + pixel_y = 5 + }, +/turf/open/floor/wood, +/area/station/command/heads_quarters/hop) "gAt" = ( /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plating, @@ -19649,6 +19687,20 @@ }, /turf/open/floor/iron, /area/station/cargo/sorting) +"hlj" = ( +/obj/structure/table/wood, +/obj/structure/secure_safe/directional/east, +/obj/machinery/computer/security/wooden_tv{ + pixel_x = 3; + pixel_y = 2 + }, +/obj/machinery/button/door/directional/north{ + id = "detective_shutters"; + name = "detective's office shutters control"; + req_access = list("detective") + }, +/turf/open/floor/carpet, +/area/station/security/detectives_office) "hlq" = ( /obj/structure/chair{ dir = 4 @@ -23602,13 +23654,6 @@ /obj/structure/reagent_dispensers/plumbed, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"iEs" = ( -/obj/structure/secure_safe/directional/south, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 1 - }, -/turf/open/floor/plating, -/area/station/commons/vacant_room/commissary) "iEv" = ( /obj/structure/closet, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -26067,17 +26112,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/engineering/storage/tech) -"jtw" = ( -/obj/machinery/light/directional/south, -/obj/machinery/firealarm/directional/south, -/obj/structure/rack, -/obj/item/storage/briefcase/secure, -/obj/item/clothing/mask/cigarette/cigar, -/obj/effect/turf_decal/tile/blue/half/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/dark, -/area/station/command/bridge) "jtA" = ( /obj/structure/table/glass, /obj/effect/turf_decal/siding/white{ @@ -36844,25 +36878,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/aft) -"nka" = ( -/obj/structure/safe, -/obj/item/storage/briefcase/secure/riches, -/obj/item/storage/backpack/duffelbag/syndie/hitman, -/obj/item/card/id/advanced/silver/reaper, -/obj/item/lazarus_injector, -/obj/item/gun/energy/disabler, -/obj/item/gun/ballistic/revolver/russian, -/obj/item/ammo_box/a357, -/obj/item/clothing/neck/stethoscope, -/obj/item/book{ - desc = "An undeniably handy book."; - icon_state = "bookknock"; - name = "\improper A Simpleton's Guide to Safe-cracking with Stethoscopes" - }, -/obj/effect/turf_decal/bot_white/left, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/ai_monitored/command/nuke_storage) "nkj" = ( /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ dir = 10 @@ -36925,14 +36940,6 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/science/research) -"nlV" = ( -/obj/item/storage/briefcase/secure, -/obj/structure/table/wood, -/obj/item/folder/blue, -/obj/item/storage/briefcase/secure, -/obj/item/assembly/flash/handheld, -/turf/open/floor/wood, -/area/station/command/heads_quarters/hop) "nmf" = ( /obj/machinery/smartfridge, /obj/machinery/door/poddoor/shutters/preopen{ @@ -37349,12 +37356,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/wood, /area/station/service/theater) -"nsx" = ( -/obj/machinery/light_switch/directional/east, -/obj/structure/dresser, -/obj/structure/secure_safe/directional/north, -/turf/open/floor/wood, -/area/station/command/heads_quarters/captain/private) "nsA" = ( /turf/closed/wall, /area/station/science/ordnance/testlab) @@ -37526,6 +37527,13 @@ }, /turf/open/floor/iron/white, /area/station/medical/office) +"nuB" = ( +/obj/structure/secure_safe/directional/south, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 1 + }, +/turf/open/floor/plating, +/area/station/commons/vacant_room/commissary) "nuI" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -38292,14 +38300,6 @@ /obj/structure/easel, /turf/open/floor/plating, /area/station/maintenance/disposal) -"nIx" = ( -/obj/structure/closet/secure_closet/engineering_chief, -/obj/machinery/airalarm/directional/east, -/obj/structure/cable, -/obj/item/storage/briefcase/secure, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/command/heads_quarters/ce) "nIP" = ( /obj/structure/table/glass, /obj/item/paper_bin{ @@ -39590,6 +39590,20 @@ }, /turf/open/floor/iron/white, /area/station/command/heads_quarters/captain/private) +"oha" = ( +/obj/structure/rack, +/obj/item/storage/briefcase{ + pixel_x = -3; + pixel_y = 2 + }, +/obj/item/storage/briefcase/secure{ + pixel_x = 2; + pixel_y = -2 + }, +/obj/item/taperecorder, +/obj/item/clothing/glasses/sunglasses, +/turf/open/floor/wood, +/area/station/service/lawoffice) "ohm" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -40100,6 +40114,15 @@ /obj/structure/window/reinforced/spawner/directional/east, /turf/open/space, /area/space/nearstation) +"osH" = ( +/obj/structure/secure_safe/hos{ + pixel_x = 36; + pixel_y = 28 + }, +/obj/machinery/status_display/evac/directional/north, +/obj/structure/cable, +/turf/open/floor/carpet, +/area/station/command/heads_quarters/hos) "ota" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -41723,6 +41746,25 @@ /obj/item/stack/cable_coil, /turf/open/floor/plating, /area/station/maintenance/solars/starboard/aft) +"oXK" = ( +/obj/structure/safe, +/obj/item/storage/briefcase/secure/riches, +/obj/item/storage/backpack/duffelbag/syndie/hitman, +/obj/item/card/id/advanced/silver/reaper, +/obj/item/lazarus_injector, +/obj/item/gun/energy/disabler, +/obj/item/gun/ballistic/revolver/russian, +/obj/item/ammo_box/a357, +/obj/item/clothing/neck/stethoscope, +/obj/item/book{ + desc = "An undeniably handy book."; + icon_state = "bookknock"; + name = "\improper A Simpleton's Guide to Safe-cracking with Stethoscopes" + }, +/obj/effect/turf_decal/bot_white/left, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/ai_monitored/command/nuke_storage) "oXL" = ( /obj/machinery/disposal/bin, /obj/structure/cable, @@ -41810,17 +41852,6 @@ }, /turf/open/floor/engine/cult, /area/station/service/library) -"oZn" = ( -/obj/effect/landmark/blobstart, -/obj/machinery/camera/directional/north{ - c_tag = "Security - Evidence Storage" - }, -/obj/structure/secure_safe/directional/north{ - name = "evidence safe" - }, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/security/evidence) "oZs" = ( /obj/structure/bed/medical/emergency{ dir = 4 @@ -42351,20 +42382,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/hallway/primary/central) -"pjK" = ( -/obj/structure/table/wood, -/obj/structure/secure_safe/directional/east, -/obj/machinery/computer/security/wooden_tv{ - pixel_x = 3; - pixel_y = 2 - }, -/obj/machinery/button/door/directional/north{ - id = "detective_shutters"; - name = "detective's office shutters control"; - req_access = list("detective") - }, -/turf/open/floor/carpet, -/area/station/security/detectives_office) "pjS" = ( /obj/machinery/vending/cigarette, /obj/structure/extinguisher_cabinet/directional/east, @@ -47076,15 +47093,6 @@ }, /turf/open/floor/iron, /area/station/commons/locker) -"qRs" = ( -/obj/structure/table/wood, -/obj/item/storage/briefcase/secure{ - desc = "A large briefcase with a digital locking system, and the Nanotrasen logo emblazoned on the sides."; - name = "\improper Nanotrasen-brand secure briefcase exhibit"; - pixel_y = 2 - }, -/turf/open/floor/carpet, -/area/station/command/corporate_showroom) "qRz" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible, /obj/effect/spawner/random/trash/janitor_supplies, @@ -48856,18 +48864,6 @@ /obj/structure/cable, /turf/open/floor/plating/airless, /area/station/solars/starboard/aft) -"rxN" = ( -/obj/item/folder/white{ - pixel_x = 4; - pixel_y = -3 - }, -/obj/structure/table/glass, -/obj/structure/secure_safe/caps_spare/directional/west, -/obj/effect/turf_decal/tile/green/half/contrasted{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/station/command/bridge) "rxP" = ( /obj/machinery/computer/security, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -50570,6 +50566,12 @@ /obj/machinery/airalarm/directional/south, /turf/open/floor/iron/white, /area/station/medical/abandoned) +"sby" = ( +/obj/structure/filingcabinet/chestdrawer, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/mob/living/basic/parrot/poly, +/turf/open/floor/iron/dark, +/area/station/command/heads_quarters/ce) "sbG" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/structure/window/reinforced/spawner/directional/east, @@ -55850,6 +55852,17 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/station/security/execution/education) +"tVk" = ( +/obj/machinery/light/directional/south, +/obj/machinery/firealarm/directional/south, +/obj/structure/rack, +/obj/item/storage/briefcase/secure, +/obj/item/clothing/mask/cigarette/cigar, +/obj/effect/turf_decal/tile/blue/half/contrasted{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/station/command/bridge) "tVm" = ( /obj/structure/closet/secure_closet/brig, /obj/effect/turf_decal/trimline/red/filled/line{ @@ -56865,22 +56878,6 @@ }, /turf/open/floor/engine, /area/station/engineering/supermatter/room) -"uno" = ( -/obj/structure/table/glass, -/obj/machinery/light_switch/directional/north, -/obj/item/storage/briefcase/secure{ - pixel_x = 3; - pixel_y = 5 - }, -/obj/item/storage/medkit/regular{ - pixel_x = -3; - pixel_y = -3 - }, -/obj/effect/turf_decal/tile/blue/anticorner/contrasted{ - dir = 1 - }, -/turf/open/floor/iron/white, -/area/station/command/heads_quarters/cmo) "unt" = ( /obj/item/radio/intercom/directional/south, /obj/effect/turf_decal/tile/yellow/anticorner/contrasted, @@ -57226,6 +57223,18 @@ }, /turf/open/floor/iron, /area/station/commons/locker) +"usQ" = ( +/obj/item/folder/white{ + pixel_x = 4; + pixel_y = -3 + }, +/obj/structure/table/glass, +/obj/structure/secure_safe/caps_spare/directional/west, +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/command/bridge) "uta" = ( /obj/structure/rack, /obj/item/book/manual/wiki/security_space_law{ @@ -57837,14 +57846,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/central) -"uEC" = ( -/obj/machinery/conveyor{ - dir = 4; - id = "garbage" - }, -/obj/machinery/recycler, -/turf/open/floor/plating, -/area/station/maintenance/disposal) "uEO" = ( /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plating, @@ -65311,12 +65312,6 @@ /obj/effect/mapping_helpers/airlock/access/all/medical/cmo, /turf/open/floor/plating, /area/station/maintenance/department/medical/central) -"xgh" = ( -/obj/structure/secure_safe/directional/north{ - name = "armory safe A" - }, -/turf/open/floor/iron/dark, -/area/station/ai_monitored/security/armory) "xgi" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/bot, @@ -66082,6 +66077,23 @@ /obj/effect/spawner/random/structure/grille, /turf/open/floor/plating, /area/station/maintenance/port) +"xuy" = ( +/obj/item/radio/intercom/directional/south, +/obj/effect/turf_decal/tile/bar, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/table, +/obj/machinery/reagentgrinder{ + pixel_x = 6; + pixel_y = 6 + }, +/obj/item/reagent_containers/condiment/enzyme{ + layer = 5; + pixel_x = -6 + }, +/turf/open/floor/iron/cafeteria, +/area/station/service/kitchen) "xuA" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 4 @@ -66116,6 +66128,16 @@ }, /turf/open/floor/iron/solarpanel/airless, /area/station/solars/port/fore) +"xuP" = ( +/obj/machinery/conveyor{ + dir = 4; + id = "garbage" + }, +/obj/machinery/recycler{ + dir = 8 + }, +/turf/open/floor/plating, +/area/station/maintenance/disposal) "xuS" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -67419,15 +67441,6 @@ "xTw" = ( /turf/closed/wall/r_wall, /area/station/medical/medbay/central) -"xTH" = ( -/obj/structure/table, -/obj/item/storage/briefcase/secure{ - pixel_x = -7; - pixel_y = 12 - }, -/obj/effect/spawner/random/engineering/flashlight, -/turf/open/floor/iron/dark, -/area/station/security/office) "xTO" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -67475,6 +67488,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/port/aft) +"xUx" = ( +/obj/machinery/light_switch/directional/east, +/obj/structure/dresser, +/obj/structure/secure_safe/directional/north, +/turf/open/floor/wood, +/area/station/command/heads_quarters/captain/private) "xUB" = ( /obj/structure/sign/directions/security{ dir = 1; @@ -67621,23 +67640,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/port) -"xWY" = ( -/obj/item/radio/intercom/directional/south, -/obj/effect/turf_decal/tile/bar, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/structure/table, -/obj/machinery/reagentgrinder{ - pixel_x = 6; - pixel_y = 6 - }, -/obj/item/reagent_containers/condiment/enzyme{ - layer = 5; - pixel_x = -6 - }, -/turf/open/floor/iron/cafeteria, -/area/station/service/kitchen) "xXf" = ( /obj/machinery/door/airlock/mining{ name = "Deliveries" @@ -86104,7 +86106,7 @@ gYC xGm isO gYE -uEC +xuP wgw twr bSm @@ -90227,7 +90229,7 @@ rlU vis mCi ixT -nka +oXK rlU aaa aEH @@ -92051,7 +92053,7 @@ wvo xCl nMz pJR -nlV +egp kfA rWH oOE @@ -92086,7 +92088,7 @@ ePX svQ duu pKP -uno +cQz rQd cJm jGw @@ -92306,9 +92308,9 @@ oIa cpn koa srP -iEs +nuB pJR -cMc +gAk qAA uFQ eIy @@ -94580,7 +94582,7 @@ aaa aaa aaa rJB -oZn +bhv dxe wTO xxZ @@ -94619,7 +94621,7 @@ tKN aaf dsQ mZL -rxN +usQ aGQ acf hmq @@ -94880,7 +94882,7 @@ nxO qXF qXF aMB -jtw +tVk duI jnt cdC @@ -94896,7 +94898,7 @@ jzN sYh qeZ nBs -qRs +eLa vyi nNY htd @@ -95608,7 +95610,7 @@ aaa aaa cTk aeq -xgh +dXs tJE kVU tJE @@ -98479,7 +98481,7 @@ ogL tyY aPs cUX -gfc +guO nOq xDa vwP @@ -98697,7 +98699,7 @@ kxA xXh ooG wxj -xTH +gem ipz nOv dgS @@ -99220,7 +99222,7 @@ pBG sOZ uWo jMy -fiI +eey aHr mhA xNo @@ -99741,7 +99743,7 @@ bHN ilh ilh ilh -ddy +oha fbs itp soX @@ -100013,7 +100015,7 @@ wEG htd qBC syo -nsx +xUx cRU oRn sjS @@ -100248,7 +100250,7 @@ lAM dDe lAM sWV -pjK +hlj dbj jyQ lGj @@ -101515,7 +101517,7 @@ aaa rrt lMJ mxn -fze +osH gTt sdu fad @@ -104145,7 +104147,7 @@ hPK pgK idR dVm -xWY +xuy uIs rwa aJI @@ -108233,7 +108235,7 @@ vHs iBm uXd sqE -fhz +cKW dJP bfO pCt @@ -108494,7 +108496,7 @@ nLz jEh hYE rEd -bdV +sby tUw iqU jLg @@ -108751,7 +108753,7 @@ qtm fyJ qVD cuc -nIx +adz tUw rHq peX From 86282e70c3dc36cda21ea26670158c8da2833864 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:44:02 +0300 Subject: [PATCH 29/55] [MIRROR] Removes a duplicate bookcase in icebox permabrig library (#758) * [MIRROR] Removes a duplicate bookcase in icebox permabrig library [MDB IGNORE] (#25158) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: die_amond <58376695+dieamond13@users.noreply.github.com> Co-authored-by: Iajret --- .../map_files/IceBoxStation/IceBoxStation.dmm | 203 +++++++++--------- 1 file changed, 99 insertions(+), 104 deletions(-) diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index db9b6bbba80..f40f1945f01 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -4163,16 +4163,6 @@ /obj/structure/sign/poster/contraband/the_griffin/directional/south, /turf/open/floor/iron/grimy, /area/station/commons/vacant_room/office) -"boj" = ( -/obj/machinery/airalarm/directional/north, -/obj/structure/closet/secure_closet/personal, -/obj/item/storage/briefcase/secure, -/obj/effect/turf_decal/tile/neutral/opposingcorners, -/obj/effect/turf_decal/tile/brown/opposingcorners{ - dir = 1 - }, -/turf/open/floor/iron, -/area/station/commons/vacant_room/commissary) "bol" = ( /turf/open/floor/iron/dark/textured, /area/station/security/prison) @@ -4594,12 +4584,6 @@ }, /turf/open/floor/plating, /area/station/engineering/atmos/pumproom) -"bup" = ( -/obj/structure/filingcabinet/chestdrawer, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/basic/parrot/poly, -/turf/open/floor/iron/dark, -/area/station/command/heads_quarters/ce) "buv" = ( /obj/machinery/atmospherics/pipe/multiz/scrubbers/visible/layer2{ color = "#ff0000"; @@ -10054,14 +10038,6 @@ }, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors/nospawn) -"cXb" = ( -/obj/structure/table/reinforced, -/obj/structure/secure_safe/caps_spare/directional/east, -/obj/item/papercutter{ - pixel_x = 7 - }, -/turf/open/floor/iron, -/area/station/command/bridge) "cXc" = ( /obj/effect/turf_decal/arrows, /turf/open/floor/iron, @@ -17140,6 +17116,12 @@ "fiL" = ( /turf/closed/wall/r_wall, /area/station/security/evidence) +"fiN" = ( +/obj/structure/table/wood, +/obj/structure/secure_safe/directional/east, +/obj/machinery/light/directional/east, +/turf/open/floor/wood, +/area/station/command/heads_quarters/captain) "fiO" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -17992,6 +17974,14 @@ /obj/structure/cable, /turf/open/floor/iron/showroomfloor, /area/station/engineering/atmos) +"fwQ" = ( +/obj/structure/table/reinforced, +/obj/structure/secure_safe/caps_spare/directional/east, +/obj/item/papercutter{ + pixel_x = 7 + }, +/turf/open/floor/iron, +/area/station/command/bridge) "fwS" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -27847,15 +27837,6 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron/white, /area/station/maintenance/port/fore) -"iBi" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/obj/structure/table, -/obj/structure/secure_safe/directional/south, -/obj/item/storage/briefcase/secure, -/turf/open/floor/iron/smooth, -/area/station/command/heads_quarters/rd) "iBj" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 1 @@ -28640,14 +28621,6 @@ /obj/effect/spawner/random/structure/steam_vent, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"iOQ" = ( -/obj/structure/table/reinforced, -/obj/item/storage/briefcase/secure{ - pixel_y = 5 - }, -/obj/machinery/status_display/evac/directional/west, -/turf/open/floor/iron, -/area/station/command/bridge) "iOS" = ( /obj/machinery/airalarm/directional/east, /obj/structure/table, @@ -30568,6 +30541,12 @@ }, /turf/open/floor/iron/white, /area/station/medical/treatment_center) +"juH" = ( +/obj/structure/filingcabinet/chestdrawer, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/mob/living/basic/parrot/poly, +/turf/open/floor/iron/dark, +/area/station/command/heads_quarters/ce) "juQ" = ( /obj/structure/rack, /obj/item/stack/rods/fifty, @@ -32043,11 +32022,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/aft) -"jSc" = ( -/obj/structure/bookcase/random, -/obj/structure/bookcase/random, -/turf/open/floor/carpet/red, -/area/station/security/prison/work) "jSe" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -38129,6 +38103,14 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) +"lET" = ( +/obj/structure/table/reinforced, +/obj/item/storage/briefcase/secure{ + pixel_y = 5 + }, +/obj/machinery/status_display/evac/directional/west, +/turf/open/floor/iron, +/area/station/command/bridge) "lFe" = ( /obj/structure/bookcase/random/adult, /turf/open/floor/iron/dark/textured, @@ -42338,12 +42320,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/commons/fitness) -"mZO" = ( -/obj/structure/table/wood, -/obj/structure/secure_safe/directional/east, -/obj/machinery/light/directional/east, -/turf/open/floor/wood, -/area/station/command/heads_quarters/captain) "mZS" = ( /obj/machinery/door/firedoor, /obj/effect/turf_decal/tile/blue, @@ -52200,6 +52176,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/cafeteria, /area/station/commons/storage/art) +"pRX" = ( +/obj/structure/secure_safe/directional/south, +/obj/machinery/light/directional/south, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/commons/vacant_room/commissary) "pRZ" = ( /obj/machinery/shower/directional/south, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, @@ -53283,6 +53267,15 @@ /obj/machinery/firealarm/directional/north, /turf/open/floor/iron, /area/station/science/explab) +"qlO" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 6 + }, +/obj/structure/table, +/obj/structure/secure_safe/directional/south, +/obj/item/storage/briefcase/secure, +/turf/open/floor/iron/smooth, +/area/station/command/heads_quarters/rd) "qlP" = ( /obj/machinery/door/airlock/external/glass, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -54822,29 +54815,6 @@ /obj/item/cigbutt, /turf/open/floor/wood/large, /area/mine/eva/lower) -"qJO" = ( -/obj/structure/table/wood, -/obj/item/reagent_containers/cup/glass/bottle/vodka/badminka{ - pixel_x = 7; - pixel_y = 20 - }, -/obj/item/taperecorder{ - pixel_x = -5; - pixel_y = 1 - }, -/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{ - pixel_x = 7; - pixel_y = 8 - }, -/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{ - pixel_x = 6 - }, -/obj/structure/secure_safe/hos{ - pixel_x = 35 - }, -/obj/machinery/firealarm/directional/south, -/turf/open/floor/iron/dark/smooth_large, -/area/station/command/heads_quarters/hos) "qJT" = ( /obj/machinery/light/small/directional/south, /turf/open/floor/plating/snowed/icemoon, @@ -59015,6 +58985,17 @@ /obj/structure/cable, /turf/open/floor/carpet, /area/station/command/heads_quarters/captain) +"rXj" = ( +/obj/structure/bed{ + dir = 4 + }, +/obj/item/bedsheet/medical{ + dir = 4 + }, +/obj/structure/secure_safe/directional/south, +/obj/effect/turf_decal/tile/green/full, +/turf/open/floor/iron/dark/smooth_large, +/area/station/medical/virology) "rXr" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -65563,6 +65544,16 @@ /obj/effect/decal/cleanable/cobweb, /turf/open/floor/plating, /area/station/maintenance/department/chapel) +"uao" = ( +/obj/machinery/airalarm/directional/north, +/obj/structure/closet/secure_closet/personal, +/obj/item/storage/briefcase/secure, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/tile/brown/opposingcorners{ + dir = 1 + }, +/turf/open/floor/iron, +/area/station/commons/vacant_room/commissary) "uar" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -69730,6 +69721,29 @@ dir = 10 }, /area/station/science/research) +"vtZ" = ( +/obj/structure/table/wood, +/obj/item/reagent_containers/cup/glass/bottle/vodka/badminka{ + pixel_x = 7; + pixel_y = 20 + }, +/obj/item/taperecorder{ + pixel_x = -5; + pixel_y = 1 + }, +/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{ + pixel_x = 7; + pixel_y = 8 + }, +/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{ + pixel_x = 6 + }, +/obj/structure/secure_safe/hos{ + pixel_x = 35 + }, +/obj/machinery/firealarm/directional/south, +/turf/open/floor/iron/dark/smooth_large, +/area/station/command/heads_quarters/hos) "vuh" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -70739,17 +70753,6 @@ /obj/machinery/light_switch/directional/west, /turf/open/floor/iron/dark, /area/station/science/breakroom) -"vJX" = ( -/obj/structure/bed{ - dir = 4 - }, -/obj/item/bedsheet/medical{ - dir = 4 - }, -/obj/structure/secure_safe/directional/south, -/obj/effect/turf_decal/tile/green/full, -/turf/open/floor/iron/dark/smooth_large, -/area/station/medical/virology) "vJY" = ( /obj/structure/railing/corner{ dir = 8 @@ -73970,14 +73973,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/carpet, /area/station/commons/dorms) -"wIE" = ( -/obj/structure/secure_safe/directional/south, -/obj/machinery/light/directional/south, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/commons/vacant_room/commissary) "wIF" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -169146,7 +169141,7 @@ scl dck scl htB -jSc +scl jty cIc nUL @@ -184135,7 +184130,7 @@ hzz gmf jUB gyY -vJX +rXj xDb thA thA @@ -233195,7 +233190,7 @@ gpZ vov cAo gst -boj +uao plN rTO rTO @@ -233457,7 +233452,7 @@ fXu uOM vzw rTO -wIE +pRX gst byl rgl @@ -237817,7 +237812,7 @@ dnq kgD utR uEQ -iOQ +lET grA cEv nOH @@ -239576,7 +239571,7 @@ jDt wtg diq ehy -qJO +vtZ mgU fUj kcc @@ -240388,7 +240383,7 @@ nfk utR tmQ qnV -cXb +fwQ kBr lhv iGH @@ -240442,7 +240437,7 @@ ami oPU wHj mBB -bup +juH ojv htc mDw @@ -242454,7 +242449,7 @@ eEC aTw iFL hpe -mZO +fiN mBX uEm viQ @@ -254813,7 +254808,7 @@ bHa oMT gaT bZc -iBi +qlO jbU ily hdH From cb35300bbd71ac5adb73f94e3abcc1514fac0541 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:44:23 +0300 Subject: [PATCH 30/55] [MIRROR] fixes some things that bugged me on icebox [MDB IGNORE] (#759) * fixes some things that bugged me on icebox (#79832) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> --- .../map_files/IceBoxStation/IceBoxStation.dmm | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index f40f1945f01..e37c8699be8 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -9330,11 +9330,6 @@ /area/station/cargo/warehouse) "cLw" = ( /obj/structure/table/reinforced, -/obj/machinery/door/window/left/directional/north{ - dir = 4; - name = "Engineering Desk"; - req_access = list("engine_equip") - }, /obj/machinery/door/firedoor, /obj/item/paper_bin{ pixel_x = -6; @@ -9351,6 +9346,11 @@ /obj/structure/desk_bell{ pixel_x = 6 }, +/obj/machinery/door/window/left/directional/north{ + dir = 4; + name = "Engineering Desk"; + req_access = list("engineering") + }, /turf/open/floor/iron, /area/station/engineering/lobby) "cLB" = ( @@ -35542,6 +35542,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden, /turf/open/floor/iron/showroomfloor, /area/station/engineering/atmos) +"kRy" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/turf_decal/tile/red, +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/hallway/primary/central/fore) "kRE" = ( /obj/machinery/computer/mech_bay_power_console{ dir = 8 @@ -40989,7 +40996,7 @@ "mCb" = ( /mob/living/basic/goat/pete{ desc = "Not known for their pleasant disposition. This one seems a bit more hardy to the cold."; - habitable_atmos = list("min_oxy" = 1, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0); + habitable_atmos = list("min_oxy"=1,"max_oxy"=0,"min_plas"=0,"max_plas"=1,"min_co2"=0,"max_co2"=5,"min_n2"=0,"max_n2"=0); minimum_survivable_temperature = 150; name = "Snowy Pete" }, @@ -45848,6 +45855,7 @@ }, /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/security/general, +/obj/structure/cable, /turf/open/floor/iron/textured, /area/station/security/brig) "nZf" = ( @@ -59411,6 +59419,10 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/storage/eva) +"sen" = ( +/obj/structure/cable, +/turf/open/floor/iron, +/area/station/security/courtroom) "seA" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -70554,6 +70566,7 @@ "vFO" = ( /obj/structure/window/reinforced/spawner/directional/west, /obj/structure/window/reinforced/spawner/directional/east, +/obj/structure/cable, /turf/open/floor/iron/textured, /area/station/security/brig) "vFW" = ( @@ -77374,6 +77387,7 @@ }, /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/security/general, +/obj/structure/cable, /turf/open/floor/iron/textured, /area/station/security/courtroom) "xGZ" = ( @@ -78420,7 +78434,7 @@ }, /obj/machinery/elevator_control_panel/directional/north{ linked_elevator_id = "publicElevator"; - preset_destination_names = list("3" = "Icemoon Level", "4" = "Station Level") + preset_destination_names = list("3"="Icemoon Level","4"="Station Level") }, /turf/open/floor/plating/elevatorshaft, /area/mine/storage) @@ -169163,7 +169177,7 @@ jLB qpB qpB siv -qpB +kRy qpB iwC qzV @@ -170455,8 +170469,8 @@ vFO vFO vFO xGX -aiX -aiX +sen +sen lQq aiX vrc From 292cc2ad31977989e70de748087ccaafca8b4696 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:44:47 +0300 Subject: [PATCH 31/55] [MIRROR] Adds one way exits to Tramstation science entrance (#760) * [MIRROR] Adds one way exits to Tramstation science entrance [MDB IGNORE] (#25136) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: die_amond <58376695+dieamond13@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Iajret --- _maps/map_files/tramstation/tramstation.dmm | 312 ++++++++++---------- 1 file changed, 158 insertions(+), 154 deletions(-) diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 7c7614177b7..a41f196bc29 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -3298,6 +3298,18 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/atmospherics_engine) +"asG" = ( +/obj/structure/table, +/obj/item/storage/fancy/cigarettes{ + pixel_x = 8; + pixel_y = 8 + }, +/obj/item/storage/briefcase/secure{ + pixel_x = -3; + pixel_y = 2 + }, +/turf/open/floor/iron, +/area/station/security/office) "asQ" = ( /obj/structure/sign/warning/no_smoking, /turf/closed/wall, @@ -8257,6 +8269,7 @@ /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 1 }, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/iron/white, /area/station/science/research) "bNi" = ( @@ -11142,16 +11155,6 @@ /obj/machinery/light/directional/south, /turf/open/floor/iron/dark, /area/station/security/courtroom) -"cMY" = ( -/obj/structure/table/reinforced, -/obj/item/storage/briefcase/secure, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron/dark/side{ - dir = 8 - }, -/area/station/command/bridge) "cNc" = ( /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 4 @@ -15547,6 +15550,16 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/hallway/primary/tram/left) +"esf" = ( +/obj/structure/table/reinforced, +/obj/item/storage/briefcase/secure, +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/turf/open/floor/iron/dark/side{ + dir = 8 + }, +/area/station/command/bridge) "esi" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 @@ -15690,14 +15703,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/engineering/supermatter/room) -"evc" = ( -/obj/structure/displaycase/captain{ - pixel_y = 5 - }, -/obj/machinery/status_display/evac/directional/north, -/obj/structure/secure_safe/directional/west, -/turf/open/floor/wood, -/area/station/command/heads_quarters/captain) "evd" = ( /obj/effect/turf_decal/trimline/purple/filled/line{ dir = 1 @@ -16750,14 +16755,6 @@ /obj/machinery/airalarm/directional/west, /turf/open/floor/plating, /area/station/maintenance/central/greater) -"eQO" = ( -/obj/structure/closet{ - name = "Evidence Closet 1" - }, -/obj/structure/secure_safe/directional/east, -/obj/effect/spawner/random/contraband/cannabis, -/turf/open/floor/iron/dark, -/area/station/security/evidence) "eQR" = ( /obj/structure/railing/corner{ dir = 8 @@ -17608,6 +17605,16 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/freezer, /area/station/security/prison/shower) +"fhK" = ( +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/table/wood, +/obj/item/storage/briefcase/secure{ + pixel_x = -2; + pixel_y = 4 + }, +/obj/item/storage/lockbox/medal, +/turf/open/floor/wood, +/area/station/command/heads_quarters/captain) "fhL" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -18521,15 +18528,6 @@ /obj/effect/turf_decal/trimline/purple/filled/corner, /turf/open/floor/iron, /area/station/hallway/secondary/exit) -"fyA" = ( -/obj/structure/table/reinforced, -/obj/structure/secure_safe/caps_spare/directional/east, -/obj/machinery/cell_charger{ - pixel_y = 4 - }, -/obj/item/stock_parts/cell/high, -/turf/open/floor/iron, -/area/station/command/bridge) "fyF" = ( /obj/effect/landmark/event_spawn, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -22054,6 +22052,7 @@ /obj/effect/mapping_helpers/airlock/access/all/science/general, /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/structure/disposalpipe/segment, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/iron/white/side, /area/station/science/research) "gPA" = ( @@ -24680,6 +24679,13 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/command) +"hPQ" = ( +/obj/structure/secure_safe/directional/north, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark, +/area/station/commons/vacant_room/commissary) "hPW" = ( /obj/effect/turf_decal/trimline/red/filled/line, /obj/effect/turf_decal/trimline/red/filled/corner{ @@ -24981,20 +24987,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/storage) -"hWu" = ( -/obj/structure/rack, -/obj/item/storage/briefcase{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/storage/briefcase/secure, -/obj/effect/turf_decal/trimline/green/filled/corner, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 9 - }, -/obj/machinery/light/directional/north, -/turf/open/floor/iron, -/area/station/security/courtroom) "hWI" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -27743,15 +27735,6 @@ /obj/structure/cable, /turf/open/openspace, /area/station/solars/starboard/fore) -"iXr" = ( -/obj/structure/table/wood, -/obj/item/storage/briefcase/secure{ - pixel_x = -2; - pixel_y = 6 - }, -/obj/structure/cable, -/turf/open/floor/wood, -/area/station/command/heads_quarters/hop) "iXx" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible/layer2, /obj/structure/lattice, @@ -28904,13 +28887,6 @@ }, /turf/open/floor/iron/white, /area/station/science/research) -"jqE" = ( -/obj/structure/secure_safe/directional/north, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/commons/vacant_room/commissary) "jqK" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -32841,6 +32817,33 @@ "kHB" = ( /turf/open/floor/grass, /area/station/medical/virology) +"kHR" = ( +/obj/structure/filingcabinet/chestdrawer, +/obj/effect/turf_decal/trimline/yellow/filled/line{ + dir = 9 + }, +/obj/machinery/button/door/directional/west{ + id = "atmos"; + name = "Atmospherics Lockdown"; + pixel_y = 8; + req_access = list("atmospherics") + }, +/obj/machinery/button/door/directional/west{ + id = "Secure Storage"; + name = "Engineering Secure Storage"; + req_access = list("engine_equip") + }, +/obj/machinery/button/door/directional/west{ + id = "Engineering"; + name = "Engineering Lockdown"; + pixel_y = -8; + req_access = list("engineering") + }, +/obj/machinery/power/apc/auto_name/directional/north, +/obj/structure/cable, +/mob/living/basic/parrot/poly, +/turf/open/floor/iron, +/area/station/command/heads_quarters/ce) "kHS" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/public/glass{ @@ -33004,18 +33007,6 @@ }, /turf/open/floor/iron/white, /area/station/science/explab) -"kKw" = ( -/obj/structure/table, -/obj/item/storage/fancy/cigarettes{ - pixel_x = 8; - pixel_y = 8 - }, -/obj/item/storage/briefcase/secure{ - pixel_x = -3; - pixel_y = 2 - }, -/turf/open/floor/iron, -/area/station/security/office) "kKB" = ( /obj/machinery/door/airlock{ name = "Law Office" @@ -41944,14 +41935,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/tram/left) -"nQF" = ( -/obj/structure/closet/secure_closet/hos, -/obj/structure/secure_safe/hos{ - pixel_x = 35 - }, -/obj/structure/sign/poster/official/space_cops/directional/north, -/turf/open/floor/carpet, -/area/station/command/heads_quarters/hos) "nQG" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, @@ -42392,6 +42375,13 @@ /obj/item/stamp/head/cmo, /turf/open/floor/iron/white, /area/station/command/heads_quarters/cmo) +"nXM" = ( +/obj/structure/table/glass, +/obj/item/storage/briefcase/secure, +/obj/effect/turf_decal/tile/blue/fourcorners, +/obj/machinery/light/cold/directional/south, +/turf/open/floor/iron/white, +/area/station/command/heads_quarters/cmo) "nXP" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -44178,6 +44168,11 @@ /obj/structure/sign/warning/fire, /turf/closed/wall/r_wall, /area/station/engineering/supermatter) +"oMh" = ( +/obj/structure/secure_safe/directional/east, +/obj/machinery/airalarm/directional/north, +/turf/open/floor/carpet, +/area/station/security/detectives_office) "oMz" = ( /obj/effect/turf_decal/trimline/purple/filled/corner{ dir = 4 @@ -44726,13 +44721,6 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/aisat/foyer) -"oXx" = ( -/obj/structure/table/glass, -/obj/item/storage/briefcase/secure, -/obj/effect/turf_decal/tile/blue/fourcorners, -/obj/machinery/light/cold/directional/south, -/turf/open/floor/iron/white, -/area/station/command/heads_quarters/cmo) "oXz" = ( /obj/machinery/iv_drip, /obj/effect/turf_decal/trimline/blue/filled/line{ @@ -46162,6 +46150,14 @@ /obj/structure/closet/toolcloset, /turf/open/floor/iron, /area/station/engineering/main) +"pxf" = ( +/obj/structure/closet/secure_closet/hos, +/obj/structure/secure_safe/hos{ + pixel_x = 35 + }, +/obj/structure/sign/poster/official/space_cops/directional/north, +/turf/open/floor/carpet, +/area/station/command/heads_quarters/hos) "pxj" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/table, @@ -46426,6 +46422,7 @@ dir = 1 }, /obj/structure/disposalpipe/segment, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/iron/white, /area/station/science/research) "pAR" = ( @@ -46643,6 +46640,7 @@ /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/science/general, /obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/effect/mapping_helpers/airlock/unres, /turf/open/floor/iron/white/side, /area/station/science/research) "pFm" = ( @@ -47542,33 +47540,6 @@ /obj/machinery/light/warm/directional/north, /turf/open/floor/iron/dark, /area/station/service/bar) -"pWa" = ( -/obj/structure/filingcabinet/chestdrawer, -/obj/effect/turf_decal/trimline/yellow/filled/line{ - dir = 9 - }, -/obj/machinery/button/door/directional/west{ - id = "atmos"; - name = "Atmospherics Lockdown"; - pixel_y = 8; - req_access = list("atmospherics") - }, -/obj/machinery/button/door/directional/west{ - id = "Secure Storage"; - name = "Engineering Secure Storage"; - req_access = list("engine_equip") - }, -/obj/machinery/button/door/directional/west{ - id = "Engineering"; - name = "Engineering Lockdown"; - pixel_y = -8; - req_access = list("engineering") - }, -/obj/machinery/power/apc/auto_name/directional/north, -/obj/structure/cable, -/mob/living/basic/parrot/poly, -/turf/open/floor/iron, -/area/station/command/heads_quarters/ce) "pWt" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ dir = 4 @@ -48216,6 +48187,15 @@ "qgt" = ( /turf/closed/wall/rock/porous, /area/station/medical/chemistry) +"qgy" = ( +/obj/structure/table/reinforced, +/obj/structure/secure_safe/caps_spare/directional/east, +/obj/machinery/cell_charger{ + pixel_y = 4 + }, +/obj/item/stock_parts/cell/high, +/turf/open/floor/iron, +/area/station/command/bridge) "qgB" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -48552,6 +48532,14 @@ /obj/machinery/light/directional/south, /turf/open/floor/iron/dark, /area/station/hallway/secondary/exit/departure_lounge) +"qmC" = ( +/obj/structure/closet{ + name = "Evidence Closet 1" + }, +/obj/structure/secure_safe/directional/east, +/obj/effect/spawner/random/contraband/cannabis, +/turf/open/floor/iron/dark, +/area/station/security/evidence) "qmH" = ( /obj/structure/closet/secure_closet/quartermaster, /obj/effect/turf_decal/trimline/brown/filled/line{ @@ -48621,12 +48609,6 @@ }, /turf/open/floor/iron, /area/station/science/explab) -"qnC" = ( -/obj/structure/closet/secure_closet/hop, -/obj/structure/sign/clock/directional/west, -/obj/structure/secure_safe/directional/north, -/turf/open/floor/carpet, -/area/station/command/heads_quarters/hop) "qnL" = ( /obj/machinery/light/directional/east, /turf/open/floor/noslip/tram, @@ -50910,6 +50892,14 @@ }, /turf/open/floor/iron/freezer, /area/station/commons/toilet) +"rdm" = ( +/obj/structure/displaycase/captain{ + pixel_y = 5 + }, +/obj/machinery/status_display/evac/directional/north, +/obj/structure/secure_safe/directional/west, +/turf/open/floor/wood, +/area/station/command/heads_quarters/captain) "rdo" = ( /obj/machinery/computer/shuttle/labor, /obj/effect/turf_decal/trimline/red/filled/line{ @@ -54887,11 +54877,6 @@ "syv" = ( /turf/closed/wall/r_wall, /area/station/security/checkpoint/science) -"syB" = ( -/obj/structure/secure_safe/directional/east, -/obj/machinery/airalarm/directional/north, -/turf/open/floor/carpet, -/area/station/security/detectives_office) "syE" = ( /obj/machinery/rnd/production/circuit_imprinter/department/science, /obj/effect/turf_decal/stripes/line{ @@ -57991,6 +57976,15 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"tDR" = ( +/obj/structure/table/wood, +/obj/item/storage/briefcase/secure{ + pixel_x = -2; + pixel_y = 6 + }, +/obj/structure/cable, +/turf/open/floor/wood, +/area/station/command/heads_quarters/hop) "tDT" = ( /turf/open/openspace, /area/station/commons/fitness/recreation) @@ -60228,6 +60222,12 @@ /obj/machinery/telecomms/processor/preset_three, /turf/open/floor/iron/dark/telecomms, /area/station/tcommsat/server) +"uqs" = ( +/obj/structure/closet/secure_closet/hop, +/obj/structure/sign/clock/directional/west, +/obj/structure/secure_safe/directional/north, +/turf/open/floor/carpet, +/area/station/command/heads_quarters/hop) "uqA" = ( /obj/effect/turf_decal/siding/thinplating/dark/corner, /obj/machinery/duct, @@ -60886,6 +60886,20 @@ }, /turf/open/floor/engine/hull, /area/station/solars/starboard/fore) +"uBi" = ( +/obj/structure/rack, +/obj/item/storage/briefcase{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/storage/briefcase/secure, +/obj/effect/turf_decal/trimline/green/filled/corner, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 9 + }, +/obj/machinery/light/directional/north, +/turf/open/floor/iron, +/area/station/security/courtroom) "uBo" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -68684,16 +68698,6 @@ /obj/effect/turf_decal/trimline/white/filled/line, /turf/open/floor/iron/dark, /area/station/engineering/storage/tech) -"xsV" = ( -/obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/table/wood, -/obj/item/storage/briefcase/secure{ - pixel_x = -2; - pixel_y = 4 - }, -/obj/item/storage/lockbox/medal, -/turf/open/floor/wood, -/area/station/command/heads_quarters/captain) "xsW" = ( /obj/machinery/porta_turret/ai{ dir = 4 @@ -99186,7 +99190,7 @@ aaa hFr nMu hFr -hWu +uBi abZ ycB jyA @@ -102592,7 +102596,7 @@ fXQ srY roB roB -pWa +kHR tga rnf xBD @@ -150871,7 +150875,7 @@ aBV aBV aBV wHT -qnC +uqs kcw ruV wHT @@ -151905,7 +151909,7 @@ umf qjW dCk iDR -iXr +tDR wHT omH jKZ @@ -155757,7 +155761,7 @@ uvu aCC ukE hhc -cMY +esf lPY eaT kiU @@ -156011,7 +156015,7 @@ aQO rup wzm rAh -fyA +qgy eUy mgq nhV @@ -157511,7 +157515,7 @@ aaa aaa aaa rmB -nQF +pxf bWb toY wpM @@ -157522,7 +157526,7 @@ avl fBk myB vhl -kKw +asG vhl gnL lvm @@ -157803,9 +157807,9 @@ ltw pbx pyA ltw -evc +rdm vjq -xsV +fhK ktl mjd mjI @@ -158838,7 +158842,7 @@ phl sSx xJH xEo -syB +oMh ixO urP kOE @@ -159575,7 +159579,7 @@ aaa abM abM tFJ -eQO +qmC fsQ jil fsQ @@ -166592,7 +166596,7 @@ aOF wdj wao cHU -oXx +nXM wdj oGJ oGJ @@ -184809,7 +184813,7 @@ ebY aGn brm nSI -jqE +hPQ vDI nSd rMB From 2cc9a5b62ff8c4fef140f5f89face3e56c1a470c Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:46:33 +0300 Subject: [PATCH 32/55] Automatic changelog for PR #753 [ci skip] --- html/changelogs/AutoChangeLog-pr-753.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-753.yml diff --git a/html/changelogs/AutoChangeLog-pr-753.yml b/html/changelogs/AutoChangeLog-pr-753.yml new file mode 100644 index 00000000000..ee6df4df70e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-753.yml @@ -0,0 +1,4 @@ +author: "EuSouAFazer" +delete-after: True +changes: + - bugfix: "Meta's recycler works again" \ No newline at end of file From 0d8e410de040f8737220d181173f88b7a93df5af Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:47:42 +0300 Subject: [PATCH 33/55] Automatic changelog for PR #758 [ci skip] --- html/changelogs/AutoChangeLog-pr-758.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-758.yml diff --git a/html/changelogs/AutoChangeLog-pr-758.yml b/html/changelogs/AutoChangeLog-pr-758.yml new file mode 100644 index 00000000000..8a4173cb415 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-758.yml @@ -0,0 +1,4 @@ +author: "dieamond13" +delete-after: True +changes: + - bugfix: "removes a duplicate bookcase in icebox permabrig library" \ No newline at end of file From fbd532eb847aabea4c302793b8ea9b21a2f56b96 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:49:13 +0300 Subject: [PATCH 34/55] Automatic changelog for PR #759 [ci skip] --- html/changelogs/AutoChangeLog-pr-759.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-759.yml diff --git a/html/changelogs/AutoChangeLog-pr-759.yml b/html/changelogs/AutoChangeLog-pr-759.yml new file mode 100644 index 00000000000..fadd2abe4ef --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-759.yml @@ -0,0 +1,5 @@ +author: "JohnFulpWillard" +delete-after: True +changes: + - bugfix: "[Icebox] Atmos techs have access to the Engineering front desk windoor." + - qol: "[Icebox] Security's lower floor is not as easily cut off from the powernet anymore." \ No newline at end of file From f59c9ac1ead182c5aca4291ac3d17f6f45f86bfa Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:49:38 +0300 Subject: [PATCH 35/55] Automatic changelog for PR #760 [ci skip] --- html/changelogs/AutoChangeLog-pr-760.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-760.yml diff --git a/html/changelogs/AutoChangeLog-pr-760.yml b/html/changelogs/AutoChangeLog-pr-760.yml new file mode 100644 index 00000000000..cc612b07651 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-760.yml @@ -0,0 +1,4 @@ +author: "dieamond13" +delete-after: True +changes: + - bugfix: "adds back one way exits to Tramstation science's entrance" \ No newline at end of file From 834db1653b04e829501d4a348693112addb7f5b6 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Wed, 22 Nov 2023 03:40:28 +0300 Subject: [PATCH 36/55] [MIRROR] Enzyme (var) exorcism in Metastation (#763) * [MIRROR] Enzyme (var) exorcism in Metastation [MDB IGNORE] (#25130) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Fazzie <84548101+EuSouAFazer@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Iajret --- _maps/map_files/MetaStation/MetaStation.dmm | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index cf996d4b8e1..6b23ab29959 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -57846,6 +57846,16 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"uEC" = ( +/obj/machinery/conveyor{ + dir = 4; + id = "garbage" + }, +/obj/machinery/recycler{ + dir = 8 + }, +/turf/open/floor/plating, +/area/station/maintenance/disposal) "uEO" = ( /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/plating, @@ -67640,6 +67650,23 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/port) +"xWY" = ( +/obj/item/radio/intercom/directional/south, +/obj/effect/turf_decal/tile/bar, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/table, +/obj/machinery/reagentgrinder{ + pixel_x = 6; + pixel_y = 6 + }, +/obj/item/reagent_containers/condiment/enzyme{ + pixel_x = -6; + pixel_y = 5 + }, +/turf/open/floor/iron/cafeteria, +/area/station/service/kitchen) "xXf" = ( /obj/machinery/door/airlock/mining{ name = "Deliveries" From cf88a3ec675613f3c0afc46ac9253f43b872d3e4 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Wed, 22 Nov 2023 03:40:50 +0300 Subject: [PATCH 37/55] Automatic changelog for PR #763 [ci skip] --- html/changelogs/AutoChangeLog-pr-763.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-763.yml diff --git a/html/changelogs/AutoChangeLog-pr-763.yml b/html/changelogs/AutoChangeLog-pr-763.yml new file mode 100644 index 00000000000..878550fdbfc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-763.yml @@ -0,0 +1,5 @@ +author: "EuSouAFazer" +delete-after: True +changes: + - qol: "Slightly moved the universal enzyme on meta's kitchen to a prettier spot." + - bugfix: "The universal enzyme on meta's kitchen is no longer unecessarely varedited." \ No newline at end of file From 558abbafe990d250aa376c929a927fdcb0c2f0b0 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 22 Nov 2023 01:08:00 +0000 Subject: [PATCH 38/55] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-739.yml | 4 -- html/changelogs/AutoChangeLog-pr-744.yml | 5 -- html/changelogs/AutoChangeLog-pr-745.yml | 5 -- html/changelogs/AutoChangeLog-pr-746.yml | 6 --- html/changelogs/AutoChangeLog-pr-749.yml | 7 --- html/changelogs/AutoChangeLog-pr-751.yml | 4 -- html/changelogs/AutoChangeLog-pr-752.yml | 4 -- html/changelogs/AutoChangeLog-pr-753.yml | 4 -- html/changelogs/AutoChangeLog-pr-754.yml | 4 -- html/changelogs/AutoChangeLog-pr-755.yml | 4 -- html/changelogs/AutoChangeLog-pr-756.yml | 5 -- html/changelogs/AutoChangeLog-pr-757.yml | 4 -- html/changelogs/AutoChangeLog-pr-758.yml | 4 -- html/changelogs/AutoChangeLog-pr-759.yml | 5 -- html/changelogs/AutoChangeLog-pr-760.yml | 4 -- html/changelogs/AutoChangeLog-pr-761.yml | 4 -- html/changelogs/AutoChangeLog-pr-763.yml | 5 -- html/changelogs/archive/2023-11.yml | 63 ++++++++++++++++++++++++ 18 files changed, 63 insertions(+), 78 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-739.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-744.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-745.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-746.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-749.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-751.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-752.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-753.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-754.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-755.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-756.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-757.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-758.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-759.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-760.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-761.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-763.yml diff --git a/html/changelogs/AutoChangeLog-pr-739.yml b/html/changelogs/AutoChangeLog-pr-739.yml deleted file mode 100644 index eacb835f703..00000000000 --- a/html/changelogs/AutoChangeLog-pr-739.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "When you successfully block a body collision, it does something rather than nothing at all." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-744.yml b/html/changelogs/AutoChangeLog-pr-744.yml deleted file mode 100644 index c49b081a12c..00000000000 --- a/html/changelogs/AutoChangeLog-pr-744.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Hatterhat" -delete-after: True -changes: - - balance: "The SC/FISHER disruptor pistol is now more likely to show up in black market uplinks." - - balance: "The SC/FISHER now has more range (21 tiles up from 14), and is usable by pacifists." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-745.yml b/html/changelogs/AutoChangeLog-pr-745.yml deleted file mode 100644 index d7977979f16..00000000000 --- a/html/changelogs/AutoChangeLog-pr-745.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "san7890 and Ben10Omintrix/Kobsamobsa" -delete-after: True -changes: - - refactor: "Parrots (including Poly) have undergone a massive refactor, please report any bugs or unexpected behavior that you may encounter." - - qol: "Left-clicking a parrot with a cracker will tame it, right-clicking a parrot with a cracker will now feed it the cracker." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-746.yml b/html/changelogs/AutoChangeLog-pr-746.yml deleted file mode 100644 index 9b1f67170d8..00000000000 --- a/html/changelogs/AutoChangeLog-pr-746.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "yooriss" -delete-after: True -changes: - - rscadd: "Examining tamed companions of any type with shift double-click now gives a brief indication as to their overall health. This also includes a handy reminder on how to heal pets if they get injured." - - rscadd: "A new recipe for anointing bloodresin is now available exclusively for Primitive Demihumans, made from 80u liquid gibs and 20u of blood. Bloodresin invokes traditional rites of the Hearth to give names to worthy creatures. Using this in poor ways may displease the Gods. Woe upon your lineage." - - rscadd: "A single pack of glowshroom mycelium has been added to the Hearth's starting seed stores for the benefit of creative healers, shamans, and radiation enthusiasts." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-749.yml b/html/changelogs/AutoChangeLog-pr-749.yml deleted file mode 100644 index 941c7daa96a..00000000000 --- a/html/changelogs/AutoChangeLog-pr-749.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "Atrocinating mobs will now behave more as you'd expect. Meaning they don't slip on wet patches, can't trigger bear traps / landmines / mouse traps, ignore conveyors, and can walk over tables and railings." - - bugfix: "Floating mobs are unaffected by conveyor belts, acid (on the ground), glass tables" - - bugfix: "Floating mobs won't squish stuff like roaches anymore" - - bugfix: "Fixes bear traps triggering on floating / flying mobs" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-751.yml b/html/changelogs/AutoChangeLog-pr-751.yml deleted file mode 100644 index 857e8c8a4f9..00000000000 --- a/html/changelogs/AutoChangeLog-pr-751.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "LT3" -delete-after: True -changes: - - bugfix: "Cursed/bad luck omen will now stick with the player for more than 1 incident" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-752.yml b/html/changelogs/AutoChangeLog-pr-752.yml deleted file mode 100644 index 4fb98d4e8d2..00000000000 --- a/html/changelogs/AutoChangeLog-pr-752.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ghommie" -delete-after: True -changes: - - spellcheck: "Examining a human mob as an observer displays \"Quirks\", not \"Traits\"" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-753.yml b/html/changelogs/AutoChangeLog-pr-753.yml deleted file mode 100644 index ee6df4df70e..00000000000 --- a/html/changelogs/AutoChangeLog-pr-753.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "EuSouAFazer" -delete-after: True -changes: - - bugfix: "Meta's recycler works again" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-754.yml b/html/changelogs/AutoChangeLog-pr-754.yml deleted file mode 100644 index bd0f359aed9..00000000000 --- a/html/changelogs/AutoChangeLog-pr-754.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DaCoolBoss" -delete-after: True -changes: - - bugfix: "Removed a duplicate grille from the abandoned mime outpost space ruin, and replaced the 'energy weapon lenses' with spent revolver rounds." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-755.yml b/html/changelogs/AutoChangeLog-pr-755.yml deleted file mode 100644 index 24569b28c51..00000000000 --- a/html/changelogs/AutoChangeLog-pr-755.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Bumtickley00" -delete-after: True -changes: - - balance: "The CMO's hypospray now holds 60u, and can be set to inject smaller amounts of reagents" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-756.yml b/html/changelogs/AutoChangeLog-pr-756.yml deleted file mode 100644 index e55cb39ed13..00000000000 --- a/html/changelogs/AutoChangeLog-pr-756.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "lizardqueenlexi" -delete-after: True -changes: - - bugfix: "Heads impaled on spears now render in the correct place on the tip, instead of halfway down the shaft." - - bugfix: "Blind personnel are no longer able to magically see heads impaled on spears from a distance." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-757.yml b/html/changelogs/AutoChangeLog-pr-757.yml deleted file mode 100644 index 09f31b52d3b..00000000000 --- a/html/changelogs/AutoChangeLog-pr-757.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jane" -delete-after: True -changes: - - rscadd: "Bargonia Bar Sign for Cargo Bar Enjoyers" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-758.yml b/html/changelogs/AutoChangeLog-pr-758.yml deleted file mode 100644 index 8a4173cb415..00000000000 --- a/html/changelogs/AutoChangeLog-pr-758.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "dieamond13" -delete-after: True -changes: - - bugfix: "removes a duplicate bookcase in icebox permabrig library" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-759.yml b/html/changelogs/AutoChangeLog-pr-759.yml deleted file mode 100644 index fadd2abe4ef..00000000000 --- a/html/changelogs/AutoChangeLog-pr-759.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "JohnFulpWillard" -delete-after: True -changes: - - bugfix: "[Icebox] Atmos techs have access to the Engineering front desk windoor." - - qol: "[Icebox] Security's lower floor is not as easily cut off from the powernet anymore." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-760.yml b/html/changelogs/AutoChangeLog-pr-760.yml deleted file mode 100644 index cc612b07651..00000000000 --- a/html/changelogs/AutoChangeLog-pr-760.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "dieamond13" -delete-after: True -changes: - - bugfix: "adds back one way exits to Tramstation science's entrance" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-761.yml b/html/changelogs/AutoChangeLog-pr-761.yml deleted file mode 100644 index 20eb4fcd84e..00000000000 --- a/html/changelogs/AutoChangeLog-pr-761.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "OrionTheFox" -delete-after: True -changes: - - bugfix: "fixed a few missing/outdated HUD icons, including the Bitrunner's SecHUD icon, and switching the \"Suspected\" tag to match the color used on consoles" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-763.yml b/html/changelogs/AutoChangeLog-pr-763.yml deleted file mode 100644 index 878550fdbfc..00000000000 --- a/html/changelogs/AutoChangeLog-pr-763.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "EuSouAFazer" -delete-after: True -changes: - - qol: "Slightly moved the universal enzyme on meta's kitchen to a prettier spot." - - bugfix: "The universal enzyme on meta's kitchen is no longer unecessarely varedited." \ No newline at end of file diff --git a/html/changelogs/archive/2023-11.yml b/html/changelogs/archive/2023-11.yml index b41d68bd4b5..b6b20d983c2 100644 --- a/html/changelogs/archive/2023-11.yml +++ b/html/changelogs/archive/2023-11.yml @@ -1080,3 +1080,66 @@ once friendly. Being rather large dogs, they also have access to most of the pet commands you'd expect, such as fetching things, and violently mauling people their owners point at. +2023-11-22: + Bumtickley00: + - balance: The CMO's hypospray now holds 60u, and can be set to inject smaller amounts + of reagents + DaCoolBoss: + - bugfix: Removed a duplicate grille from the abandoned mime outpost space ruin, + and replaced the 'energy weapon lenses' with spent revolver rounds. + EuSouAFazer: + - bugfix: Meta's recycler works again + - qol: Slightly moved the universal enzyme on meta's kitchen to a prettier spot. + - bugfix: The universal enzyme on meta's kitchen is no longer unecessarely varedited. + Ghommie: + - spellcheck: Examining a human mob as an observer displays "Quirks", not "Traits" + Hatterhat: + - balance: The SC/FISHER disruptor pistol is now more likely to show up in black + market uplinks. + - balance: The SC/FISHER now has more range (21 tiles up from 14), and is usable + by pacifists. + Jane: + - rscadd: Bargonia Bar Sign for Cargo Bar Enjoyers + JohnFulpWillard: + - bugfix: '[Icebox] Atmos techs have access to the Engineering front desk windoor.' + - qol: '[Icebox] Security''s lower floor is not as easily cut off from the powernet + anymore.' + LT3: + - bugfix: Cursed/bad luck omen will now stick with the player for more than 1 incident + Melbert: + - bugfix: Atrocinating mobs will now behave more as you'd expect. Meaning they don't + slip on wet patches, can't trigger bear traps / landmines / mouse traps, ignore + conveyors, and can walk over tables and railings. + - bugfix: Floating mobs are unaffected by conveyor belts, acid (on the ground), + glass tables + - bugfix: Floating mobs won't squish stuff like roaches anymore + - bugfix: Fixes bear traps triggering on floating / flying mobs + OrionTheFox: + - bugfix: fixed a few missing/outdated HUD icons, including the Bitrunner's SecHUD + icon, and switching the "Suspected" tag to match the color used on consoles + dieamond13: + - bugfix: removes a duplicate bookcase in icebox permabrig library + - bugfix: adds back one way exits to Tramstation science's entrance + lizardqueenlexi: + - bugfix: Heads impaled on spears now render in the correct place on the tip, instead + of halfway down the shaft. + - bugfix: Blind personnel are no longer able to magically see heads impaled on spears + from a distance. + necromanceranne: + - bugfix: When you successfully block a body collision, it does something rather + than nothing at all. + san7890 and Ben10Omintrix/Kobsamobsa: + - refactor: Parrots (including Poly) have undergone a massive refactor, please report + any bugs or unexpected behavior that you may encounter. + - qol: Left-clicking a parrot with a cracker will tame it, right-clicking a parrot + with a cracker will now feed it the cracker. + yooriss: + - rscadd: Examining tamed companions of any type with shift double-click now gives + a brief indication as to their overall health. This also includes a handy reminder + on how to heal pets if they get injured. + - rscadd: A new recipe for anointing bloodresin is now available exclusively for + Primitive Demihumans, made from 80u liquid gibs and 20u of blood. Bloodresin + invokes traditional rites of the Hearth to give names to worthy creatures. Using + this in poor ways may displease the Gods. Woe upon your lineage. + - rscadd: A single pack of glowshroom mycelium has been added to the Hearth's starting + seed stores for the benefit of creative healers, shamans, and radiation enthusiasts. From 0c1aed9989bfaf18e9acb47ebf5fdca41d0428f0 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:40:29 +0300 Subject: [PATCH 39/55] [MIRROR] Sleeping Carp grant scroll no longer says deflect with throw mode (#609) * [MIRROR] Sleeping Carp grant scroll no longer says deflect with throw mode [MDB IGNORE] (#24980) * Sleeping Carp grant scroll no longer says deflect with throw mode (#79656) ## About The Pull Request https://github.com/tgstation/tgstation/pull/79517 changed sleeping carp to use combat mode to deflect instead of throw mode, but didn't change the grant scroll text to reflect. I doubt anyone reads that anyways. * Sleeping Carp grant scroll no longer says deflect with throw mode --------- Co-authored-by: 1393F <59183821+1393F@users.noreply.github.com> * Update sleeping_carp.dm --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: 1393F <59183821+1393F@users.noreply.github.com> Co-authored-by: ReezeBL --- code/game/objects/items/granters/martial_arts/sleeping_carp.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items/granters/martial_arts/sleeping_carp.dm b/code/game/objects/items/granters/martial_arts/sleeping_carp.dm index ab3e343b28d..a6b0ac58225 100644 --- a/code/game/objects/items/granters/martial_arts/sleeping_carp.dm +++ b/code/game/objects/items/granters/martial_arts/sleeping_carp.dm @@ -5,7 +5,7 @@ desc = "A scroll filled with strange markings. It seems to be drawings of some sort of martial art." greet = "You have learned the ancient martial art of the Sleeping Carp! Your hand-to-hand combat has become much more effective, and you are now able to deflect any projectiles \ directed toward you while in Throw Mode. Your body has also hardened itself, granting extra protection against lasting wounds that would otherwise mount during extended combat. \ - However, you are also unable to use any ranged weaponry. You can learn more about your newfound art by using the Recall Teachings verb in the Sleeping Carp tab." + However, you are also unable to use any ranged weaponry. You can learn more about your newfound art by using the Recall Teachings verb in the Sleeping Carp tab." // FF edit. Original: ... while in Combat Mode. ... icon = 'icons/obj/scrolls.dmi' icon_state = "sleepingcarp" worn_icon_state = "scroll" From dc4bee064387000f8ac770ce558fcc9a9c2bd31d Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:40:54 +0300 Subject: [PATCH 40/55] Automatic changelog for PR #609 [ci skip] --- html/changelogs/AutoChangeLog-pr-609.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-609.yml diff --git a/html/changelogs/AutoChangeLog-pr-609.yml b/html/changelogs/AutoChangeLog-pr-609.yml new file mode 100644 index 00000000000..c68aebecbb5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-609.yml @@ -0,0 +1,4 @@ +author: "1393F" +delete-after: True +changes: + - bugfix: "~~The Sleeping Carp scroll no longer says deflect using throw mode.~~ Nevermind." \ No newline at end of file From 7e810b867f4084363b50415e78411b8f14e39849 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 22 Nov 2023 12:29:07 +0000 Subject: [PATCH 41/55] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-609.yml | 4 ---- html/changelogs/archive/2023-11.yml | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-609.yml diff --git a/html/changelogs/AutoChangeLog-pr-609.yml b/html/changelogs/AutoChangeLog-pr-609.yml deleted file mode 100644 index c68aebecbb5..00000000000 --- a/html/changelogs/AutoChangeLog-pr-609.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "1393F" -delete-after: True -changes: - - bugfix: "~~The Sleeping Carp scroll no longer says deflect using throw mode.~~ Nevermind." \ No newline at end of file diff --git a/html/changelogs/archive/2023-11.yml b/html/changelogs/archive/2023-11.yml index b6b20d983c2..2462f64f68e 100644 --- a/html/changelogs/archive/2023-11.yml +++ b/html/changelogs/archive/2023-11.yml @@ -1081,6 +1081,9 @@ pet commands you'd expect, such as fetching things, and violently mauling people their owners point at. 2023-11-22: + 1393F: + - bugfix: ~~The Sleeping Carp scroll no longer says deflect using throw mode.~~ + Nevermind. Bumtickley00: - balance: The CMO's hypospray now holds 60u, and can be set to inject smaller amounts of reagents From e35ead03962f624c622d052233245f6315c4ac9d Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 01:57:38 +0300 Subject: [PATCH 42/55] [MIRROR] Renames js files into "proper" jsx [MDB IGNORE] (#770) * Renames js files into "proper" jsx * Rename skyrat js --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> --- .../common/{keycodes.js => keycodes.ts} | 0 tgui/packages/tgui-dev-server/dreamseeker.js | 4 +- tgui/packages/tgui-dev-server/index.js | 4 +- tgui/packages/tgui-dev-server/link/retrace.js | 6 +-- tgui/packages/tgui-dev-server/link/server.js | 6 +-- tgui/packages/tgui-dev-server/reloader.js | 8 +-- tgui/packages/tgui-dev-server/util.js | 2 +- tgui/packages/tgui-dev-server/webpack.js | 8 +-- tgui/packages/tgui-dev-server/winreg.js | 2 +- .../{Notifications.js => Notifications.jsx} | 0 .../tgui-panel/{Panel.js => Panel.jsx} | 0 ...wPlayingWidget.js => NowPlayingWidget.jsx} | 0 .../tgui-panel/audio/{index.js => index.ts} | 0 ...atPageSettings.js => ChatPageSettings.jsx} | 0 .../chat/{ChatPanel.js => ChatPanel.jsx} | 0 .../chat/{ChatTabs.js => ChatTabs.jsx} | 0 .../chat/{constants.js => constants.ts} | 0 .../tgui-panel/chat/{index.js => index.ts} | 0 .../game/{constants.js => constants.ts} | 0 .../tgui-panel/game/{index.js => index.ts} | 0 .../{PingIndicator.js => PingIndicator.jsx} | 0 .../ping/{constants.js => constants.ts} | 0 .../tgui-panel/ping/{index.js => index.ts} | 0 .../{SettingsPanel.js => SettingsPanel.jsx} | 0 .../settings/{constants.js => constants.ts} | 0 .../settings/{index.js => index.ts} | 0 .../tgui/components/{Blink.js => Blink.jsx} | 0 .../{BlockQuote.js => BlockQuote.jsx} | 0 .../tgui/components/{Button.js => Button.jsx} | 0 .../components/{ByondUi.js => ByondUi.jsx} | 0 .../tgui/components/{Chart.js => Chart.jsx} | 0 .../{Collapsible.js => Collapsible.jsx} | 0 .../components/{ColorBox.js => ColorBox.jsx} | 0 .../tgui/components/{Dimmer.js => Dimmer.jsx} | 0 .../components/{Divider.js => Divider.jsx} | 0 ...aggableControl.js => DraggableControl.jsx} | 0 .../packages/tgui/components/FakeTerminal.jsx | 51 +++++++++++++++++++ .../tgui/components/{Grid.js => Grid.jsx} | 0 .../{InfinitePlane.js => InfinitePlane.jsx} | 0 .../tgui/components/{Input.js => Input.jsx} | 0 .../tgui/components/{Knob.js => Knob.jsx} | 0 ...LabeledControls.js => LabeledControls.jsx} | 0 .../tgui/components/{Modal.js => Modal.jsx} | 0 .../{NoticeBox.js => NoticeBox.jsx} | 0 .../{NumberInput.js => NumberInput.jsx} | 0 .../{ProgressBar.js => ProgressBar.jsx} | 0 ...RestrictedInput.js => RestrictedInput.jsx} | 0 .../{RoundGauge.js => RoundGauge.jsx} | 0 .../tgui/components/{Slider.js => Slider.jsx} | 0 .../tgui/components/{Table.js => Table.jsx} | 0 .../tgui/components/{Tabs.js => Tabs.jsx} | 0 .../components/{TextArea.js => TextArea.jsx} | 0 .../{TimeDisplay.js => TimeDisplay.jsx} | 0 .../tgui/components/{index.js => index.ts} | 0 .../debug/{KitchenSink.js => KitchenSink.jsx} | 0 .../tgui/debug/{index.js => index.ts} | 0 ...AbductorConsole.js => AbductorConsole.jsx} | 0 .../{Achievements.js => Achievements.jsx} | 0 .../interfaces/{AdminFax.js => AdminFax.jsx} | 0 .../interfaces/{AdminPDA.js => AdminPDA.jsx} | 0 .../{AiAirlock.js => AiAirlock.jsx} | 0 .../{AmmoWorkbench.js => AmmoWorkbench.jsx} | 0 ...AnomalyRefinery.js => AnomalyRefinery.jsx} | 0 ...gInfoSentient.js => AntagInfoSentient.jsx} | 0 .../{AntagInfoShade.js => AntagInfoShade.jsx} | 0 .../tgui/interfaces/{Apc.js => Apc.jsx} | 0 .../{ApcControl.js => ApcControl.jsx} | 0 ...ArmamentStation.js => ArmamentStation.jsx} | 0 ...sControlPanel.js => AtmosControlPanel.jsx} | 0 .../{BorerChem.js => BorerChem.jsx} | 0 .../{BorgPanel.js => BorgPanel.jsx} | 0 .../interfaces/{Canister.js => Canister.jsx} | 0 .../tgui/interfaces/{Cargo.js => Cargo.jsx} | 0 ...mportConsole.js => CargoImportConsole.jsx} | 0 ...mPodLauncher.js => CentcomPodLauncher.jsx} | 0 .../{ChameleonCard.js => ChameleonCard.jsx} | 0 .../{Changelog.js => Changelog.jsx} | 0 .../{ChemHeater.js => ChemHeater.jsx} | 0 .../{ChemPress.js => ChemPress.jsx} | 0 ...ChemRecipeDebug.js => ChemRecipeDebug.jsx} | 0 .../{CircuitModule.js => CircuitModule.jsx} | 0 ...ldTerminal.js => CivCargoHoldTerminal.jsx} | 0 .../{ClockworkSlab.js => ClockworkSlab.jsx} | 0 ...ortConsole.js => CommandReportConsole.jsx} | 0 ...nsConsole.js => CommunicationsConsole.jsx} | 0 .../{CrewConsole.js => CrewConsole.jsx} | 0 ...ConsoleSkyrat.js => CrewConsoleSkyrat.jsx} | 0 ...eld.js => CrewConsoleSkyratBlueshield.jsx} | 0 .../{CrewManifest.js => CrewManifest.jsx} | 0 .../tgui/interfaces/{Cryo.js => Cryo.jsx} | 0 .../{CryopodConsole.js => CryopodConsole.jsx} | 0 ...CyborgBootDebug.js => CyborgBootDebug.jsx} | 0 .../{DisposalUnit.js => DisposalUnit.jsx} | 0 ...onsoleEnzymes.js => DnaConsoleEnzymes.jsx} | 0 ...leSequencer.js => DnaConsoleSequencer.jsx} | 0 ...onsoleStorage.js => DnaConsoleStorage.jsx} | 0 .../{DnaScanner.js => DnaScanner.jsx} | 0 ...ticMakeupInfo.js => GeneticMakeupInfo.jsx} | 0 .../{MutationInfo.js => MutationInfo.jsx} | 0 .../DnaConsole/{constants.js => constants.ts} | 0 .../DnaConsole/{index.js => index.jsx} | 0 .../interfaces/{DnaVault.js => DnaVault.jsx} | 0 .../{DopplerArray.js => DopplerArray.jsx} | 0 .../{Electropack.js => Electropack.jsx} | 0 ...Console.js => EmergencyShuttleConsole.jsx} | 0 ...EngravedMessage.js => EngravedMessage.jsx} | 0 .../{EventPanel.js => EventPanel.jsx} | 0 .../{ExaminePanel.js => ExaminePanel.jsx} | 0 ...olConsole.js => ExosuitControlConsole.jsx} | 0 ...ntConfigure.js => ExperimentConfigure.jsx} | 0 .../{Filteriffic.js => Filteriffic.jsx} | 0 .../interfaces/{Gateway.js => Gateway.jsx} | 0 ...lProtection.js => GhostPoolProtection.jsx} | 0 .../tgui/interfaces/{Gps.js => Gps.jsx} | 0 ...avityGenerator.js => GravityGenerator.jsx} | 0 ...rConsole.js => GulagTeleporterConsole.jsx} | 0 .../interfaces/{Holodeck.js => Holodeck.jsx} | 0 .../interfaces/{Holopad.js => Holopad.jsx} | 0 .../{HypnoChair.js => HypnoChair.jsx} | 0 .../{ImplantChair.js => ImplantChair.jsx} | 0 .../{BasicInput.js => BasicInput.jsx} | 0 .../{CircuitInfo.js => CircuitInfo.jsx} | 0 .../{ComponentMenu.js => ComponentMenu.jsx} | 0 ...splayComponent.js => DisplayComponent.jsx} | 0 .../{DisplayName.js => DisplayName.jsx} | 0 ...ndamentalTypes.js => FundamentalTypes.jsx} | 0 ...ObjectComponent.js => ObjectComponent.jsx} | 0 .../IntegratedCircuit/{Port.js => Port.jsx} | 0 .../{VariableMenu.js => VariableMenu.jsx} | 0 .../{constants.js => constants.ts} | 0 .../IntegratedCircuit/{index.js => index.jsx} | 0 .../{Intellicard.js => Intellicard.jsx} | 0 .../{Interview.js => Interview.jsx} | 0 ...terviewManager.js => InterviewManager.jsx} | 0 .../interfaces/{Jukebox.js => Jukebox.jsx} | 0 .../{KeycardAuth.js => KeycardAuth.jsx} | 0 ...rClaimConsole.js => LaborClaimConsole.jsx} | 0 .../{LanguageMenu.js => LanguageMenu.jsx} | 0 ...unchpadConsole.js => LaunchpadConsole.jsx} | 0 .../{LibraryConsole.js => LibraryConsole.jsx} | 0 .../{LibraryScanner.js => LibraryScanner.jsx} | 0 .../{LibraryVisitor.js => LibraryVisitor.jsx} | 0 .../{Limbgrower.js => Limbgrower.jsx} | 0 .../{LoadoutManager.js => LoadoutManager.jsx} | 0 .../LuaEditor/{CallModal.js => CallModal.jsx} | 0 .../{ChunkViewModal.js => ChunkViewModal.jsx} | 0 .../{ListMapper.js => ListMapper.jsx} | 0 .../interfaces/LuaEditor/{Log.js => Log.jsx} | 0 ...ateSelectModal.js => StateSelectModal.jsx} | 0 .../{TaskManager.js => TaskManager.jsx} | 0 .../LuaEditor/{index.js => index.jsx} | 0 .../interfaces/{MODpaint.js => MODpaint.jsx} | 0 ...ePicker.js => MalfunctionModulePicker.jsx} | 0 ...DriverControl.js => MassDriverControl.jsx} | 0 .../interfaces/{MassSpec.js => MassSpec.jsx} | 0 ...owerConsole.js => MechBayPowerConsole.jsx} | 0 .../{MechpadConsole.js => MechpadConsole.jsx} | 0 .../{MedicalKiosk.js => MedicalKiosk.jsx} | 0 .../{MemoryPanel.js => MemoryPanel.jsx} | 0 ...unControl.js => MicrofusionGunControl.jsx} | 0 .../{Microscope.js => Microscope.jsx} | 0 .../{MilkingMachine.js => MilkingMachine.jsx} | 0 .../tgui/interfaces/{Mule.js => Mule.jsx} | 0 .../{Newscaster.js => Newscaster.jsx} | 0 .../interfaces/{NifPanel.js => NifPanel.jsx} | 0 .../{NifSoulPoem.js => NifSoulPoem.jsx} | 0 .../{NightmareInfo.js => NightmareInfo.jsx} | 0 ...erences.js => NotificationPreferences.jsx} | 0 .../{NtosArcade.js => NtosArcade.jsx} | 0 .../{NtosCamera.js => NtosCamera.jsx} | 0 .../interfaces/{NtosCard.js => NtosCard.jsx} | 0 tgui/packages/tgui/interfaces/NtosCargo.tsx | 2 +- ...osCrewManifest.js => NtosCrewManifest.jsx} | 0 ...Monitor.js => NtosCyborgRemoteMonitor.jsx} | 0 .../{NtosEmojipedia.js => NtosEmojipedia.jsx} | 0 ...NtosFileManager.js => NtosFileManager.jsx} | 0 .../{NtosJobManager.js => NtosJobManager.jsx} | 0 .../{NtosMODsuit.js => NtosMODsuit.jsx} | 0 .../interfaces/{NtosMain.js => NtosMain.jsx} | 0 .../{NtosNetChat.js => NtosNetChat.jsx} | 0 .../{NtosNetDos.js => NtosNetDos.jsx} | 0 ...NetDownloader.js => NtosNetDownloader.jsx} | 0 .../{NtosNetMonitor.js => NtosNetMonitor.jsx} | 0 ...NtosNewsArchive.js => NtosNewsArchive.jsx} | 0 ...fsoftCatalog.js => NtosNifsoftCatalog.jsx} | 0 ...NtosPhysScanner.js => NtosPhysScanner.jsx} | 0 ...raitPrinter.js => NtosPortraitPrinter.jsx} | 0 .../{NtosRecords.js => NtosRecords.jsx} | 0 ...NtosRoboControl.js => NtosRoboControl.jsx} | 0 .../{NtosRobotact.js => NtosRobotact.jsx} | 0 .../{NtosScipaper.js => NtosScipaper.jsx} | 0 ...osSkillTracker.js => NtosSkillTracker.jsx} | 0 tgui/packages/tgui/interfaces/NtosTechweb.tsx | 2 +- .../{NuclearBomb.js => NuclearBomb.jsx} | 0 ...atingComputer.js => OperatingComputer.jsx} | 0 ...ngForcePanel.js => OpposingForcePanel.jsx} | 0 ...ionMachine.js => OreRedemptionMachine.jsx} | 0 .../{OrionGame.js => OrionGame.jsx} | 0 .../{OutfitEditor.js => OutfitEditor.jsx} | 0 .../{OutfitManager.js => OutfitManager.jsx} | 0 ...PaintingMachine.js => PaintingMachine.jsx} | 0 ...Accelerator.js => ParticleAccelerator.jsx} | 0 .../{Photocopier.js => Photocopier.jsx} | 0 ...ableGenerator.js => PortableGenerator.jsx} | 0 .../{PortablePump.js => PortablePump.jsx} | 0 .../{PortableTurret.js => PortableTurret.jsx} | 0 .../{PortraitPicker.js => PortraitPicker.jsx} | 0 .../{PowerMonitor.js => PowerMonitor.jsx} | 0 .../{ProbingConsole.js => ProbingConsole.jsx} | 0 ...ProximitySensor.js => ProximitySensor.jsx} | 0 .../tgui/interfaces/{Radio.js => Radio.jsx} | 0 ...icrolaser.js => RadioactiveMicrolaser.jsx} | 0 .../interfaces/{Reagents.js => Reagents.jsx} | 0 .../{RecordManifest.js => RecordManifest.jsx} | 0 .../{ReligiousTool.js => ReligiousTool.jsx} | 0 ...RobotControl.js => RemoteRobotControl.jsx} | 0 .../{RequestManager.js => RequestManager.jsx} | 0 ...lConsole.js => RoboticsControlConsole.jsx} | 0 .../interfaces/{Roulette.js => Roulette.jsx} | 0 .../tgui/interfaces/{Safe.js => Safe.jsx} | 0 .../{ScannerGate.js => ScannerGate.jsx} | 0 .../interfaces/{Secrets.js => Secrets.jsx} | 0 ...SelectEquipment.js => SelectEquipment.jsx} | 0 ...eFunBalloon.js => SentienceFunBalloon.jsx} | 0 ...ControlPanel.js => ServerControlPanel.jsx} | 0 .../{ServerMonitor.js => ServerMonitor.jsx} | 0 .../{ShuttleConsole.js => ShuttleConsole.jsx} | 0 ...eManipulator.js => ShuttleManipulator.jsx} | 0 .../{Signalvib.js => Signalvib.jsx} | 0 .../{SkillPanel.js => SkillPanel.jsx} | 0 .../{SkillStation.js => SkillStation.jsx} | 0 .../interfaces/{Sleeper.js => Sleeper.jsx} | 0 ...imeBodySwapper.js => SlimeBodySwapper.jsx} | 0 .../tgui/interfaces/{Smes.js => Smes.jsx} | 0 .../{Soulcatcher.js => Soulcatcher.jsx} | 0 ...SoulcatcherUser.js => SoulcatcherUser.jsx} | 0 .../{SpaceHeater.js => SpaceHeater.jsx} | 0 ...StackingConsole.js => StackingConsole.jsx} | 0 ...lertConsole.js => StationAlertConsole.jsx} | 0 .../{SyndContractor.js => SyndContractor.jsx} | 0 .../tgui/interfaces/{Tank.js => Tank.jsx} | 0 .../{TankCompressor.js => TankCompressor.jsx} | 0 .../{TankDispenser.js => TankDispenser.jsx} | 0 .../interfaces/{Techweb.js => Techweb.jsx} | 0 .../{Telecomms.js => Telecomms.jsx} | 0 .../{Teleporter.js => Teleporter.jsx} | 0 .../{ThermoMachine.js => ThermoMachine.jsx} | 0 .../{Thermometer.js => Thermometer.jsx} | 0 .../{TimeClock.js => TimeClock.jsx} | 0 ...TrackedPlaytime.js => TrackedPlaytime.jsx} | 0 .../{TramControl.js => TramControl.jsx} | 0 .../{TransferValve.js => TransferValve.jsx} | 0 ...ophyAdminPanel.js => TrophyAdminPanel.jsx} | 0 .../{Trophycase.js => Trophycase.jsx} | 0 .../{AccessConfig.js => AccessConfig.jsx} | 0 .../common/{AccessList.js => AccessList.jsx} | 0 .../{BeakerContents.js => BeakerContents.jsx} | 0 ...oticeBox.js => InterfaceLockNoticeBox.jsx} | 0 .../{PortableAtmos.js => PortableAtmos.jsx} | 0 .../{ReagentLookup.js => ReagentLookup.jsx} | 0 .../{RecipeLookup.js => RecipeLookup.jsx} | 0 .../tgui/layouts/{Layout.js => Layout.jsx} | 0 .../layouts/{NtosWindow.js => NtosWindow.jsx} | 0 .../tgui/layouts/{Pane.js => Pane.jsx} | 0 .../tgui/layouts/{Window.js => Window.jsx} | 0 .../tgui/layouts/{index.js => index.ts} | 0 tgui/packages/tgui/routes.tsx | 4 +- tgui/webpack.config.js | 19 ++----- 268 files changed, 80 insertions(+), 38 deletions(-) rename tgui/packages/common/{keycodes.js => keycodes.ts} (100%) rename tgui/packages/tgui-panel/{Notifications.js => Notifications.jsx} (100%) rename tgui/packages/tgui-panel/{Panel.js => Panel.jsx} (100%) rename tgui/packages/tgui-panel/audio/{NowPlayingWidget.js => NowPlayingWidget.jsx} (100%) rename tgui/packages/tgui-panel/audio/{index.js => index.ts} (100%) rename tgui/packages/tgui-panel/chat/{ChatPageSettings.js => ChatPageSettings.jsx} (100%) rename tgui/packages/tgui-panel/chat/{ChatPanel.js => ChatPanel.jsx} (100%) rename tgui/packages/tgui-panel/chat/{ChatTabs.js => ChatTabs.jsx} (100%) rename tgui/packages/tgui-panel/chat/{constants.js => constants.ts} (100%) rename tgui/packages/tgui-panel/chat/{index.js => index.ts} (100%) rename tgui/packages/tgui-panel/game/{constants.js => constants.ts} (100%) rename tgui/packages/tgui-panel/game/{index.js => index.ts} (100%) rename tgui/packages/tgui-panel/ping/{PingIndicator.js => PingIndicator.jsx} (100%) rename tgui/packages/tgui-panel/ping/{constants.js => constants.ts} (100%) rename tgui/packages/tgui-panel/ping/{index.js => index.ts} (100%) rename tgui/packages/tgui-panel/settings/{SettingsPanel.js => SettingsPanel.jsx} (100%) rename tgui/packages/tgui-panel/settings/{constants.js => constants.ts} (100%) rename tgui/packages/tgui-panel/settings/{index.js => index.ts} (100%) rename tgui/packages/tgui/components/{Blink.js => Blink.jsx} (100%) rename tgui/packages/tgui/components/{BlockQuote.js => BlockQuote.jsx} (100%) rename tgui/packages/tgui/components/{Button.js => Button.jsx} (100%) rename tgui/packages/tgui/components/{ByondUi.js => ByondUi.jsx} (100%) rename tgui/packages/tgui/components/{Chart.js => Chart.jsx} (100%) rename tgui/packages/tgui/components/{Collapsible.js => Collapsible.jsx} (100%) rename tgui/packages/tgui/components/{ColorBox.js => ColorBox.jsx} (100%) rename tgui/packages/tgui/components/{Dimmer.js => Dimmer.jsx} (100%) rename tgui/packages/tgui/components/{Divider.js => Divider.jsx} (100%) rename tgui/packages/tgui/components/{DraggableControl.js => DraggableControl.jsx} (100%) create mode 100644 tgui/packages/tgui/components/FakeTerminal.jsx rename tgui/packages/tgui/components/{Grid.js => Grid.jsx} (100%) rename tgui/packages/tgui/components/{InfinitePlane.js => InfinitePlane.jsx} (100%) rename tgui/packages/tgui/components/{Input.js => Input.jsx} (100%) rename tgui/packages/tgui/components/{Knob.js => Knob.jsx} (100%) rename tgui/packages/tgui/components/{LabeledControls.js => LabeledControls.jsx} (100%) rename tgui/packages/tgui/components/{Modal.js => Modal.jsx} (100%) rename tgui/packages/tgui/components/{NoticeBox.js => NoticeBox.jsx} (100%) rename tgui/packages/tgui/components/{NumberInput.js => NumberInput.jsx} (100%) rename tgui/packages/tgui/components/{ProgressBar.js => ProgressBar.jsx} (100%) rename tgui/packages/tgui/components/{RestrictedInput.js => RestrictedInput.jsx} (100%) rename tgui/packages/tgui/components/{RoundGauge.js => RoundGauge.jsx} (100%) rename tgui/packages/tgui/components/{Slider.js => Slider.jsx} (100%) rename tgui/packages/tgui/components/{Table.js => Table.jsx} (100%) rename tgui/packages/tgui/components/{Tabs.js => Tabs.jsx} (100%) rename tgui/packages/tgui/components/{TextArea.js => TextArea.jsx} (100%) rename tgui/packages/tgui/components/{TimeDisplay.js => TimeDisplay.jsx} (100%) rename tgui/packages/tgui/components/{index.js => index.ts} (100%) rename tgui/packages/tgui/debug/{KitchenSink.js => KitchenSink.jsx} (100%) rename tgui/packages/tgui/debug/{index.js => index.ts} (100%) rename tgui/packages/tgui/interfaces/{AbductorConsole.js => AbductorConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{Achievements.js => Achievements.jsx} (100%) rename tgui/packages/tgui/interfaces/{AdminFax.js => AdminFax.jsx} (100%) rename tgui/packages/tgui/interfaces/{AdminPDA.js => AdminPDA.jsx} (100%) rename tgui/packages/tgui/interfaces/{AiAirlock.js => AiAirlock.jsx} (100%) rename tgui/packages/tgui/interfaces/{AmmoWorkbench.js => AmmoWorkbench.jsx} (100%) rename tgui/packages/tgui/interfaces/{AnomalyRefinery.js => AnomalyRefinery.jsx} (100%) rename tgui/packages/tgui/interfaces/{AntagInfoSentient.js => AntagInfoSentient.jsx} (100%) rename tgui/packages/tgui/interfaces/{AntagInfoShade.js => AntagInfoShade.jsx} (100%) rename tgui/packages/tgui/interfaces/{Apc.js => Apc.jsx} (100%) rename tgui/packages/tgui/interfaces/{ApcControl.js => ApcControl.jsx} (100%) rename tgui/packages/tgui/interfaces/{ArmamentStation.js => ArmamentStation.jsx} (100%) rename tgui/packages/tgui/interfaces/{AtmosControlPanel.js => AtmosControlPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{BorerChem.js => BorerChem.jsx} (100%) rename tgui/packages/tgui/interfaces/{BorgPanel.js => BorgPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{Canister.js => Canister.jsx} (100%) rename tgui/packages/tgui/interfaces/{Cargo.js => Cargo.jsx} (100%) rename tgui/packages/tgui/interfaces/{CargoImportConsole.js => CargoImportConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{CentcomPodLauncher.js => CentcomPodLauncher.jsx} (100%) rename tgui/packages/tgui/interfaces/{ChameleonCard.js => ChameleonCard.jsx} (100%) rename tgui/packages/tgui/interfaces/{Changelog.js => Changelog.jsx} (100%) rename tgui/packages/tgui/interfaces/{ChemHeater.js => ChemHeater.jsx} (100%) rename tgui/packages/tgui/interfaces/{ChemPress.js => ChemPress.jsx} (100%) rename tgui/packages/tgui/interfaces/{ChemRecipeDebug.js => ChemRecipeDebug.jsx} (100%) rename tgui/packages/tgui/interfaces/{CircuitModule.js => CircuitModule.jsx} (100%) rename tgui/packages/tgui/interfaces/{CivCargoHoldTerminal.js => CivCargoHoldTerminal.jsx} (100%) rename tgui/packages/tgui/interfaces/{ClockworkSlab.js => ClockworkSlab.jsx} (100%) rename tgui/packages/tgui/interfaces/{CommandReportConsole.js => CommandReportConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{CommunicationsConsole.js => CommunicationsConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{CrewConsole.js => CrewConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{CrewConsoleSkyrat.js => CrewConsoleSkyrat.jsx} (100%) rename tgui/packages/tgui/interfaces/{CrewConsoleSkyratBlueshield.js => CrewConsoleSkyratBlueshield.jsx} (100%) rename tgui/packages/tgui/interfaces/{CrewManifest.js => CrewManifest.jsx} (100%) rename tgui/packages/tgui/interfaces/{Cryo.js => Cryo.jsx} (100%) rename tgui/packages/tgui/interfaces/{CryopodConsole.js => CryopodConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{CyborgBootDebug.js => CyborgBootDebug.jsx} (100%) rename tgui/packages/tgui/interfaces/{DisposalUnit.js => DisposalUnit.jsx} (100%) rename tgui/packages/tgui/interfaces/DnaConsole/{DnaConsoleEnzymes.js => DnaConsoleEnzymes.jsx} (100%) rename tgui/packages/tgui/interfaces/DnaConsole/{DnaConsoleSequencer.js => DnaConsoleSequencer.jsx} (100%) rename tgui/packages/tgui/interfaces/DnaConsole/{DnaConsoleStorage.js => DnaConsoleStorage.jsx} (100%) rename tgui/packages/tgui/interfaces/DnaConsole/{DnaScanner.js => DnaScanner.jsx} (100%) rename tgui/packages/tgui/interfaces/DnaConsole/{GeneticMakeupInfo.js => GeneticMakeupInfo.jsx} (100%) rename tgui/packages/tgui/interfaces/DnaConsole/{MutationInfo.js => MutationInfo.jsx} (100%) rename tgui/packages/tgui/interfaces/DnaConsole/{constants.js => constants.ts} (100%) rename tgui/packages/tgui/interfaces/DnaConsole/{index.js => index.jsx} (100%) rename tgui/packages/tgui/interfaces/{DnaVault.js => DnaVault.jsx} (100%) rename tgui/packages/tgui/interfaces/{DopplerArray.js => DopplerArray.jsx} (100%) rename tgui/packages/tgui/interfaces/{Electropack.js => Electropack.jsx} (100%) rename tgui/packages/tgui/interfaces/{EmergencyShuttleConsole.js => EmergencyShuttleConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{EngravedMessage.js => EngravedMessage.jsx} (100%) rename tgui/packages/tgui/interfaces/{EventPanel.js => EventPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{ExaminePanel.js => ExaminePanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{ExosuitControlConsole.js => ExosuitControlConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{ExperimentConfigure.js => ExperimentConfigure.jsx} (100%) rename tgui/packages/tgui/interfaces/{Filteriffic.js => Filteriffic.jsx} (100%) rename tgui/packages/tgui/interfaces/{Gateway.js => Gateway.jsx} (100%) rename tgui/packages/tgui/interfaces/{GhostPoolProtection.js => GhostPoolProtection.jsx} (100%) rename tgui/packages/tgui/interfaces/{Gps.js => Gps.jsx} (100%) rename tgui/packages/tgui/interfaces/{GravityGenerator.js => GravityGenerator.jsx} (100%) rename tgui/packages/tgui/interfaces/{GulagTeleporterConsole.js => GulagTeleporterConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{Holodeck.js => Holodeck.jsx} (100%) rename tgui/packages/tgui/interfaces/{Holopad.js => Holopad.jsx} (100%) rename tgui/packages/tgui/interfaces/{HypnoChair.js => HypnoChair.jsx} (100%) rename tgui/packages/tgui/interfaces/{ImplantChair.js => ImplantChair.jsx} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{BasicInput.js => BasicInput.jsx} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{CircuitInfo.js => CircuitInfo.jsx} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{ComponentMenu.js => ComponentMenu.jsx} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{DisplayComponent.js => DisplayComponent.jsx} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{DisplayName.js => DisplayName.jsx} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{FundamentalTypes.js => FundamentalTypes.jsx} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{ObjectComponent.js => ObjectComponent.jsx} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{Port.js => Port.jsx} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{VariableMenu.js => VariableMenu.jsx} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{constants.js => constants.ts} (100%) rename tgui/packages/tgui/interfaces/IntegratedCircuit/{index.js => index.jsx} (100%) rename tgui/packages/tgui/interfaces/{Intellicard.js => Intellicard.jsx} (100%) rename tgui/packages/tgui/interfaces/{Interview.js => Interview.jsx} (100%) rename tgui/packages/tgui/interfaces/{InterviewManager.js => InterviewManager.jsx} (100%) rename tgui/packages/tgui/interfaces/{Jukebox.js => Jukebox.jsx} (100%) rename tgui/packages/tgui/interfaces/{KeycardAuth.js => KeycardAuth.jsx} (100%) rename tgui/packages/tgui/interfaces/{LaborClaimConsole.js => LaborClaimConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{LanguageMenu.js => LanguageMenu.jsx} (100%) rename tgui/packages/tgui/interfaces/{LaunchpadConsole.js => LaunchpadConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{LibraryConsole.js => LibraryConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{LibraryScanner.js => LibraryScanner.jsx} (100%) rename tgui/packages/tgui/interfaces/{LibraryVisitor.js => LibraryVisitor.jsx} (100%) rename tgui/packages/tgui/interfaces/{Limbgrower.js => Limbgrower.jsx} (100%) rename tgui/packages/tgui/interfaces/{LoadoutManager.js => LoadoutManager.jsx} (100%) rename tgui/packages/tgui/interfaces/LuaEditor/{CallModal.js => CallModal.jsx} (100%) rename tgui/packages/tgui/interfaces/LuaEditor/{ChunkViewModal.js => ChunkViewModal.jsx} (100%) rename tgui/packages/tgui/interfaces/LuaEditor/{ListMapper.js => ListMapper.jsx} (100%) rename tgui/packages/tgui/interfaces/LuaEditor/{Log.js => Log.jsx} (100%) rename tgui/packages/tgui/interfaces/LuaEditor/{StateSelectModal.js => StateSelectModal.jsx} (100%) rename tgui/packages/tgui/interfaces/LuaEditor/{TaskManager.js => TaskManager.jsx} (100%) rename tgui/packages/tgui/interfaces/LuaEditor/{index.js => index.jsx} (100%) rename tgui/packages/tgui/interfaces/{MODpaint.js => MODpaint.jsx} (100%) rename tgui/packages/tgui/interfaces/{MalfunctionModulePicker.js => MalfunctionModulePicker.jsx} (100%) rename tgui/packages/tgui/interfaces/{MassDriverControl.js => MassDriverControl.jsx} (100%) rename tgui/packages/tgui/interfaces/{MassSpec.js => MassSpec.jsx} (100%) rename tgui/packages/tgui/interfaces/{MechBayPowerConsole.js => MechBayPowerConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{MechpadConsole.js => MechpadConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{MedicalKiosk.js => MedicalKiosk.jsx} (100%) rename tgui/packages/tgui/interfaces/{MemoryPanel.js => MemoryPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{MicrofusionGunControl.js => MicrofusionGunControl.jsx} (100%) rename tgui/packages/tgui/interfaces/{Microscope.js => Microscope.jsx} (100%) rename tgui/packages/tgui/interfaces/{MilkingMachine.js => MilkingMachine.jsx} (100%) rename tgui/packages/tgui/interfaces/{Mule.js => Mule.jsx} (100%) rename tgui/packages/tgui/interfaces/{Newscaster.js => Newscaster.jsx} (100%) rename tgui/packages/tgui/interfaces/{NifPanel.js => NifPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{NifSoulPoem.js => NifSoulPoem.jsx} (100%) rename tgui/packages/tgui/interfaces/{NightmareInfo.js => NightmareInfo.jsx} (100%) rename tgui/packages/tgui/interfaces/{NotificationPreferences.js => NotificationPreferences.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosArcade.js => NtosArcade.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosCamera.js => NtosCamera.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosCard.js => NtosCard.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosCrewManifest.js => NtosCrewManifest.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosCyborgRemoteMonitor.js => NtosCyborgRemoteMonitor.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosEmojipedia.js => NtosEmojipedia.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosFileManager.js => NtosFileManager.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosJobManager.js => NtosJobManager.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosMODsuit.js => NtosMODsuit.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosMain.js => NtosMain.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosNetChat.js => NtosNetChat.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosNetDos.js => NtosNetDos.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosNetDownloader.js => NtosNetDownloader.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosNetMonitor.js => NtosNetMonitor.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosNewsArchive.js => NtosNewsArchive.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosNifsoftCatalog.js => NtosNifsoftCatalog.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosPhysScanner.js => NtosPhysScanner.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosPortraitPrinter.js => NtosPortraitPrinter.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosRecords.js => NtosRecords.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosRoboControl.js => NtosRoboControl.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosRobotact.js => NtosRobotact.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosScipaper.js => NtosScipaper.jsx} (100%) rename tgui/packages/tgui/interfaces/{NtosSkillTracker.js => NtosSkillTracker.jsx} (100%) rename tgui/packages/tgui/interfaces/{NuclearBomb.js => NuclearBomb.jsx} (100%) rename tgui/packages/tgui/interfaces/{OperatingComputer.js => OperatingComputer.jsx} (100%) rename tgui/packages/tgui/interfaces/{OpposingForcePanel.js => OpposingForcePanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{OreRedemptionMachine.js => OreRedemptionMachine.jsx} (100%) rename tgui/packages/tgui/interfaces/{OrionGame.js => OrionGame.jsx} (100%) rename tgui/packages/tgui/interfaces/{OutfitEditor.js => OutfitEditor.jsx} (100%) rename tgui/packages/tgui/interfaces/{OutfitManager.js => OutfitManager.jsx} (100%) rename tgui/packages/tgui/interfaces/{PaintingMachine.js => PaintingMachine.jsx} (100%) rename tgui/packages/tgui/interfaces/{ParticleAccelerator.js => ParticleAccelerator.jsx} (100%) rename tgui/packages/tgui/interfaces/{Photocopier.js => Photocopier.jsx} (100%) rename tgui/packages/tgui/interfaces/{PortableGenerator.js => PortableGenerator.jsx} (100%) rename tgui/packages/tgui/interfaces/{PortablePump.js => PortablePump.jsx} (100%) rename tgui/packages/tgui/interfaces/{PortableTurret.js => PortableTurret.jsx} (100%) rename tgui/packages/tgui/interfaces/{PortraitPicker.js => PortraitPicker.jsx} (100%) rename tgui/packages/tgui/interfaces/{PowerMonitor.js => PowerMonitor.jsx} (100%) rename tgui/packages/tgui/interfaces/{ProbingConsole.js => ProbingConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{ProximitySensor.js => ProximitySensor.jsx} (100%) rename tgui/packages/tgui/interfaces/{Radio.js => Radio.jsx} (100%) rename tgui/packages/tgui/interfaces/{RadioactiveMicrolaser.js => RadioactiveMicrolaser.jsx} (100%) rename tgui/packages/tgui/interfaces/{Reagents.js => Reagents.jsx} (100%) rename tgui/packages/tgui/interfaces/{RecordManifest.js => RecordManifest.jsx} (100%) rename tgui/packages/tgui/interfaces/{ReligiousTool.js => ReligiousTool.jsx} (100%) rename tgui/packages/tgui/interfaces/{RemoteRobotControl.js => RemoteRobotControl.jsx} (100%) rename tgui/packages/tgui/interfaces/{RequestManager.js => RequestManager.jsx} (100%) rename tgui/packages/tgui/interfaces/{RoboticsControlConsole.js => RoboticsControlConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{Roulette.js => Roulette.jsx} (100%) rename tgui/packages/tgui/interfaces/{Safe.js => Safe.jsx} (100%) rename tgui/packages/tgui/interfaces/{ScannerGate.js => ScannerGate.jsx} (100%) rename tgui/packages/tgui/interfaces/{Secrets.js => Secrets.jsx} (100%) rename tgui/packages/tgui/interfaces/{SelectEquipment.js => SelectEquipment.jsx} (100%) rename tgui/packages/tgui/interfaces/{SentienceFunBalloon.js => SentienceFunBalloon.jsx} (100%) rename tgui/packages/tgui/interfaces/{ServerControlPanel.js => ServerControlPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{ServerMonitor.js => ServerMonitor.jsx} (100%) rename tgui/packages/tgui/interfaces/{ShuttleConsole.js => ShuttleConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{ShuttleManipulator.js => ShuttleManipulator.jsx} (100%) rename tgui/packages/tgui/interfaces/{Signalvib.js => Signalvib.jsx} (100%) rename tgui/packages/tgui/interfaces/{SkillPanel.js => SkillPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{SkillStation.js => SkillStation.jsx} (100%) rename tgui/packages/tgui/interfaces/{Sleeper.js => Sleeper.jsx} (100%) rename tgui/packages/tgui/interfaces/{SlimeBodySwapper.js => SlimeBodySwapper.jsx} (100%) rename tgui/packages/tgui/interfaces/{Smes.js => Smes.jsx} (100%) rename tgui/packages/tgui/interfaces/{Soulcatcher.js => Soulcatcher.jsx} (100%) rename tgui/packages/tgui/interfaces/{SoulcatcherUser.js => SoulcatcherUser.jsx} (100%) rename tgui/packages/tgui/interfaces/{SpaceHeater.js => SpaceHeater.jsx} (100%) rename tgui/packages/tgui/interfaces/{StackingConsole.js => StackingConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{StationAlertConsole.js => StationAlertConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{SyndContractor.js => SyndContractor.jsx} (100%) rename tgui/packages/tgui/interfaces/{Tank.js => Tank.jsx} (100%) rename tgui/packages/tgui/interfaces/{TankCompressor.js => TankCompressor.jsx} (100%) rename tgui/packages/tgui/interfaces/{TankDispenser.js => TankDispenser.jsx} (100%) rename tgui/packages/tgui/interfaces/{Techweb.js => Techweb.jsx} (100%) rename tgui/packages/tgui/interfaces/{Telecomms.js => Telecomms.jsx} (100%) rename tgui/packages/tgui/interfaces/{Teleporter.js => Teleporter.jsx} (100%) rename tgui/packages/tgui/interfaces/{ThermoMachine.js => ThermoMachine.jsx} (100%) rename tgui/packages/tgui/interfaces/{Thermometer.js => Thermometer.jsx} (100%) rename tgui/packages/tgui/interfaces/{TimeClock.js => TimeClock.jsx} (100%) rename tgui/packages/tgui/interfaces/{TrackedPlaytime.js => TrackedPlaytime.jsx} (100%) rename tgui/packages/tgui/interfaces/{TramControl.js => TramControl.jsx} (100%) rename tgui/packages/tgui/interfaces/{TransferValve.js => TransferValve.jsx} (100%) rename tgui/packages/tgui/interfaces/{TrophyAdminPanel.js => TrophyAdminPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{Trophycase.js => Trophycase.jsx} (100%) rename tgui/packages/tgui/interfaces/common/{AccessConfig.js => AccessConfig.jsx} (100%) rename tgui/packages/tgui/interfaces/common/{AccessList.js => AccessList.jsx} (100%) rename tgui/packages/tgui/interfaces/common/{BeakerContents.js => BeakerContents.jsx} (100%) rename tgui/packages/tgui/interfaces/common/{InterfaceLockNoticeBox.js => InterfaceLockNoticeBox.jsx} (100%) rename tgui/packages/tgui/interfaces/common/{PortableAtmos.js => PortableAtmos.jsx} (100%) rename tgui/packages/tgui/interfaces/common/{ReagentLookup.js => ReagentLookup.jsx} (100%) rename tgui/packages/tgui/interfaces/common/{RecipeLookup.js => RecipeLookup.jsx} (100%) rename tgui/packages/tgui/layouts/{Layout.js => Layout.jsx} (100%) rename tgui/packages/tgui/layouts/{NtosWindow.js => NtosWindow.jsx} (100%) rename tgui/packages/tgui/layouts/{Pane.js => Pane.jsx} (100%) rename tgui/packages/tgui/layouts/{Window.js => Window.jsx} (100%) rename tgui/packages/tgui/layouts/{index.js => index.ts} (100%) diff --git a/tgui/packages/common/keycodes.js b/tgui/packages/common/keycodes.ts similarity index 100% rename from tgui/packages/common/keycodes.js rename to tgui/packages/common/keycodes.ts diff --git a/tgui/packages/tgui-dev-server/dreamseeker.js b/tgui/packages/tgui-dev-server/dreamseeker.js index 2b25b155ae0..c81f51e35c5 100644 --- a/tgui/packages/tgui-dev-server/dreamseeker.js +++ b/tgui/packages/tgui-dev-server/dreamseeker.js @@ -6,8 +6,8 @@ import { exec } from 'child_process'; import { promisify } from 'util'; -import { createLogger } from './logging.js'; -import { require } from './require.js'; +import { createLogger } from './logging'; +import { require } from './require'; const axios = require('axios'); const logger = createLogger('dreamseeker'); diff --git a/tgui/packages/tgui-dev-server/index.js b/tgui/packages/tgui-dev-server/index.js index 199e93d8363..460b15d99ad 100644 --- a/tgui/packages/tgui-dev-server/index.js +++ b/tgui/packages/tgui-dev-server/index.js @@ -4,8 +4,8 @@ * @license MIT */ -import { createCompiler } from './webpack.js'; -import { reloadByondCache } from './reloader.js'; +import { createCompiler } from './webpack'; +import { reloadByondCache } from './reloader'; const noHot = process.argv.includes('--no-hot'); const noTmp = process.argv.includes('--no-tmp'); diff --git a/tgui/packages/tgui-dev-server/link/retrace.js b/tgui/packages/tgui-dev-server/link/retrace.js index 842de228fdf..949835c7002 100644 --- a/tgui/packages/tgui-dev-server/link/retrace.js +++ b/tgui/packages/tgui-dev-server/link/retrace.js @@ -6,9 +6,9 @@ import fs from 'fs'; import { basename } from 'path'; -import { createLogger } from '../logging.js'; -import { require } from '../require.js'; -import { resolveGlob } from '../util.js'; +import { createLogger } from '../logging'; +import { require } from '../require'; +import { resolveGlob } from '../util'; const SourceMap = require('source-map'); const { parse: parseStackTrace } = require('stacktrace-parser'); diff --git a/tgui/packages/tgui-dev-server/link/server.js b/tgui/packages/tgui-dev-server/link/server.js index 60cc78c1bd9..f0c0d153d3a 100644 --- a/tgui/packages/tgui-dev-server/link/server.js +++ b/tgui/packages/tgui-dev-server/link/server.js @@ -6,9 +6,9 @@ import http from 'http'; import { inspect } from 'util'; -import { createLogger, directLog } from '../logging.js'; -import { require } from '../require.js'; -import { loadSourceMaps, retrace } from './retrace.js'; +import { createLogger, directLog } from '../logging'; +import { require } from '../require'; +import { loadSourceMaps, retrace } from './retrace'; const WebSocket = require('ws'); diff --git a/tgui/packages/tgui-dev-server/reloader.js b/tgui/packages/tgui-dev-server/reloader.js index c13a8afdfcf..aed9a7dcd77 100644 --- a/tgui/packages/tgui-dev-server/reloader.js +++ b/tgui/packages/tgui-dev-server/reloader.js @@ -7,10 +7,10 @@ import fs from 'fs'; import os from 'os'; import { basename } from 'path'; -import { DreamSeeker } from './dreamseeker.js'; -import { createLogger } from './logging.js'; -import { resolveGlob, resolvePath } from './util.js'; -import { regQuery } from './winreg.js'; +import { DreamSeeker } from './dreamseeker'; +import { createLogger } from './logging'; +import { resolveGlob, resolvePath } from './util'; +import { regQuery } from './winreg'; const logger = createLogger('reloader'); diff --git a/tgui/packages/tgui-dev-server/util.js b/tgui/packages/tgui-dev-server/util.js index 9d07b96c71a..d60ebb212fa 100644 --- a/tgui/packages/tgui-dev-server/util.js +++ b/tgui/packages/tgui-dev-server/util.js @@ -6,7 +6,7 @@ import fs from 'fs'; import path from 'path'; -import { require } from './require.js'; +import { require } from './require'; const globPkg = require('glob'); diff --git a/tgui/packages/tgui-dev-server/webpack.js b/tgui/packages/tgui-dev-server/webpack.js index 139610b79ce..1c16345a892 100644 --- a/tgui/packages/tgui-dev-server/webpack.js +++ b/tgui/packages/tgui-dev-server/webpack.js @@ -7,10 +7,10 @@ import fs from 'fs'; import { createRequire } from 'module'; import { dirname } from 'path'; -import { loadSourceMaps, setupLink } from './link/server.js'; -import { createLogger } from './logging.js'; -import { reloadByondCache } from './reloader.js'; -import { resolveGlob } from './util.js'; +import { loadSourceMaps, setupLink } from './link/server'; +import { createLogger } from './logging'; +import { reloadByondCache } from './reloader'; +import { resolveGlob } from './util'; const logger = createLogger('webpack'); diff --git a/tgui/packages/tgui-dev-server/winreg.js b/tgui/packages/tgui-dev-server/winreg.js index b61fddc1a25..d7408b5c390 100644 --- a/tgui/packages/tgui-dev-server/winreg.js +++ b/tgui/packages/tgui-dev-server/winreg.js @@ -8,7 +8,7 @@ import { exec } from 'child_process'; import { promisify } from 'util'; -import { createLogger } from './logging.js'; +import { createLogger } from './logging'; const logger = createLogger('winreg'); diff --git a/tgui/packages/tgui-panel/Notifications.js b/tgui/packages/tgui-panel/Notifications.jsx similarity index 100% rename from tgui/packages/tgui-panel/Notifications.js rename to tgui/packages/tgui-panel/Notifications.jsx diff --git a/tgui/packages/tgui-panel/Panel.js b/tgui/packages/tgui-panel/Panel.jsx similarity index 100% rename from tgui/packages/tgui-panel/Panel.js rename to tgui/packages/tgui-panel/Panel.jsx diff --git a/tgui/packages/tgui-panel/audio/NowPlayingWidget.js b/tgui/packages/tgui-panel/audio/NowPlayingWidget.jsx similarity index 100% rename from tgui/packages/tgui-panel/audio/NowPlayingWidget.js rename to tgui/packages/tgui-panel/audio/NowPlayingWidget.jsx diff --git a/tgui/packages/tgui-panel/audio/index.js b/tgui/packages/tgui-panel/audio/index.ts similarity index 100% rename from tgui/packages/tgui-panel/audio/index.js rename to tgui/packages/tgui-panel/audio/index.ts diff --git a/tgui/packages/tgui-panel/chat/ChatPageSettings.js b/tgui/packages/tgui-panel/chat/ChatPageSettings.jsx similarity index 100% rename from tgui/packages/tgui-panel/chat/ChatPageSettings.js rename to tgui/packages/tgui-panel/chat/ChatPageSettings.jsx diff --git a/tgui/packages/tgui-panel/chat/ChatPanel.js b/tgui/packages/tgui-panel/chat/ChatPanel.jsx similarity index 100% rename from tgui/packages/tgui-panel/chat/ChatPanel.js rename to tgui/packages/tgui-panel/chat/ChatPanel.jsx diff --git a/tgui/packages/tgui-panel/chat/ChatTabs.js b/tgui/packages/tgui-panel/chat/ChatTabs.jsx similarity index 100% rename from tgui/packages/tgui-panel/chat/ChatTabs.js rename to tgui/packages/tgui-panel/chat/ChatTabs.jsx diff --git a/tgui/packages/tgui-panel/chat/constants.js b/tgui/packages/tgui-panel/chat/constants.ts similarity index 100% rename from tgui/packages/tgui-panel/chat/constants.js rename to tgui/packages/tgui-panel/chat/constants.ts diff --git a/tgui/packages/tgui-panel/chat/index.js b/tgui/packages/tgui-panel/chat/index.ts similarity index 100% rename from tgui/packages/tgui-panel/chat/index.js rename to tgui/packages/tgui-panel/chat/index.ts diff --git a/tgui/packages/tgui-panel/game/constants.js b/tgui/packages/tgui-panel/game/constants.ts similarity index 100% rename from tgui/packages/tgui-panel/game/constants.js rename to tgui/packages/tgui-panel/game/constants.ts diff --git a/tgui/packages/tgui-panel/game/index.js b/tgui/packages/tgui-panel/game/index.ts similarity index 100% rename from tgui/packages/tgui-panel/game/index.js rename to tgui/packages/tgui-panel/game/index.ts diff --git a/tgui/packages/tgui-panel/ping/PingIndicator.js b/tgui/packages/tgui-panel/ping/PingIndicator.jsx similarity index 100% rename from tgui/packages/tgui-panel/ping/PingIndicator.js rename to tgui/packages/tgui-panel/ping/PingIndicator.jsx diff --git a/tgui/packages/tgui-panel/ping/constants.js b/tgui/packages/tgui-panel/ping/constants.ts similarity index 100% rename from tgui/packages/tgui-panel/ping/constants.js rename to tgui/packages/tgui-panel/ping/constants.ts diff --git a/tgui/packages/tgui-panel/ping/index.js b/tgui/packages/tgui-panel/ping/index.ts similarity index 100% rename from tgui/packages/tgui-panel/ping/index.js rename to tgui/packages/tgui-panel/ping/index.ts diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.js b/tgui/packages/tgui-panel/settings/SettingsPanel.jsx similarity index 100% rename from tgui/packages/tgui-panel/settings/SettingsPanel.js rename to tgui/packages/tgui-panel/settings/SettingsPanel.jsx diff --git a/tgui/packages/tgui-panel/settings/constants.js b/tgui/packages/tgui-panel/settings/constants.ts similarity index 100% rename from tgui/packages/tgui-panel/settings/constants.js rename to tgui/packages/tgui-panel/settings/constants.ts diff --git a/tgui/packages/tgui-panel/settings/index.js b/tgui/packages/tgui-panel/settings/index.ts similarity index 100% rename from tgui/packages/tgui-panel/settings/index.js rename to tgui/packages/tgui-panel/settings/index.ts diff --git a/tgui/packages/tgui/components/Blink.js b/tgui/packages/tgui/components/Blink.jsx similarity index 100% rename from tgui/packages/tgui/components/Blink.js rename to tgui/packages/tgui/components/Blink.jsx diff --git a/tgui/packages/tgui/components/BlockQuote.js b/tgui/packages/tgui/components/BlockQuote.jsx similarity index 100% rename from tgui/packages/tgui/components/BlockQuote.js rename to tgui/packages/tgui/components/BlockQuote.jsx diff --git a/tgui/packages/tgui/components/Button.js b/tgui/packages/tgui/components/Button.jsx similarity index 100% rename from tgui/packages/tgui/components/Button.js rename to tgui/packages/tgui/components/Button.jsx diff --git a/tgui/packages/tgui/components/ByondUi.js b/tgui/packages/tgui/components/ByondUi.jsx similarity index 100% rename from tgui/packages/tgui/components/ByondUi.js rename to tgui/packages/tgui/components/ByondUi.jsx diff --git a/tgui/packages/tgui/components/Chart.js b/tgui/packages/tgui/components/Chart.jsx similarity index 100% rename from tgui/packages/tgui/components/Chart.js rename to tgui/packages/tgui/components/Chart.jsx diff --git a/tgui/packages/tgui/components/Collapsible.js b/tgui/packages/tgui/components/Collapsible.jsx similarity index 100% rename from tgui/packages/tgui/components/Collapsible.js rename to tgui/packages/tgui/components/Collapsible.jsx diff --git a/tgui/packages/tgui/components/ColorBox.js b/tgui/packages/tgui/components/ColorBox.jsx similarity index 100% rename from tgui/packages/tgui/components/ColorBox.js rename to tgui/packages/tgui/components/ColorBox.jsx diff --git a/tgui/packages/tgui/components/Dimmer.js b/tgui/packages/tgui/components/Dimmer.jsx similarity index 100% rename from tgui/packages/tgui/components/Dimmer.js rename to tgui/packages/tgui/components/Dimmer.jsx diff --git a/tgui/packages/tgui/components/Divider.js b/tgui/packages/tgui/components/Divider.jsx similarity index 100% rename from tgui/packages/tgui/components/Divider.js rename to tgui/packages/tgui/components/Divider.jsx diff --git a/tgui/packages/tgui/components/DraggableControl.js b/tgui/packages/tgui/components/DraggableControl.jsx similarity index 100% rename from tgui/packages/tgui/components/DraggableControl.js rename to tgui/packages/tgui/components/DraggableControl.jsx diff --git a/tgui/packages/tgui/components/FakeTerminal.jsx b/tgui/packages/tgui/components/FakeTerminal.jsx new file mode 100644 index 00000000000..d6479a25796 --- /dev/null +++ b/tgui/packages/tgui/components/FakeTerminal.jsx @@ -0,0 +1,51 @@ +import { Box } from './Box'; +import { Component, Fragment } from 'inferno'; + +export class FakeTerminal extends Component { + constructor(props) { + super(props); + this.timer = null; + this.state = { + currentIndex: 0, + currentDisplay: [], + }; + } + + tick() { + const { props, state } = this; + if (state.currentIndex <= props.allMessages.length) { + this.setState((prevState) => { + return { + currentIndex: prevState.currentIndex + 1, + }; + }); + const { currentDisplay } = state; + currentDisplay.push(props.allMessages[state.currentIndex]); + } else { + clearTimeout(this.timer); + setTimeout(props.onFinished, props.finishedTimeout); + } + } + + componentDidMount() { + const { linesPerSecond = 2.5 } = this.props; + this.timer = setInterval(() => this.tick(), 1000 / linesPerSecond); + } + + componentWillUnmount() { + clearTimeout(this.timer); + } + + render() { + return ( + + {this.state.currentDisplay.map((value) => ( + + {value} +
+
+ ))} +
+ ); + } +} diff --git a/tgui/packages/tgui/components/Grid.js b/tgui/packages/tgui/components/Grid.jsx similarity index 100% rename from tgui/packages/tgui/components/Grid.js rename to tgui/packages/tgui/components/Grid.jsx diff --git a/tgui/packages/tgui/components/InfinitePlane.js b/tgui/packages/tgui/components/InfinitePlane.jsx similarity index 100% rename from tgui/packages/tgui/components/InfinitePlane.js rename to tgui/packages/tgui/components/InfinitePlane.jsx diff --git a/tgui/packages/tgui/components/Input.js b/tgui/packages/tgui/components/Input.jsx similarity index 100% rename from tgui/packages/tgui/components/Input.js rename to tgui/packages/tgui/components/Input.jsx diff --git a/tgui/packages/tgui/components/Knob.js b/tgui/packages/tgui/components/Knob.jsx similarity index 100% rename from tgui/packages/tgui/components/Knob.js rename to tgui/packages/tgui/components/Knob.jsx diff --git a/tgui/packages/tgui/components/LabeledControls.js b/tgui/packages/tgui/components/LabeledControls.jsx similarity index 100% rename from tgui/packages/tgui/components/LabeledControls.js rename to tgui/packages/tgui/components/LabeledControls.jsx diff --git a/tgui/packages/tgui/components/Modal.js b/tgui/packages/tgui/components/Modal.jsx similarity index 100% rename from tgui/packages/tgui/components/Modal.js rename to tgui/packages/tgui/components/Modal.jsx diff --git a/tgui/packages/tgui/components/NoticeBox.js b/tgui/packages/tgui/components/NoticeBox.jsx similarity index 100% rename from tgui/packages/tgui/components/NoticeBox.js rename to tgui/packages/tgui/components/NoticeBox.jsx diff --git a/tgui/packages/tgui/components/NumberInput.js b/tgui/packages/tgui/components/NumberInput.jsx similarity index 100% rename from tgui/packages/tgui/components/NumberInput.js rename to tgui/packages/tgui/components/NumberInput.jsx diff --git a/tgui/packages/tgui/components/ProgressBar.js b/tgui/packages/tgui/components/ProgressBar.jsx similarity index 100% rename from tgui/packages/tgui/components/ProgressBar.js rename to tgui/packages/tgui/components/ProgressBar.jsx diff --git a/tgui/packages/tgui/components/RestrictedInput.js b/tgui/packages/tgui/components/RestrictedInput.jsx similarity index 100% rename from tgui/packages/tgui/components/RestrictedInput.js rename to tgui/packages/tgui/components/RestrictedInput.jsx diff --git a/tgui/packages/tgui/components/RoundGauge.js b/tgui/packages/tgui/components/RoundGauge.jsx similarity index 100% rename from tgui/packages/tgui/components/RoundGauge.js rename to tgui/packages/tgui/components/RoundGauge.jsx diff --git a/tgui/packages/tgui/components/Slider.js b/tgui/packages/tgui/components/Slider.jsx similarity index 100% rename from tgui/packages/tgui/components/Slider.js rename to tgui/packages/tgui/components/Slider.jsx diff --git a/tgui/packages/tgui/components/Table.js b/tgui/packages/tgui/components/Table.jsx similarity index 100% rename from tgui/packages/tgui/components/Table.js rename to tgui/packages/tgui/components/Table.jsx diff --git a/tgui/packages/tgui/components/Tabs.js b/tgui/packages/tgui/components/Tabs.jsx similarity index 100% rename from tgui/packages/tgui/components/Tabs.js rename to tgui/packages/tgui/components/Tabs.jsx diff --git a/tgui/packages/tgui/components/TextArea.js b/tgui/packages/tgui/components/TextArea.jsx similarity index 100% rename from tgui/packages/tgui/components/TextArea.js rename to tgui/packages/tgui/components/TextArea.jsx diff --git a/tgui/packages/tgui/components/TimeDisplay.js b/tgui/packages/tgui/components/TimeDisplay.jsx similarity index 100% rename from tgui/packages/tgui/components/TimeDisplay.js rename to tgui/packages/tgui/components/TimeDisplay.jsx diff --git a/tgui/packages/tgui/components/index.js b/tgui/packages/tgui/components/index.ts similarity index 100% rename from tgui/packages/tgui/components/index.js rename to tgui/packages/tgui/components/index.ts diff --git a/tgui/packages/tgui/debug/KitchenSink.js b/tgui/packages/tgui/debug/KitchenSink.jsx similarity index 100% rename from tgui/packages/tgui/debug/KitchenSink.js rename to tgui/packages/tgui/debug/KitchenSink.jsx diff --git a/tgui/packages/tgui/debug/index.js b/tgui/packages/tgui/debug/index.ts similarity index 100% rename from tgui/packages/tgui/debug/index.js rename to tgui/packages/tgui/debug/index.ts diff --git a/tgui/packages/tgui/interfaces/AbductorConsole.js b/tgui/packages/tgui/interfaces/AbductorConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AbductorConsole.js rename to tgui/packages/tgui/interfaces/AbductorConsole.jsx diff --git a/tgui/packages/tgui/interfaces/Achievements.js b/tgui/packages/tgui/interfaces/Achievements.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Achievements.js rename to tgui/packages/tgui/interfaces/Achievements.jsx diff --git a/tgui/packages/tgui/interfaces/AdminFax.js b/tgui/packages/tgui/interfaces/AdminFax.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AdminFax.js rename to tgui/packages/tgui/interfaces/AdminFax.jsx diff --git a/tgui/packages/tgui/interfaces/AdminPDA.js b/tgui/packages/tgui/interfaces/AdminPDA.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AdminPDA.js rename to tgui/packages/tgui/interfaces/AdminPDA.jsx diff --git a/tgui/packages/tgui/interfaces/AiAirlock.js b/tgui/packages/tgui/interfaces/AiAirlock.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AiAirlock.js rename to tgui/packages/tgui/interfaces/AiAirlock.jsx diff --git a/tgui/packages/tgui/interfaces/AmmoWorkbench.js b/tgui/packages/tgui/interfaces/AmmoWorkbench.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AmmoWorkbench.js rename to tgui/packages/tgui/interfaces/AmmoWorkbench.jsx diff --git a/tgui/packages/tgui/interfaces/AnomalyRefinery.js b/tgui/packages/tgui/interfaces/AnomalyRefinery.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AnomalyRefinery.js rename to tgui/packages/tgui/interfaces/AnomalyRefinery.jsx diff --git a/tgui/packages/tgui/interfaces/AntagInfoSentient.js b/tgui/packages/tgui/interfaces/AntagInfoSentient.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AntagInfoSentient.js rename to tgui/packages/tgui/interfaces/AntagInfoSentient.jsx diff --git a/tgui/packages/tgui/interfaces/AntagInfoShade.js b/tgui/packages/tgui/interfaces/AntagInfoShade.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AntagInfoShade.js rename to tgui/packages/tgui/interfaces/AntagInfoShade.jsx diff --git a/tgui/packages/tgui/interfaces/Apc.js b/tgui/packages/tgui/interfaces/Apc.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Apc.js rename to tgui/packages/tgui/interfaces/Apc.jsx diff --git a/tgui/packages/tgui/interfaces/ApcControl.js b/tgui/packages/tgui/interfaces/ApcControl.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ApcControl.js rename to tgui/packages/tgui/interfaces/ApcControl.jsx diff --git a/tgui/packages/tgui/interfaces/ArmamentStation.js b/tgui/packages/tgui/interfaces/ArmamentStation.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ArmamentStation.js rename to tgui/packages/tgui/interfaces/ArmamentStation.jsx diff --git a/tgui/packages/tgui/interfaces/AtmosControlPanel.js b/tgui/packages/tgui/interfaces/AtmosControlPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AtmosControlPanel.js rename to tgui/packages/tgui/interfaces/AtmosControlPanel.jsx diff --git a/tgui/packages/tgui/interfaces/BorerChem.js b/tgui/packages/tgui/interfaces/BorerChem.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/BorerChem.js rename to tgui/packages/tgui/interfaces/BorerChem.jsx diff --git a/tgui/packages/tgui/interfaces/BorgPanel.js b/tgui/packages/tgui/interfaces/BorgPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/BorgPanel.js rename to tgui/packages/tgui/interfaces/BorgPanel.jsx diff --git a/tgui/packages/tgui/interfaces/Canister.js b/tgui/packages/tgui/interfaces/Canister.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Canister.js rename to tgui/packages/tgui/interfaces/Canister.jsx diff --git a/tgui/packages/tgui/interfaces/Cargo.js b/tgui/packages/tgui/interfaces/Cargo.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Cargo.js rename to tgui/packages/tgui/interfaces/Cargo.jsx diff --git a/tgui/packages/tgui/interfaces/CargoImportConsole.js b/tgui/packages/tgui/interfaces/CargoImportConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CargoImportConsole.js rename to tgui/packages/tgui/interfaces/CargoImportConsole.jsx diff --git a/tgui/packages/tgui/interfaces/CentcomPodLauncher.js b/tgui/packages/tgui/interfaces/CentcomPodLauncher.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CentcomPodLauncher.js rename to tgui/packages/tgui/interfaces/CentcomPodLauncher.jsx diff --git a/tgui/packages/tgui/interfaces/ChameleonCard.js b/tgui/packages/tgui/interfaces/ChameleonCard.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ChameleonCard.js rename to tgui/packages/tgui/interfaces/ChameleonCard.jsx diff --git a/tgui/packages/tgui/interfaces/Changelog.js b/tgui/packages/tgui/interfaces/Changelog.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Changelog.js rename to tgui/packages/tgui/interfaces/Changelog.jsx diff --git a/tgui/packages/tgui/interfaces/ChemHeater.js b/tgui/packages/tgui/interfaces/ChemHeater.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ChemHeater.js rename to tgui/packages/tgui/interfaces/ChemHeater.jsx diff --git a/tgui/packages/tgui/interfaces/ChemPress.js b/tgui/packages/tgui/interfaces/ChemPress.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ChemPress.js rename to tgui/packages/tgui/interfaces/ChemPress.jsx diff --git a/tgui/packages/tgui/interfaces/ChemRecipeDebug.js b/tgui/packages/tgui/interfaces/ChemRecipeDebug.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ChemRecipeDebug.js rename to tgui/packages/tgui/interfaces/ChemRecipeDebug.jsx diff --git a/tgui/packages/tgui/interfaces/CircuitModule.js b/tgui/packages/tgui/interfaces/CircuitModule.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CircuitModule.js rename to tgui/packages/tgui/interfaces/CircuitModule.jsx diff --git a/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.js b/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CivCargoHoldTerminal.js rename to tgui/packages/tgui/interfaces/CivCargoHoldTerminal.jsx diff --git a/tgui/packages/tgui/interfaces/ClockworkSlab.js b/tgui/packages/tgui/interfaces/ClockworkSlab.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ClockworkSlab.js rename to tgui/packages/tgui/interfaces/ClockworkSlab.jsx diff --git a/tgui/packages/tgui/interfaces/CommandReportConsole.js b/tgui/packages/tgui/interfaces/CommandReportConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CommandReportConsole.js rename to tgui/packages/tgui/interfaces/CommandReportConsole.jsx diff --git a/tgui/packages/tgui/interfaces/CommunicationsConsole.js b/tgui/packages/tgui/interfaces/CommunicationsConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CommunicationsConsole.js rename to tgui/packages/tgui/interfaces/CommunicationsConsole.jsx diff --git a/tgui/packages/tgui/interfaces/CrewConsole.js b/tgui/packages/tgui/interfaces/CrewConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CrewConsole.js rename to tgui/packages/tgui/interfaces/CrewConsole.jsx diff --git a/tgui/packages/tgui/interfaces/CrewConsoleSkyrat.js b/tgui/packages/tgui/interfaces/CrewConsoleSkyrat.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CrewConsoleSkyrat.js rename to tgui/packages/tgui/interfaces/CrewConsoleSkyrat.jsx diff --git a/tgui/packages/tgui/interfaces/CrewConsoleSkyratBlueshield.js b/tgui/packages/tgui/interfaces/CrewConsoleSkyratBlueshield.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CrewConsoleSkyratBlueshield.js rename to tgui/packages/tgui/interfaces/CrewConsoleSkyratBlueshield.jsx diff --git a/tgui/packages/tgui/interfaces/CrewManifest.js b/tgui/packages/tgui/interfaces/CrewManifest.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CrewManifest.js rename to tgui/packages/tgui/interfaces/CrewManifest.jsx diff --git a/tgui/packages/tgui/interfaces/Cryo.js b/tgui/packages/tgui/interfaces/Cryo.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Cryo.js rename to tgui/packages/tgui/interfaces/Cryo.jsx diff --git a/tgui/packages/tgui/interfaces/CryopodConsole.js b/tgui/packages/tgui/interfaces/CryopodConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CryopodConsole.js rename to tgui/packages/tgui/interfaces/CryopodConsole.jsx diff --git a/tgui/packages/tgui/interfaces/CyborgBootDebug.js b/tgui/packages/tgui/interfaces/CyborgBootDebug.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CyborgBootDebug.js rename to tgui/packages/tgui/interfaces/CyborgBootDebug.jsx diff --git a/tgui/packages/tgui/interfaces/DisposalUnit.js b/tgui/packages/tgui/interfaces/DisposalUnit.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DisposalUnit.js rename to tgui/packages/tgui/interfaces/DisposalUnit.jsx diff --git a/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleEnzymes.js b/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleEnzymes.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleEnzymes.js rename to tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleEnzymes.jsx diff --git a/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleSequencer.js b/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleSequencer.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleSequencer.js rename to tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleSequencer.jsx diff --git a/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleStorage.js b/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleStorage.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleStorage.js rename to tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleStorage.jsx diff --git a/tgui/packages/tgui/interfaces/DnaConsole/DnaScanner.js b/tgui/packages/tgui/interfaces/DnaConsole/DnaScanner.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DnaConsole/DnaScanner.js rename to tgui/packages/tgui/interfaces/DnaConsole/DnaScanner.jsx diff --git a/tgui/packages/tgui/interfaces/DnaConsole/GeneticMakeupInfo.js b/tgui/packages/tgui/interfaces/DnaConsole/GeneticMakeupInfo.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DnaConsole/GeneticMakeupInfo.js rename to tgui/packages/tgui/interfaces/DnaConsole/GeneticMakeupInfo.jsx diff --git a/tgui/packages/tgui/interfaces/DnaConsole/MutationInfo.js b/tgui/packages/tgui/interfaces/DnaConsole/MutationInfo.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DnaConsole/MutationInfo.js rename to tgui/packages/tgui/interfaces/DnaConsole/MutationInfo.jsx diff --git a/tgui/packages/tgui/interfaces/DnaConsole/constants.js b/tgui/packages/tgui/interfaces/DnaConsole/constants.ts similarity index 100% rename from tgui/packages/tgui/interfaces/DnaConsole/constants.js rename to tgui/packages/tgui/interfaces/DnaConsole/constants.ts diff --git a/tgui/packages/tgui/interfaces/DnaConsole/index.js b/tgui/packages/tgui/interfaces/DnaConsole/index.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DnaConsole/index.js rename to tgui/packages/tgui/interfaces/DnaConsole/index.jsx diff --git a/tgui/packages/tgui/interfaces/DnaVault.js b/tgui/packages/tgui/interfaces/DnaVault.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DnaVault.js rename to tgui/packages/tgui/interfaces/DnaVault.jsx diff --git a/tgui/packages/tgui/interfaces/DopplerArray.js b/tgui/packages/tgui/interfaces/DopplerArray.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DopplerArray.js rename to tgui/packages/tgui/interfaces/DopplerArray.jsx diff --git a/tgui/packages/tgui/interfaces/Electropack.js b/tgui/packages/tgui/interfaces/Electropack.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Electropack.js rename to tgui/packages/tgui/interfaces/Electropack.jsx diff --git a/tgui/packages/tgui/interfaces/EmergencyShuttleConsole.js b/tgui/packages/tgui/interfaces/EmergencyShuttleConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/EmergencyShuttleConsole.js rename to tgui/packages/tgui/interfaces/EmergencyShuttleConsole.jsx diff --git a/tgui/packages/tgui/interfaces/EngravedMessage.js b/tgui/packages/tgui/interfaces/EngravedMessage.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/EngravedMessage.js rename to tgui/packages/tgui/interfaces/EngravedMessage.jsx diff --git a/tgui/packages/tgui/interfaces/EventPanel.js b/tgui/packages/tgui/interfaces/EventPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/EventPanel.js rename to tgui/packages/tgui/interfaces/EventPanel.jsx diff --git a/tgui/packages/tgui/interfaces/ExaminePanel.js b/tgui/packages/tgui/interfaces/ExaminePanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ExaminePanel.js rename to tgui/packages/tgui/interfaces/ExaminePanel.jsx diff --git a/tgui/packages/tgui/interfaces/ExosuitControlConsole.js b/tgui/packages/tgui/interfaces/ExosuitControlConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ExosuitControlConsole.js rename to tgui/packages/tgui/interfaces/ExosuitControlConsole.jsx diff --git a/tgui/packages/tgui/interfaces/ExperimentConfigure.js b/tgui/packages/tgui/interfaces/ExperimentConfigure.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ExperimentConfigure.js rename to tgui/packages/tgui/interfaces/ExperimentConfigure.jsx diff --git a/tgui/packages/tgui/interfaces/Filteriffic.js b/tgui/packages/tgui/interfaces/Filteriffic.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Filteriffic.js rename to tgui/packages/tgui/interfaces/Filteriffic.jsx diff --git a/tgui/packages/tgui/interfaces/Gateway.js b/tgui/packages/tgui/interfaces/Gateway.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Gateway.js rename to tgui/packages/tgui/interfaces/Gateway.jsx diff --git a/tgui/packages/tgui/interfaces/GhostPoolProtection.js b/tgui/packages/tgui/interfaces/GhostPoolProtection.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/GhostPoolProtection.js rename to tgui/packages/tgui/interfaces/GhostPoolProtection.jsx diff --git a/tgui/packages/tgui/interfaces/Gps.js b/tgui/packages/tgui/interfaces/Gps.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Gps.js rename to tgui/packages/tgui/interfaces/Gps.jsx diff --git a/tgui/packages/tgui/interfaces/GravityGenerator.js b/tgui/packages/tgui/interfaces/GravityGenerator.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/GravityGenerator.js rename to tgui/packages/tgui/interfaces/GravityGenerator.jsx diff --git a/tgui/packages/tgui/interfaces/GulagTeleporterConsole.js b/tgui/packages/tgui/interfaces/GulagTeleporterConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/GulagTeleporterConsole.js rename to tgui/packages/tgui/interfaces/GulagTeleporterConsole.jsx diff --git a/tgui/packages/tgui/interfaces/Holodeck.js b/tgui/packages/tgui/interfaces/Holodeck.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Holodeck.js rename to tgui/packages/tgui/interfaces/Holodeck.jsx diff --git a/tgui/packages/tgui/interfaces/Holopad.js b/tgui/packages/tgui/interfaces/Holopad.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Holopad.js rename to tgui/packages/tgui/interfaces/Holopad.jsx diff --git a/tgui/packages/tgui/interfaces/HypnoChair.js b/tgui/packages/tgui/interfaces/HypnoChair.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/HypnoChair.js rename to tgui/packages/tgui/interfaces/HypnoChair.jsx diff --git a/tgui/packages/tgui/interfaces/ImplantChair.js b/tgui/packages/tgui/interfaces/ImplantChair.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ImplantChair.js rename to tgui/packages/tgui/interfaces/ImplantChair.jsx diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/BasicInput.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/BasicInput.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/BasicInput.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/BasicInput.jsx diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/CircuitInfo.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/CircuitInfo.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/CircuitInfo.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/CircuitInfo.jsx diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/ComponentMenu.jsx diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayComponent.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayComponent.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayComponent.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayComponent.jsx diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayName.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayName.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayName.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayName.jsx diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/FundamentalTypes.jsx diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/ObjectComponent.jsx diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/Port.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/Port.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/Port.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/Port.jsx diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/VariableMenu.jsx diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/constants.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/constants.ts similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/constants.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/constants.ts diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/index.js b/tgui/packages/tgui/interfaces/IntegratedCircuit/index.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/IntegratedCircuit/index.js rename to tgui/packages/tgui/interfaces/IntegratedCircuit/index.jsx diff --git a/tgui/packages/tgui/interfaces/Intellicard.js b/tgui/packages/tgui/interfaces/Intellicard.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Intellicard.js rename to tgui/packages/tgui/interfaces/Intellicard.jsx diff --git a/tgui/packages/tgui/interfaces/Interview.js b/tgui/packages/tgui/interfaces/Interview.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Interview.js rename to tgui/packages/tgui/interfaces/Interview.jsx diff --git a/tgui/packages/tgui/interfaces/InterviewManager.js b/tgui/packages/tgui/interfaces/InterviewManager.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/InterviewManager.js rename to tgui/packages/tgui/interfaces/InterviewManager.jsx diff --git a/tgui/packages/tgui/interfaces/Jukebox.js b/tgui/packages/tgui/interfaces/Jukebox.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Jukebox.js rename to tgui/packages/tgui/interfaces/Jukebox.jsx diff --git a/tgui/packages/tgui/interfaces/KeycardAuth.js b/tgui/packages/tgui/interfaces/KeycardAuth.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/KeycardAuth.js rename to tgui/packages/tgui/interfaces/KeycardAuth.jsx diff --git a/tgui/packages/tgui/interfaces/LaborClaimConsole.js b/tgui/packages/tgui/interfaces/LaborClaimConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LaborClaimConsole.js rename to tgui/packages/tgui/interfaces/LaborClaimConsole.jsx diff --git a/tgui/packages/tgui/interfaces/LanguageMenu.js b/tgui/packages/tgui/interfaces/LanguageMenu.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LanguageMenu.js rename to tgui/packages/tgui/interfaces/LanguageMenu.jsx diff --git a/tgui/packages/tgui/interfaces/LaunchpadConsole.js b/tgui/packages/tgui/interfaces/LaunchpadConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LaunchpadConsole.js rename to tgui/packages/tgui/interfaces/LaunchpadConsole.jsx diff --git a/tgui/packages/tgui/interfaces/LibraryConsole.js b/tgui/packages/tgui/interfaces/LibraryConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LibraryConsole.js rename to tgui/packages/tgui/interfaces/LibraryConsole.jsx diff --git a/tgui/packages/tgui/interfaces/LibraryScanner.js b/tgui/packages/tgui/interfaces/LibraryScanner.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LibraryScanner.js rename to tgui/packages/tgui/interfaces/LibraryScanner.jsx diff --git a/tgui/packages/tgui/interfaces/LibraryVisitor.js b/tgui/packages/tgui/interfaces/LibraryVisitor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LibraryVisitor.js rename to tgui/packages/tgui/interfaces/LibraryVisitor.jsx diff --git a/tgui/packages/tgui/interfaces/Limbgrower.js b/tgui/packages/tgui/interfaces/Limbgrower.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Limbgrower.js rename to tgui/packages/tgui/interfaces/Limbgrower.jsx diff --git a/tgui/packages/tgui/interfaces/LoadoutManager.js b/tgui/packages/tgui/interfaces/LoadoutManager.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LoadoutManager.js rename to tgui/packages/tgui/interfaces/LoadoutManager.jsx diff --git a/tgui/packages/tgui/interfaces/LuaEditor/CallModal.js b/tgui/packages/tgui/interfaces/LuaEditor/CallModal.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LuaEditor/CallModal.js rename to tgui/packages/tgui/interfaces/LuaEditor/CallModal.jsx diff --git a/tgui/packages/tgui/interfaces/LuaEditor/ChunkViewModal.js b/tgui/packages/tgui/interfaces/LuaEditor/ChunkViewModal.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LuaEditor/ChunkViewModal.js rename to tgui/packages/tgui/interfaces/LuaEditor/ChunkViewModal.jsx diff --git a/tgui/packages/tgui/interfaces/LuaEditor/ListMapper.js b/tgui/packages/tgui/interfaces/LuaEditor/ListMapper.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LuaEditor/ListMapper.js rename to tgui/packages/tgui/interfaces/LuaEditor/ListMapper.jsx diff --git a/tgui/packages/tgui/interfaces/LuaEditor/Log.js b/tgui/packages/tgui/interfaces/LuaEditor/Log.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LuaEditor/Log.js rename to tgui/packages/tgui/interfaces/LuaEditor/Log.jsx diff --git a/tgui/packages/tgui/interfaces/LuaEditor/StateSelectModal.js b/tgui/packages/tgui/interfaces/LuaEditor/StateSelectModal.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LuaEditor/StateSelectModal.js rename to tgui/packages/tgui/interfaces/LuaEditor/StateSelectModal.jsx diff --git a/tgui/packages/tgui/interfaces/LuaEditor/TaskManager.js b/tgui/packages/tgui/interfaces/LuaEditor/TaskManager.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LuaEditor/TaskManager.js rename to tgui/packages/tgui/interfaces/LuaEditor/TaskManager.jsx diff --git a/tgui/packages/tgui/interfaces/LuaEditor/index.js b/tgui/packages/tgui/interfaces/LuaEditor/index.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LuaEditor/index.js rename to tgui/packages/tgui/interfaces/LuaEditor/index.jsx diff --git a/tgui/packages/tgui/interfaces/MODpaint.js b/tgui/packages/tgui/interfaces/MODpaint.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MODpaint.js rename to tgui/packages/tgui/interfaces/MODpaint.jsx diff --git a/tgui/packages/tgui/interfaces/MalfunctionModulePicker.js b/tgui/packages/tgui/interfaces/MalfunctionModulePicker.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MalfunctionModulePicker.js rename to tgui/packages/tgui/interfaces/MalfunctionModulePicker.jsx diff --git a/tgui/packages/tgui/interfaces/MassDriverControl.js b/tgui/packages/tgui/interfaces/MassDriverControl.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MassDriverControl.js rename to tgui/packages/tgui/interfaces/MassDriverControl.jsx diff --git a/tgui/packages/tgui/interfaces/MassSpec.js b/tgui/packages/tgui/interfaces/MassSpec.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MassSpec.js rename to tgui/packages/tgui/interfaces/MassSpec.jsx diff --git a/tgui/packages/tgui/interfaces/MechBayPowerConsole.js b/tgui/packages/tgui/interfaces/MechBayPowerConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MechBayPowerConsole.js rename to tgui/packages/tgui/interfaces/MechBayPowerConsole.jsx diff --git a/tgui/packages/tgui/interfaces/MechpadConsole.js b/tgui/packages/tgui/interfaces/MechpadConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MechpadConsole.js rename to tgui/packages/tgui/interfaces/MechpadConsole.jsx diff --git a/tgui/packages/tgui/interfaces/MedicalKiosk.js b/tgui/packages/tgui/interfaces/MedicalKiosk.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MedicalKiosk.js rename to tgui/packages/tgui/interfaces/MedicalKiosk.jsx diff --git a/tgui/packages/tgui/interfaces/MemoryPanel.js b/tgui/packages/tgui/interfaces/MemoryPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MemoryPanel.js rename to tgui/packages/tgui/interfaces/MemoryPanel.jsx diff --git a/tgui/packages/tgui/interfaces/MicrofusionGunControl.js b/tgui/packages/tgui/interfaces/MicrofusionGunControl.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MicrofusionGunControl.js rename to tgui/packages/tgui/interfaces/MicrofusionGunControl.jsx diff --git a/tgui/packages/tgui/interfaces/Microscope.js b/tgui/packages/tgui/interfaces/Microscope.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Microscope.js rename to tgui/packages/tgui/interfaces/Microscope.jsx diff --git a/tgui/packages/tgui/interfaces/MilkingMachine.js b/tgui/packages/tgui/interfaces/MilkingMachine.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MilkingMachine.js rename to tgui/packages/tgui/interfaces/MilkingMachine.jsx diff --git a/tgui/packages/tgui/interfaces/Mule.js b/tgui/packages/tgui/interfaces/Mule.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Mule.js rename to tgui/packages/tgui/interfaces/Mule.jsx diff --git a/tgui/packages/tgui/interfaces/Newscaster.js b/tgui/packages/tgui/interfaces/Newscaster.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Newscaster.js rename to tgui/packages/tgui/interfaces/Newscaster.jsx diff --git a/tgui/packages/tgui/interfaces/NifPanel.js b/tgui/packages/tgui/interfaces/NifPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NifPanel.js rename to tgui/packages/tgui/interfaces/NifPanel.jsx diff --git a/tgui/packages/tgui/interfaces/NifSoulPoem.js b/tgui/packages/tgui/interfaces/NifSoulPoem.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NifSoulPoem.js rename to tgui/packages/tgui/interfaces/NifSoulPoem.jsx diff --git a/tgui/packages/tgui/interfaces/NightmareInfo.js b/tgui/packages/tgui/interfaces/NightmareInfo.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NightmareInfo.js rename to tgui/packages/tgui/interfaces/NightmareInfo.jsx diff --git a/tgui/packages/tgui/interfaces/NotificationPreferences.js b/tgui/packages/tgui/interfaces/NotificationPreferences.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NotificationPreferences.js rename to tgui/packages/tgui/interfaces/NotificationPreferences.jsx diff --git a/tgui/packages/tgui/interfaces/NtosArcade.js b/tgui/packages/tgui/interfaces/NtosArcade.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosArcade.js rename to tgui/packages/tgui/interfaces/NtosArcade.jsx diff --git a/tgui/packages/tgui/interfaces/NtosCamera.js b/tgui/packages/tgui/interfaces/NtosCamera.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosCamera.js rename to tgui/packages/tgui/interfaces/NtosCamera.jsx diff --git a/tgui/packages/tgui/interfaces/NtosCard.js b/tgui/packages/tgui/interfaces/NtosCard.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosCard.js rename to tgui/packages/tgui/interfaces/NtosCard.jsx diff --git a/tgui/packages/tgui/interfaces/NtosCargo.tsx b/tgui/packages/tgui/interfaces/NtosCargo.tsx index b5009c0aeaf..b478e42e5ae 100644 --- a/tgui/packages/tgui/interfaces/NtosCargo.tsx +++ b/tgui/packages/tgui/interfaces/NtosCargo.tsx @@ -1,4 +1,4 @@ -import { CargoContent } from './Cargo.js'; +import { CargoContent } from './Cargo'; import { NtosWindow } from '../layouts'; export const NtosCargo = (props, context) => { diff --git a/tgui/packages/tgui/interfaces/NtosCrewManifest.js b/tgui/packages/tgui/interfaces/NtosCrewManifest.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosCrewManifest.js rename to tgui/packages/tgui/interfaces/NtosCrewManifest.jsx diff --git a/tgui/packages/tgui/interfaces/NtosCyborgRemoteMonitor.js b/tgui/packages/tgui/interfaces/NtosCyborgRemoteMonitor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosCyborgRemoteMonitor.js rename to tgui/packages/tgui/interfaces/NtosCyborgRemoteMonitor.jsx diff --git a/tgui/packages/tgui/interfaces/NtosEmojipedia.js b/tgui/packages/tgui/interfaces/NtosEmojipedia.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosEmojipedia.js rename to tgui/packages/tgui/interfaces/NtosEmojipedia.jsx diff --git a/tgui/packages/tgui/interfaces/NtosFileManager.js b/tgui/packages/tgui/interfaces/NtosFileManager.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosFileManager.js rename to tgui/packages/tgui/interfaces/NtosFileManager.jsx diff --git a/tgui/packages/tgui/interfaces/NtosJobManager.js b/tgui/packages/tgui/interfaces/NtosJobManager.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosJobManager.js rename to tgui/packages/tgui/interfaces/NtosJobManager.jsx diff --git a/tgui/packages/tgui/interfaces/NtosMODsuit.js b/tgui/packages/tgui/interfaces/NtosMODsuit.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosMODsuit.js rename to tgui/packages/tgui/interfaces/NtosMODsuit.jsx diff --git a/tgui/packages/tgui/interfaces/NtosMain.js b/tgui/packages/tgui/interfaces/NtosMain.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosMain.js rename to tgui/packages/tgui/interfaces/NtosMain.jsx diff --git a/tgui/packages/tgui/interfaces/NtosNetChat.js b/tgui/packages/tgui/interfaces/NtosNetChat.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosNetChat.js rename to tgui/packages/tgui/interfaces/NtosNetChat.jsx diff --git a/tgui/packages/tgui/interfaces/NtosNetDos.js b/tgui/packages/tgui/interfaces/NtosNetDos.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosNetDos.js rename to tgui/packages/tgui/interfaces/NtosNetDos.jsx diff --git a/tgui/packages/tgui/interfaces/NtosNetDownloader.js b/tgui/packages/tgui/interfaces/NtosNetDownloader.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosNetDownloader.js rename to tgui/packages/tgui/interfaces/NtosNetDownloader.jsx diff --git a/tgui/packages/tgui/interfaces/NtosNetMonitor.js b/tgui/packages/tgui/interfaces/NtosNetMonitor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosNetMonitor.js rename to tgui/packages/tgui/interfaces/NtosNetMonitor.jsx diff --git a/tgui/packages/tgui/interfaces/NtosNewsArchive.js b/tgui/packages/tgui/interfaces/NtosNewsArchive.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosNewsArchive.js rename to tgui/packages/tgui/interfaces/NtosNewsArchive.jsx diff --git a/tgui/packages/tgui/interfaces/NtosNifsoftCatalog.js b/tgui/packages/tgui/interfaces/NtosNifsoftCatalog.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosNifsoftCatalog.js rename to tgui/packages/tgui/interfaces/NtosNifsoftCatalog.jsx diff --git a/tgui/packages/tgui/interfaces/NtosPhysScanner.js b/tgui/packages/tgui/interfaces/NtosPhysScanner.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosPhysScanner.js rename to tgui/packages/tgui/interfaces/NtosPhysScanner.jsx diff --git a/tgui/packages/tgui/interfaces/NtosPortraitPrinter.js b/tgui/packages/tgui/interfaces/NtosPortraitPrinter.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosPortraitPrinter.js rename to tgui/packages/tgui/interfaces/NtosPortraitPrinter.jsx diff --git a/tgui/packages/tgui/interfaces/NtosRecords.js b/tgui/packages/tgui/interfaces/NtosRecords.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosRecords.js rename to tgui/packages/tgui/interfaces/NtosRecords.jsx diff --git a/tgui/packages/tgui/interfaces/NtosRoboControl.js b/tgui/packages/tgui/interfaces/NtosRoboControl.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosRoboControl.js rename to tgui/packages/tgui/interfaces/NtosRoboControl.jsx diff --git a/tgui/packages/tgui/interfaces/NtosRobotact.js b/tgui/packages/tgui/interfaces/NtosRobotact.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosRobotact.js rename to tgui/packages/tgui/interfaces/NtosRobotact.jsx diff --git a/tgui/packages/tgui/interfaces/NtosScipaper.js b/tgui/packages/tgui/interfaces/NtosScipaper.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosScipaper.js rename to tgui/packages/tgui/interfaces/NtosScipaper.jsx diff --git a/tgui/packages/tgui/interfaces/NtosSkillTracker.js b/tgui/packages/tgui/interfaces/NtosSkillTracker.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NtosSkillTracker.js rename to tgui/packages/tgui/interfaces/NtosSkillTracker.jsx diff --git a/tgui/packages/tgui/interfaces/NtosTechweb.tsx b/tgui/packages/tgui/interfaces/NtosTechweb.tsx index 844198c6a1f..6bec8c9b0bb 100644 --- a/tgui/packages/tgui/interfaces/NtosTechweb.tsx +++ b/tgui/packages/tgui/interfaces/NtosTechweb.tsx @@ -1,4 +1,4 @@ -import { AppTechweb } from './Techweb.js'; +import { AppTechweb } from './Techweb'; export const NtosTechweb = (props, context) => { return ; diff --git a/tgui/packages/tgui/interfaces/NuclearBomb.js b/tgui/packages/tgui/interfaces/NuclearBomb.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NuclearBomb.js rename to tgui/packages/tgui/interfaces/NuclearBomb.jsx diff --git a/tgui/packages/tgui/interfaces/OperatingComputer.js b/tgui/packages/tgui/interfaces/OperatingComputer.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/OperatingComputer.js rename to tgui/packages/tgui/interfaces/OperatingComputer.jsx diff --git a/tgui/packages/tgui/interfaces/OpposingForcePanel.js b/tgui/packages/tgui/interfaces/OpposingForcePanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/OpposingForcePanel.js rename to tgui/packages/tgui/interfaces/OpposingForcePanel.jsx diff --git a/tgui/packages/tgui/interfaces/OreRedemptionMachine.js b/tgui/packages/tgui/interfaces/OreRedemptionMachine.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/OreRedemptionMachine.js rename to tgui/packages/tgui/interfaces/OreRedemptionMachine.jsx diff --git a/tgui/packages/tgui/interfaces/OrionGame.js b/tgui/packages/tgui/interfaces/OrionGame.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/OrionGame.js rename to tgui/packages/tgui/interfaces/OrionGame.jsx diff --git a/tgui/packages/tgui/interfaces/OutfitEditor.js b/tgui/packages/tgui/interfaces/OutfitEditor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/OutfitEditor.js rename to tgui/packages/tgui/interfaces/OutfitEditor.jsx diff --git a/tgui/packages/tgui/interfaces/OutfitManager.js b/tgui/packages/tgui/interfaces/OutfitManager.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/OutfitManager.js rename to tgui/packages/tgui/interfaces/OutfitManager.jsx diff --git a/tgui/packages/tgui/interfaces/PaintingMachine.js b/tgui/packages/tgui/interfaces/PaintingMachine.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/PaintingMachine.js rename to tgui/packages/tgui/interfaces/PaintingMachine.jsx diff --git a/tgui/packages/tgui/interfaces/ParticleAccelerator.js b/tgui/packages/tgui/interfaces/ParticleAccelerator.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ParticleAccelerator.js rename to tgui/packages/tgui/interfaces/ParticleAccelerator.jsx diff --git a/tgui/packages/tgui/interfaces/Photocopier.js b/tgui/packages/tgui/interfaces/Photocopier.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Photocopier.js rename to tgui/packages/tgui/interfaces/Photocopier.jsx diff --git a/tgui/packages/tgui/interfaces/PortableGenerator.js b/tgui/packages/tgui/interfaces/PortableGenerator.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/PortableGenerator.js rename to tgui/packages/tgui/interfaces/PortableGenerator.jsx diff --git a/tgui/packages/tgui/interfaces/PortablePump.js b/tgui/packages/tgui/interfaces/PortablePump.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/PortablePump.js rename to tgui/packages/tgui/interfaces/PortablePump.jsx diff --git a/tgui/packages/tgui/interfaces/PortableTurret.js b/tgui/packages/tgui/interfaces/PortableTurret.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/PortableTurret.js rename to tgui/packages/tgui/interfaces/PortableTurret.jsx diff --git a/tgui/packages/tgui/interfaces/PortraitPicker.js b/tgui/packages/tgui/interfaces/PortraitPicker.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/PortraitPicker.js rename to tgui/packages/tgui/interfaces/PortraitPicker.jsx diff --git a/tgui/packages/tgui/interfaces/PowerMonitor.js b/tgui/packages/tgui/interfaces/PowerMonitor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/PowerMonitor.js rename to tgui/packages/tgui/interfaces/PowerMonitor.jsx diff --git a/tgui/packages/tgui/interfaces/ProbingConsole.js b/tgui/packages/tgui/interfaces/ProbingConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ProbingConsole.js rename to tgui/packages/tgui/interfaces/ProbingConsole.jsx diff --git a/tgui/packages/tgui/interfaces/ProximitySensor.js b/tgui/packages/tgui/interfaces/ProximitySensor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ProximitySensor.js rename to tgui/packages/tgui/interfaces/ProximitySensor.jsx diff --git a/tgui/packages/tgui/interfaces/Radio.js b/tgui/packages/tgui/interfaces/Radio.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Radio.js rename to tgui/packages/tgui/interfaces/Radio.jsx diff --git a/tgui/packages/tgui/interfaces/RadioactiveMicrolaser.js b/tgui/packages/tgui/interfaces/RadioactiveMicrolaser.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/RadioactiveMicrolaser.js rename to tgui/packages/tgui/interfaces/RadioactiveMicrolaser.jsx diff --git a/tgui/packages/tgui/interfaces/Reagents.js b/tgui/packages/tgui/interfaces/Reagents.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Reagents.js rename to tgui/packages/tgui/interfaces/Reagents.jsx diff --git a/tgui/packages/tgui/interfaces/RecordManifest.js b/tgui/packages/tgui/interfaces/RecordManifest.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/RecordManifest.js rename to tgui/packages/tgui/interfaces/RecordManifest.jsx diff --git a/tgui/packages/tgui/interfaces/ReligiousTool.js b/tgui/packages/tgui/interfaces/ReligiousTool.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ReligiousTool.js rename to tgui/packages/tgui/interfaces/ReligiousTool.jsx diff --git a/tgui/packages/tgui/interfaces/RemoteRobotControl.js b/tgui/packages/tgui/interfaces/RemoteRobotControl.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/RemoteRobotControl.js rename to tgui/packages/tgui/interfaces/RemoteRobotControl.jsx diff --git a/tgui/packages/tgui/interfaces/RequestManager.js b/tgui/packages/tgui/interfaces/RequestManager.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/RequestManager.js rename to tgui/packages/tgui/interfaces/RequestManager.jsx diff --git a/tgui/packages/tgui/interfaces/RoboticsControlConsole.js b/tgui/packages/tgui/interfaces/RoboticsControlConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/RoboticsControlConsole.js rename to tgui/packages/tgui/interfaces/RoboticsControlConsole.jsx diff --git a/tgui/packages/tgui/interfaces/Roulette.js b/tgui/packages/tgui/interfaces/Roulette.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Roulette.js rename to tgui/packages/tgui/interfaces/Roulette.jsx diff --git a/tgui/packages/tgui/interfaces/Safe.js b/tgui/packages/tgui/interfaces/Safe.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Safe.js rename to tgui/packages/tgui/interfaces/Safe.jsx diff --git a/tgui/packages/tgui/interfaces/ScannerGate.js b/tgui/packages/tgui/interfaces/ScannerGate.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ScannerGate.js rename to tgui/packages/tgui/interfaces/ScannerGate.jsx diff --git a/tgui/packages/tgui/interfaces/Secrets.js b/tgui/packages/tgui/interfaces/Secrets.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Secrets.js rename to tgui/packages/tgui/interfaces/Secrets.jsx diff --git a/tgui/packages/tgui/interfaces/SelectEquipment.js b/tgui/packages/tgui/interfaces/SelectEquipment.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SelectEquipment.js rename to tgui/packages/tgui/interfaces/SelectEquipment.jsx diff --git a/tgui/packages/tgui/interfaces/SentienceFunBalloon.js b/tgui/packages/tgui/interfaces/SentienceFunBalloon.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SentienceFunBalloon.js rename to tgui/packages/tgui/interfaces/SentienceFunBalloon.jsx diff --git a/tgui/packages/tgui/interfaces/ServerControlPanel.js b/tgui/packages/tgui/interfaces/ServerControlPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ServerControlPanel.js rename to tgui/packages/tgui/interfaces/ServerControlPanel.jsx diff --git a/tgui/packages/tgui/interfaces/ServerMonitor.js b/tgui/packages/tgui/interfaces/ServerMonitor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ServerMonitor.js rename to tgui/packages/tgui/interfaces/ServerMonitor.jsx diff --git a/tgui/packages/tgui/interfaces/ShuttleConsole.js b/tgui/packages/tgui/interfaces/ShuttleConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ShuttleConsole.js rename to tgui/packages/tgui/interfaces/ShuttleConsole.jsx diff --git a/tgui/packages/tgui/interfaces/ShuttleManipulator.js b/tgui/packages/tgui/interfaces/ShuttleManipulator.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ShuttleManipulator.js rename to tgui/packages/tgui/interfaces/ShuttleManipulator.jsx diff --git a/tgui/packages/tgui/interfaces/Signalvib.js b/tgui/packages/tgui/interfaces/Signalvib.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Signalvib.js rename to tgui/packages/tgui/interfaces/Signalvib.jsx diff --git a/tgui/packages/tgui/interfaces/SkillPanel.js b/tgui/packages/tgui/interfaces/SkillPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SkillPanel.js rename to tgui/packages/tgui/interfaces/SkillPanel.jsx diff --git a/tgui/packages/tgui/interfaces/SkillStation.js b/tgui/packages/tgui/interfaces/SkillStation.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SkillStation.js rename to tgui/packages/tgui/interfaces/SkillStation.jsx diff --git a/tgui/packages/tgui/interfaces/Sleeper.js b/tgui/packages/tgui/interfaces/Sleeper.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Sleeper.js rename to tgui/packages/tgui/interfaces/Sleeper.jsx diff --git a/tgui/packages/tgui/interfaces/SlimeBodySwapper.js b/tgui/packages/tgui/interfaces/SlimeBodySwapper.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SlimeBodySwapper.js rename to tgui/packages/tgui/interfaces/SlimeBodySwapper.jsx diff --git a/tgui/packages/tgui/interfaces/Smes.js b/tgui/packages/tgui/interfaces/Smes.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Smes.js rename to tgui/packages/tgui/interfaces/Smes.jsx diff --git a/tgui/packages/tgui/interfaces/Soulcatcher.js b/tgui/packages/tgui/interfaces/Soulcatcher.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Soulcatcher.js rename to tgui/packages/tgui/interfaces/Soulcatcher.jsx diff --git a/tgui/packages/tgui/interfaces/SoulcatcherUser.js b/tgui/packages/tgui/interfaces/SoulcatcherUser.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SoulcatcherUser.js rename to tgui/packages/tgui/interfaces/SoulcatcherUser.jsx diff --git a/tgui/packages/tgui/interfaces/SpaceHeater.js b/tgui/packages/tgui/interfaces/SpaceHeater.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SpaceHeater.js rename to tgui/packages/tgui/interfaces/SpaceHeater.jsx diff --git a/tgui/packages/tgui/interfaces/StackingConsole.js b/tgui/packages/tgui/interfaces/StackingConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/StackingConsole.js rename to tgui/packages/tgui/interfaces/StackingConsole.jsx diff --git a/tgui/packages/tgui/interfaces/StationAlertConsole.js b/tgui/packages/tgui/interfaces/StationAlertConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/StationAlertConsole.js rename to tgui/packages/tgui/interfaces/StationAlertConsole.jsx diff --git a/tgui/packages/tgui/interfaces/SyndContractor.js b/tgui/packages/tgui/interfaces/SyndContractor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SyndContractor.js rename to tgui/packages/tgui/interfaces/SyndContractor.jsx diff --git a/tgui/packages/tgui/interfaces/Tank.js b/tgui/packages/tgui/interfaces/Tank.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Tank.js rename to tgui/packages/tgui/interfaces/Tank.jsx diff --git a/tgui/packages/tgui/interfaces/TankCompressor.js b/tgui/packages/tgui/interfaces/TankCompressor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TankCompressor.js rename to tgui/packages/tgui/interfaces/TankCompressor.jsx diff --git a/tgui/packages/tgui/interfaces/TankDispenser.js b/tgui/packages/tgui/interfaces/TankDispenser.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TankDispenser.js rename to tgui/packages/tgui/interfaces/TankDispenser.jsx diff --git a/tgui/packages/tgui/interfaces/Techweb.js b/tgui/packages/tgui/interfaces/Techweb.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Techweb.js rename to tgui/packages/tgui/interfaces/Techweb.jsx diff --git a/tgui/packages/tgui/interfaces/Telecomms.js b/tgui/packages/tgui/interfaces/Telecomms.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Telecomms.js rename to tgui/packages/tgui/interfaces/Telecomms.jsx diff --git a/tgui/packages/tgui/interfaces/Teleporter.js b/tgui/packages/tgui/interfaces/Teleporter.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Teleporter.js rename to tgui/packages/tgui/interfaces/Teleporter.jsx diff --git a/tgui/packages/tgui/interfaces/ThermoMachine.js b/tgui/packages/tgui/interfaces/ThermoMachine.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ThermoMachine.js rename to tgui/packages/tgui/interfaces/ThermoMachine.jsx diff --git a/tgui/packages/tgui/interfaces/Thermometer.js b/tgui/packages/tgui/interfaces/Thermometer.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Thermometer.js rename to tgui/packages/tgui/interfaces/Thermometer.jsx diff --git a/tgui/packages/tgui/interfaces/TimeClock.js b/tgui/packages/tgui/interfaces/TimeClock.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TimeClock.js rename to tgui/packages/tgui/interfaces/TimeClock.jsx diff --git a/tgui/packages/tgui/interfaces/TrackedPlaytime.js b/tgui/packages/tgui/interfaces/TrackedPlaytime.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TrackedPlaytime.js rename to tgui/packages/tgui/interfaces/TrackedPlaytime.jsx diff --git a/tgui/packages/tgui/interfaces/TramControl.js b/tgui/packages/tgui/interfaces/TramControl.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TramControl.js rename to tgui/packages/tgui/interfaces/TramControl.jsx diff --git a/tgui/packages/tgui/interfaces/TransferValve.js b/tgui/packages/tgui/interfaces/TransferValve.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TransferValve.js rename to tgui/packages/tgui/interfaces/TransferValve.jsx diff --git a/tgui/packages/tgui/interfaces/TrophyAdminPanel.js b/tgui/packages/tgui/interfaces/TrophyAdminPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TrophyAdminPanel.js rename to tgui/packages/tgui/interfaces/TrophyAdminPanel.jsx diff --git a/tgui/packages/tgui/interfaces/Trophycase.js b/tgui/packages/tgui/interfaces/Trophycase.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Trophycase.js rename to tgui/packages/tgui/interfaces/Trophycase.jsx diff --git a/tgui/packages/tgui/interfaces/common/AccessConfig.js b/tgui/packages/tgui/interfaces/common/AccessConfig.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/common/AccessConfig.js rename to tgui/packages/tgui/interfaces/common/AccessConfig.jsx diff --git a/tgui/packages/tgui/interfaces/common/AccessList.js b/tgui/packages/tgui/interfaces/common/AccessList.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/common/AccessList.js rename to tgui/packages/tgui/interfaces/common/AccessList.jsx diff --git a/tgui/packages/tgui/interfaces/common/BeakerContents.js b/tgui/packages/tgui/interfaces/common/BeakerContents.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/common/BeakerContents.js rename to tgui/packages/tgui/interfaces/common/BeakerContents.jsx diff --git a/tgui/packages/tgui/interfaces/common/InterfaceLockNoticeBox.js b/tgui/packages/tgui/interfaces/common/InterfaceLockNoticeBox.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/common/InterfaceLockNoticeBox.js rename to tgui/packages/tgui/interfaces/common/InterfaceLockNoticeBox.jsx diff --git a/tgui/packages/tgui/interfaces/common/PortableAtmos.js b/tgui/packages/tgui/interfaces/common/PortableAtmos.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/common/PortableAtmos.js rename to tgui/packages/tgui/interfaces/common/PortableAtmos.jsx diff --git a/tgui/packages/tgui/interfaces/common/ReagentLookup.js b/tgui/packages/tgui/interfaces/common/ReagentLookup.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/common/ReagentLookup.js rename to tgui/packages/tgui/interfaces/common/ReagentLookup.jsx diff --git a/tgui/packages/tgui/interfaces/common/RecipeLookup.js b/tgui/packages/tgui/interfaces/common/RecipeLookup.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/common/RecipeLookup.js rename to tgui/packages/tgui/interfaces/common/RecipeLookup.jsx diff --git a/tgui/packages/tgui/layouts/Layout.js b/tgui/packages/tgui/layouts/Layout.jsx similarity index 100% rename from tgui/packages/tgui/layouts/Layout.js rename to tgui/packages/tgui/layouts/Layout.jsx diff --git a/tgui/packages/tgui/layouts/NtosWindow.js b/tgui/packages/tgui/layouts/NtosWindow.jsx similarity index 100% rename from tgui/packages/tgui/layouts/NtosWindow.js rename to tgui/packages/tgui/layouts/NtosWindow.jsx diff --git a/tgui/packages/tgui/layouts/Pane.js b/tgui/packages/tgui/layouts/Pane.jsx similarity index 100% rename from tgui/packages/tgui/layouts/Pane.js rename to tgui/packages/tgui/layouts/Pane.jsx diff --git a/tgui/packages/tgui/layouts/Window.js b/tgui/packages/tgui/layouts/Window.jsx similarity index 100% rename from tgui/packages/tgui/layouts/Window.js rename to tgui/packages/tgui/layouts/Window.jsx diff --git a/tgui/packages/tgui/layouts/index.js b/tgui/packages/tgui/layouts/index.ts similarity index 100% rename from tgui/packages/tgui/layouts/index.js rename to tgui/packages/tgui/layouts/index.ts diff --git a/tgui/packages/tgui/routes.tsx b/tgui/packages/tgui/routes.tsx index 39598c4cc6e..fc2785cde5e 100644 --- a/tgui/packages/tgui/routes.tsx +++ b/tgui/packages/tgui/routes.tsx @@ -72,9 +72,9 @@ export const getRoutedComponent = (store: Store) => { const name = config?.interface; const interfacePathBuilders = [ (name: string) => `./${name}.tsx`, - (name: string) => `./${name}.js`, + (name: string) => `./${name}.jsx`, (name: string) => `./${name}/index.tsx`, - (name: string) => `./${name}/index.js`, + (name: string) => `./${name}/index.jsx`, ]; let esModule; while (!esModule && interfacePathBuilders.length > 0) { diff --git a/tgui/webpack.config.js b/tgui/webpack.config.js index 19e2975715f..27a07fd0d09 100644 --- a/tgui/webpack.config.js +++ b/tgui/webpack.config.js @@ -33,18 +33,9 @@ module.exports = (env = {}, argv) => { context: path.resolve(__dirname), target: ['web', 'es3', 'browserslist:ie 8'], entry: { - 'tgui': [ - './packages/tgui-polyfill', - './packages/tgui', - ], - 'tgui-panel': [ - './packages/tgui-polyfill', - './packages/tgui-panel', - ], - 'tgui-say': [ - './packages/tgui-polyfill', - './packages/tgui-say', - ], + 'tgui': ['./packages/tgui-polyfill', './packages/tgui'], + 'tgui-panel': ['./packages/tgui-polyfill', './packages/tgui-panel'], + 'tgui-say': ['./packages/tgui-polyfill', './packages/tgui-say'], }, output: { path: argv.useTmpFolder @@ -55,13 +46,13 @@ module.exports = (env = {}, argv) => { chunkLoadTimeout: 15000, }, resolve: { - extensions: ['.tsx', '.ts', '.js'], + extensions: ['.tsx', '.ts', '.js', '.jsx'], alias: {}, }, module: { rules: [ { - test: /\.(js|cjs|ts|tsx)$/, + test: /\.(js(x)?|cjs|ts(x)?)$/, use: [ { loader: require.resolve('babel-loader'), From ddd73998375cd5dfea5f35bca63b675f76f03aae Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 02:25:09 +0300 Subject: [PATCH 43/55] Adds Camera App to Default Downloads (#780) * initial d * wew * Forgot this! * And this * And this is no longer a skyrat edit * Finally please remember to label what the skyrat edit is (change, removal, addition) --------- Co-authored-by: Nerevar <12636964+Nerev4r@users.noreply.github.com> Co-authored-by: Snakebittenn <12636964+Snakebittenn@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/_globalvars/lists/maintenance_loot.dm | 4 ++-- code/modules/modular_computers/computers/item/pda.dm | 1 + .../file_system/programs/maintenance/camera.dm | 4 ++++ tgstation.dme | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 modular_skyrat/master_files/code/modules/modular_computers/file_system/programs/maintenance/camera.dm diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index 50575d24b5b..a54799b7bb1 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -256,10 +256,10 @@ GLOBAL_LIST_INIT(uncommon_loot, list(//uncommon: useful items list(//computer disks /obj/item/computer_disk/maintenance/scanner = 1, - /obj/item/computer_disk/maintenance/camera = 1, + ///obj/item/computer_disk/maintenance/camera = 1, //SKYRAT EDIT REMOVAL - Available To Crew Now /obj/item/computer_disk/maintenance/modsuit_control = 1, /obj/item/computer_disk/maintenance/theme = 3, - ) = 4, + ) = 3, //SKYRAT EDIT CHANGE - Original : 4 list(//modsuits /obj/effect/spawner/random/mod/maint = 3, diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm index a4b08f2d90f..0c027b5f30b 100644 --- a/code/modules/modular_computers/computers/item/pda.dm +++ b/code/modules/modular_computers/computers/item/pda.dm @@ -38,6 +38,7 @@ /datum/computer_file/program/notepad, // SKYRAT EDIT ADDITION START /datum/computer_file/program/crew_manifest, // Adds crew manifest to all base tablets + /datum/computer_file/program/maintenance/camera // Adds camera to all base tablets // SKRAT EDIT ADDITION END ) ///List of items that can be stored in a PDA diff --git a/modular_skyrat/master_files/code/modules/modular_computers/file_system/programs/maintenance/camera.dm b/modular_skyrat/master_files/code/modules/modular_computers/file_system/programs/maintenance/camera.dm new file mode 100644 index 00000000000..1fbfdedb519 --- /dev/null +++ b/modular_skyrat/master_files/code/modules/modular_computers/file_system/programs/maintenance/camera.dm @@ -0,0 +1,4 @@ +// Makes camera app readily available to crew +/datum/computer_file/program/maintenance/camera + available_on_ntnet = TRUE + unique_copy = FALSE diff --git a/tgstation.dme b/tgstation.dme index 221b05cffe8..fe320badfde 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6357,6 +6357,7 @@ #include "modular_skyrat\master_files\code\modules\mod\modules\modules_antag.dm" #include "modular_skyrat\master_files\code\modules\mod\modules\modules_supply.dm" #include "modular_skyrat\master_files\code\modules\modular_computers\computers\item\laptop_presets.dm" +#include "modular_skyrat\master_files\code\modules\modular_computers\file_system\programs\maintenance\camera.dm" #include "modular_skyrat\master_files\code\modules\pai\card.dm" #include "modular_skyrat\master_files\code\modules\paperwork\employment_contract.dm" #include "modular_skyrat\master_files\code\modules\paperwork\stamps.dm" From f7e70b06b3e2d6735e9eaac54bc50ce2b0dbd917 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 02:25:31 +0300 Subject: [PATCH 44/55] Automatic changelog for PR #780 [ci skip] --- html/changelogs/AutoChangeLog-pr-780.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-780.yml diff --git a/html/changelogs/AutoChangeLog-pr-780.yml b/html/changelogs/AutoChangeLog-pr-780.yml new file mode 100644 index 00000000000..d94f0207782 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-780.yml @@ -0,0 +1,4 @@ +author: "Nerev4r" +delete-after: True +changes: + - rscadd: "NanoTrasen, after extensive testing in a variety of stars' light wavelengths, have deemed their PDAs ready enough to actually use the onboard cameras they already had." \ No newline at end of file From 0c694c8a4320a9e8de47e8ad8b13b813b6e69748 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 02:25:46 +0300 Subject: [PATCH 45/55] [MISSED MIRROR] Bumps rust-g to `3.0.0` (#774) Bumps rust-g to `3.0.0` (#76663) Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: san7890 --- .github/workflows/autowiki.yml | 3 --- .github/workflows/run_integration_tests.yml | 5 +---- code/__DEFINES/rust_g.dm | 9 ++++++++- code/datums/helper_datums/getrev.dm | 2 ++ dependencies.sh | 2 +- tools/tgs_scripts/PreCompile.sh | 1 + 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/autowiki.yml b/.github/workflows/autowiki.yml index 0a431d520ba..91ab12cdb19 100644 --- a/.github/workflows/autowiki.yml +++ b/.github/workflows/autowiki.yml @@ -30,9 +30,6 @@ jobs: - name: Install rust-g if: steps.secrets_set.outputs.SECRETS_ENABLED run: | - sudo dpkg --add-architecture i386 - sudo apt update || true - sudo apt install -o APT::Immediate-Configure=false libssl1.1:i386 bash tools/ci/install_rust_g.sh - name: Compile and generate Autowiki files if: steps.secrets_set.outputs.SECRETS_ENABLED diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml index 0c4ba61a8a4..404119d9880 100644 --- a/.github/workflows/run_integration_tests.yml +++ b/.github/workflows/run_integration_tests.yml @@ -18,7 +18,7 @@ on: type: string jobs: run_integration_tests: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest services: mysql: image: mysql:latest @@ -43,9 +43,6 @@ jobs: mysql -u root -proot tg_ci_prefixed < SQL/tgstation_schema_prefixed.sql - name: Install rust-g run: | - sudo dpkg --add-architecture i386 - sudo apt update || true - sudo apt install -o APT::Immediate-Configure=false libssl1.1:i386 bash tools/ci/install_rust_g.sh - name: Install auxlua run: | diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm index cab4430a88d..76e5fa22d47 100644 --- a/code/__DEFINES/rust_g.dm +++ b/code/__DEFINES/rust_g.dm @@ -110,6 +110,12 @@ #define rustg_dmi_strip_metadata(fname) RUSTG_CALL(RUST_G, "dmi_strip_metadata")(fname) #define rustg_dmi_create_png(path, width, height, data) RUSTG_CALL(RUST_G, "dmi_create_png")(path, width, height, data) #define rustg_dmi_resize_png(path, width, height, resizetype) RUSTG_CALL(RUST_G, "dmi_resize_png")(path, width, height, resizetype) +/** + * input: must be a path, not an /icon; you have to do your own handling if it is one, as icon objects can't be directly passed to rustg. + * + * output: json_encode'd list. json_decode to get a flat list with icon states in the order they're in inside the .dmi + */ +#define rustg_dmi_icon_states(fname) RUSTG_CALL(RUST_G, "dmi_icon_states")(fname) #define rustg_file_read(fname) RUSTG_CALL(RUST_G, "file_read")(fname) #define rustg_file_exists(fname) RUSTG_CALL(RUST_G, "file_exists")(fname) @@ -158,8 +164,9 @@ #define rustg_time_milliseconds(id) text2num(RUSTG_CALL(RUST_G, "time_milliseconds")(id)) #define rustg_time_reset(id) RUSTG_CALL(RUST_G, "time_reset")(id) +/// Returns the timestamp as a string /proc/rustg_unix_timestamp() - return text2num(RUSTG_CALL(RUST_G, "unix_timestamp")()) + return RUSTG_CALL(RUST_G, "unix_timestamp")() #define rustg_raw_read_toml_file(path) json_decode(RUSTG_CALL(RUST_G, "toml_file_to_json")(path) || "null") diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index 06e2c1e18d6..c3562aa5987 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -37,6 +37,8 @@ else if(!originmastercommit) msg += "No commit information" + msg += "Running rust-g version [rustg_get_version()]" + return msg.Join("\n") /datum/getrev/proc/GetTestMergeInfo(header = TRUE) diff --git a/dependencies.sh b/dependencies.sh index b24b85d55b2..6162b349b51 100644 --- a/dependencies.sh +++ b/dependencies.sh @@ -8,7 +8,7 @@ export BYOND_MAJOR=514 export BYOND_MINOR=1588 #rust_g git tag -export RUST_G_VERSION=1.2.0 +export RUST_G_VERSION=3.0.0 #node version export NODE_VERSION=14 diff --git a/tools/tgs_scripts/PreCompile.sh b/tools/tgs_scripts/PreCompile.sh index 499073d9032..9f2f94646ed 100755 --- a/tools/tgs_scripts/PreCompile.sh +++ b/tools/tgs_scripts/PreCompile.sh @@ -12,6 +12,7 @@ cd "$1" . dependencies.sh cd "$original_dir" + # update rust-g if [ ! -d "rust-g" ]; then echo "Cloning rust-g..." From 1a0da8f95032be9b4b72c9ad232cd01dc1cd5283 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 02:26:08 +0300 Subject: [PATCH 46/55] Automatic changelog for PR #774 [ci skip] --- html/changelogs/AutoChangeLog-pr-774.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-774.yml diff --git a/html/changelogs/AutoChangeLog-pr-774.yml b/html/changelogs/AutoChangeLog-pr-774.yml new file mode 100644 index 00000000000..eb01bc4609b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-774.yml @@ -0,0 +1,4 @@ +author: "san7890" +delete-after: True +changes: + - code_imp: "The currently operating rust-g version on a live server is posted to places like the runtime.log, in the same place where the revision information and any applicable test merges already were. /:cl:" \ No newline at end of file From 5e270c8f9c3da1949c7d07bd45328eb594ed2a91 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 23 Nov 2023 01:13:59 +0000 Subject: [PATCH 47/55] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-774.yml | 4 ---- html/changelogs/AutoChangeLog-pr-780.yml | 4 ---- html/changelogs/archive/2023-11.yml | 9 +++++++++ 3 files changed, 9 insertions(+), 8 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-774.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-780.yml diff --git a/html/changelogs/AutoChangeLog-pr-774.yml b/html/changelogs/AutoChangeLog-pr-774.yml deleted file mode 100644 index eb01bc4609b..00000000000 --- a/html/changelogs/AutoChangeLog-pr-774.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "san7890" -delete-after: True -changes: - - code_imp: "The currently operating rust-g version on a live server is posted to places like the runtime.log, in the same place where the revision information and any applicable test merges already were. /:cl:" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-780.yml b/html/changelogs/AutoChangeLog-pr-780.yml deleted file mode 100644 index d94f0207782..00000000000 --- a/html/changelogs/AutoChangeLog-pr-780.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Nerev4r" -delete-after: True -changes: - - rscadd: "NanoTrasen, after extensive testing in a variety of stars' light wavelengths, have deemed their PDAs ready enough to actually use the onboard cameras they already had." \ No newline at end of file diff --git a/html/changelogs/archive/2023-11.yml b/html/changelogs/archive/2023-11.yml index 2462f64f68e..cc422becc6d 100644 --- a/html/changelogs/archive/2023-11.yml +++ b/html/changelogs/archive/2023-11.yml @@ -1146,3 +1146,12 @@ this in poor ways may displease the Gods. Woe upon your lineage. - rscadd: A single pack of glowshroom mycelium has been added to the Hearth's starting seed stores for the benefit of creative healers, shamans, and radiation enthusiasts. +2023-11-23: + Nerev4r: + - rscadd: NanoTrasen, after extensive testing in a variety of stars' light wavelengths, + have deemed their PDAs ready enough to actually use the onboard cameras they + already had. + san7890: + - code_imp: 'The currently operating rust-g version on a live server is posted to + places like the runtime.log, in the same place where the revision information + and any applicable test merges already were. /:cl:' From ac9d7c0979871ec1b00615aa99942c9ba9032973 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:08:50 +0300 Subject: [PATCH 48/55] Fixes borers being unable to inject chemicals (#781) Update BorerChem.jsx Co-authored-by: Iajret <8430839+Iajret@users.noreply.github.com> --- tgui/packages/tgui/interfaces/BorerChem.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/BorerChem.jsx b/tgui/packages/tgui/interfaces/BorerChem.jsx index 35eb63857fc..8f5210ed0fa 100644 --- a/tgui/packages/tgui/interfaces/BorerChem.jsx +++ b/tgui/packages/tgui/interfaces/BorerChem.jsx @@ -44,7 +44,7 @@ export const BorerChem = (props, context) => { disabled={data.onCooldown || data.notEnoughChemicals} onClick={() => act('inject', { - reagent: chemical.id, + reagent: chemical.title, }) } /> From 3ccbce2cea2c88455ef643fee170ad8453360655 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:09:22 +0300 Subject: [PATCH 49/55] Automatic changelog for PR #781 [ci skip] --- html/changelogs/AutoChangeLog-pr-781.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-781.yml diff --git a/html/changelogs/AutoChangeLog-pr-781.yml b/html/changelogs/AutoChangeLog-pr-781.yml new file mode 100644 index 00000000000..bc9451e99b6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-781.yml @@ -0,0 +1,4 @@ +author: "Iajret" +delete-after: True +changes: + - bugfix: "borers can once again fill their hosts with various wonders of chemistry" \ No newline at end of file From e62dcd7ee357a47e118c333b943d24b395f735fe Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:10:08 +0300 Subject: [PATCH 50/55] [MIRROR] Adds some more engi borg modules and buffs the engi borg RPED [MDB IGNORE] (#785) * Adds some more engi borg modules and buffs the engi borg RPED (#79374) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Autisem <36102060+Autisem@users.noreply.github.com> --- code/__DEFINES/nozzle_define.dm | 4 +++ code/game/machinery/rechargestation.dm | 5 ++- .../objects/items/robot/robot_upgrades.dm | 33 ++++++++++++++++++- code/game/objects/items/tanks/watertank.dm | 5 --- .../designs/mechfabricator_designs.dm | 11 +++++++ code/modules/research/stock_parts.dm | 8 ++++- code/modules/research/techweb/all_nodes.dm | 1 + tgstation.dme | 1 + 8 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 code/__DEFINES/nozzle_define.dm diff --git a/code/__DEFINES/nozzle_define.dm b/code/__DEFINES/nozzle_define.dm new file mode 100644 index 00000000000..06b43c1acc6 --- /dev/null +++ b/code/__DEFINES/nozzle_define.dm @@ -0,0 +1,4 @@ +/// 3 differnt modes for the firefighter extinquisher +#define EXTINGUISHER 0 +#define RESIN_LAUNCHER 1 +#define RESIN_FOAM 2 diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 415dacc9f17..f875617bd40 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -156,4 +156,7 @@ /obj/machinery/recharge_station/proc/process_occupant(seconds_per_tick) if(!occupant) return - SEND_SIGNAL(occupant, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, recharge_speed * seconds_per_tick / 2, repairs, sendmats) + var/main_draw = use_power_from_net(recharge_speed * seconds_per_tick, take_any = TRUE) //Pulls directly from the Powernet to dump into the cell + if(!main_draw) + return + SEND_SIGNAL(occupant, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, main_draw, repairs, sendmats) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 37c95a418db..b029a099875 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -598,7 +598,6 @@ /obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R, user = usr) . = ..() if(.) - var/obj/item/storage/part_replacer/cyborg/RPED = locate() in R if(RPED) to_chat(user, span_warning("This unit is already equipped with a RPED module!")) @@ -615,6 +614,38 @@ if (RPED) R.model.remove_module(RPED, TRUE) +/obj/item/borg/upgrade/inducer + name = "engineering integrated power inducer" + desc = "An integrated inducer that can charge a device's internal cell from power provided by the cyborg." + require_model = TRUE + model_type = list(/obj/item/robot_model/engineering, /obj/item/robot_model/saboteur) + model_flags = BORG_MODEL_ENGINEERING + +/obj/item/borg/upgrade/inducer/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + var/obj/item/inducer/cyborg/inter_inducer = locate() in R + if(inter_inducer) + return FALSE + inter_inducer = new(R.model) + R.model.basic_modules += inter_inducer + R.model.add_module(inter_inducer, FALSE, TRUE) + inter_inducer.cell = R.cell + +/obj/item/borg/upgrade/inducer/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + var/obj/item/inducer/cyborg/inter_inducer = locate() in R.model + if (inter_inducer) + R.model.remove_module(inter_inducer, TRUE) + inter_inducer.cell = null + +/obj/item/inducer/cyborg + name = "Internal inducer" + powertransfer = 1500 + icon = 'icons/obj/tools.dmi' + icon_state = "inducer-engi" + /obj/item/borg/upgrade/pinpointer name = "medical cyborg crew pinpointer" desc = "A crew pinpointer module for the medical cyborg. Permits remote access to the crew monitor." diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index 558c287e1e5..29dcdbcf702 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -205,11 +205,6 @@ to_chat(user, span_notice("You [amount_per_transfer_from_this == 10 ? "remove" : "affix"] the nozzle. You'll now use [amount_per_transfer_from_this] units per spray.")) //ATMOS FIRE FIGHTING BACKPACK - -#define EXTINGUISHER 0 -#define RESIN_LAUNCHER 1 -#define RESIN_FOAM 2 - /obj/item/watertank/atmos name = "backpack firefighter tank" desc = "A refrigerated and pressurized backpack tank with extinguisher nozzle, intended to fight fires. Swaps between extinguisher, resin launcher and a smaller scale resin foamer." diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 6a86bcbaae1..8c1bfa246a7 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -1581,6 +1581,17 @@ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_ENGINEERING ) +/datum/design/borg_upgrade_inducer + name = "Cyborg inducer" + id = "borg_upgrade_inducer" + build_type = MECHFAB + build_path = /obj/item/borg/upgrade/inducer + materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/silver = SHEET_MATERIAL_AMOUNT * 2) + construction_time = 120 + category = list( + RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_ENGINEERING + ) + /datum/design/borg_upgrade_circuit_app name = "Circuit Manipulator" id = "borg_upgrade_circuitapp" diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index 86b9f2dfafe..6638f56c1b4 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -197,12 +197,18 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good /obj/item/storage/part_replacer/cyborg //SKYRAT EDIT - ICON OVERRIDEN BY AESTHETICS - SEE MODULE name = "rapid part exchange device" - desc = "Special mechanical module made to store, sort, and apply standard machine parts." + desc = "Special mechanical module made to store, sort, and apply standard machine parts. This one has an extra large compartment for more parts." icon_state = "borgrped" inhand_icon_state = "RPED" lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' +/obj/item/storage/part_replacer/cyborg/Initialize(mapload) + . = ..() + atom_storage.max_slots = 400 + atom_storage.max_total_storage = 800 + atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC + /obj/item/storage/part_replacer/proc/get_sorted_parts(ignore_stacks = FALSE) var/list/part_list = list() //Assemble a list of current parts, then sort them by their rating! diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index d46bb35d8c3..28710bbfb8d 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -1017,6 +1017,7 @@ "borg_upgrade_lavaproof", "borg_upgrade_rped", "borg_upgrade_hypermod", + "borg_upgrade_inducer", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) diff --git a/tgstation.dme b/tgstation.dme index fe320badfde..f12d1d4b3dc 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -154,6 +154,7 @@ #include "code\__DEFINES\movespeed_modification.dm" #include "code\__DEFINES\multiz.dm" #include "code\__DEFINES\nitrile.dm" +#include "code\__DEFINES\nozzle_define.dm" #include "code\__DEFINES\nuclear_bomb.dm" #include "code\__DEFINES\obj_flags.dm" #include "code\__DEFINES\observers.dm" From 957a7183c66e2528e775e87fbfb5e4fe7946ed64 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:10:31 +0300 Subject: [PATCH 51/55] Automatic changelog for PR #785 [ci skip] --- html/changelogs/AutoChangeLog-pr-785.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-785.yml diff --git a/html/changelogs/AutoChangeLog-pr-785.yml b/html/changelogs/AutoChangeLog-pr-785.yml new file mode 100644 index 00000000000..ae557880c5f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-785.yml @@ -0,0 +1,6 @@ +author: "Autisem" +delete-after: True +changes: + - rscadd: "Cyborg inducer for engineering borgs" + - balance: "The borg RPED can hold as many part as the BSRPED now" + - balance: "Cyborg chargers now draw from the power net as cell chargers do" \ No newline at end of file From 8b5e65d78fde7090ef712afa6606725fb79fd14c Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:11:10 +0300 Subject: [PATCH 52/55] [MIRROR] [NO GBP] ACTUALLY Allows dogtags to fit into wallets [MDB IGNORE] (#777) * [NO GBP] ACTUALLY Allows dogtags to fit into wallets * Update wallets.dm * Update wallets.dm * Update wallets.dm * Update wallets.dm --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: OrionTheFox <76465278+OrionTheFox@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/game/objects/items/storage/wallets.dm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm index 7a75ba88674..7cb0afc2079 100644 --- a/code/game/objects/items/storage/wallets.dm +++ b/code/game/objects/items/storage/wallets.dm @@ -28,10 +28,14 @@ /obj/item/seeds, /obj/item/stack/medical, /obj/item/toy/crayon, + /obj/item/clothing/accessory/dogtag, /obj/item/coin, - /obj/item/food/chococoin, + /obj/item/coupon, /obj/item/dice, /obj/item/disk, + /obj/item/flashlight/pen, + /obj/item/folder/biscuit, + /obj/item/food/chococoin, /obj/item/implanter, /obj/item/laser_pointer, /obj/item/lighter, @@ -44,8 +48,11 @@ /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/pill, /obj/item/screwdriver, + /obj/item/seeds, /obj/item/spess_knife, - /obj/item/stamp), + /obj/item/stack/medical, + /obj/item/stamp, + /obj/item/toy/crayon), list(/obj/item/screwdriver/power)) /obj/item/storage/wallet/Exited(atom/movable/gone, direction) From 5b636ed82ae6e3fa8da9e2cd51f81f526fabf91c Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:22:29 +0300 Subject: [PATCH 53/55] Automatic changelog for PR #777 [ci skip] --- html/changelogs/AutoChangeLog-pr-777.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-777.yml diff --git a/html/changelogs/AutoChangeLog-pr-777.yml b/html/changelogs/AutoChangeLog-pr-777.yml new file mode 100644 index 00000000000..68d328d9913 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-777.yml @@ -0,0 +1,4 @@ +author: "OrionTheFox" +delete-after: True +changes: + - qol: "Allergy Dogtags (and any other dogtags, really) are now actually whitelisted to fit into wallets." \ No newline at end of file From 6edd548ad70fa47f71aff0ed86778f3287534bff Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 23 Nov 2023 12:28:28 +0000 Subject: [PATCH 54/55] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-777.yml | 4 ---- html/changelogs/AutoChangeLog-pr-781.yml | 4 ---- html/changelogs/AutoChangeLog-pr-785.yml | 6 ------ html/changelogs/archive/2023-11.yml | 9 +++++++++ 4 files changed, 9 insertions(+), 14 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-777.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-781.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-785.yml diff --git a/html/changelogs/AutoChangeLog-pr-777.yml b/html/changelogs/AutoChangeLog-pr-777.yml deleted file mode 100644 index 68d328d9913..00000000000 --- a/html/changelogs/AutoChangeLog-pr-777.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "OrionTheFox" -delete-after: True -changes: - - qol: "Allergy Dogtags (and any other dogtags, really) are now actually whitelisted to fit into wallets." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-781.yml b/html/changelogs/AutoChangeLog-pr-781.yml deleted file mode 100644 index bc9451e99b6..00000000000 --- a/html/changelogs/AutoChangeLog-pr-781.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Iajret" -delete-after: True -changes: - - bugfix: "borers can once again fill their hosts with various wonders of chemistry" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-785.yml b/html/changelogs/AutoChangeLog-pr-785.yml deleted file mode 100644 index ae557880c5f..00000000000 --- a/html/changelogs/AutoChangeLog-pr-785.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Autisem" -delete-after: True -changes: - - rscadd: "Cyborg inducer for engineering borgs" - - balance: "The borg RPED can hold as many part as the BSRPED now" - - balance: "Cyborg chargers now draw from the power net as cell chargers do" \ No newline at end of file diff --git a/html/changelogs/archive/2023-11.yml b/html/changelogs/archive/2023-11.yml index cc422becc6d..9764f72e362 100644 --- a/html/changelogs/archive/2023-11.yml +++ b/html/changelogs/archive/2023-11.yml @@ -1147,10 +1147,19 @@ - rscadd: A single pack of glowshroom mycelium has been added to the Hearth's starting seed stores for the benefit of creative healers, shamans, and radiation enthusiasts. 2023-11-23: + Autisem: + - rscadd: Cyborg inducer for engineering borgs + - balance: The borg RPED can hold as many part as the BSRPED now + - balance: Cyborg chargers now draw from the power net as cell chargers do + Iajret: + - bugfix: borers can once again fill their hosts with various wonders of chemistry Nerev4r: - rscadd: NanoTrasen, after extensive testing in a variety of stars' light wavelengths, have deemed their PDAs ready enough to actually use the onboard cameras they already had. + OrionTheFox: + - qol: Allergy Dogtags (and any other dogtags, really) are now actually whitelisted + to fit into wallets. san7890: - code_imp: 'The currently operating rust-g version on a live server is posted to places like the runtime.log, in the same place where the revision information From fb5783cba83a1fe2feb8b83fa48699741a1a13bf Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 21:25:48 +0300 Subject: [PATCH 55/55] [MIRROR] Reworks transformation sting to be temporarily in living mobs, forever in dead mobs (#764) * [MIRROR] Reworks transformation sting to be temporarily in living mobs, forever in dead mobs [MDB IGNORE] (#24002) * Reworks transformation sting to be temporarily in living mobs, forever in dead mobs * Modular updates * Recaches the icons generated in the `changeling` unit test * Pain * More tweaks * Disable unit test * Let's see if we can pass test temporarily * Makes transformation sting unobtainable more cleanly * Unit test * Cursed proc * Kill the unholy copy pasta Seriously this stuff is just awful. This is not maintainable. * test this * Update comments * Fixing the screenshot test, maybe? * grrr * Update changeling.dm * Attempt to fix this nonsense * Update changeling.dm * Update changeling.dm * Update changeling.dm * Update dna.dm * Fixes it? * Screenshot test * Update _traits.dm * Update _traits.dm * Fix this * Update dna.dm * Update dna.dm * Hmm * This proc needs a new name * I want to scream but I have no mutant parts * Fix * Update species.dm * Update species.dm * Update species.dm * Update species.dm * Some touch ups --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Jolly <70232195+Jolly-66@users.noreply.github.com> * FF species * adding our tesharies as valid species for tails and ears --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Jolly <70232195+Jolly-66@users.noreply.github.com> Co-authored-by: Iajret --- code/__DEFINES/traits/declarations.dm | 5 +- code/__DEFINES/~skyrat_defines/DNA.dm | 1 + code/__HELPERS/global_lists.dm | 2 +- code/__HELPERS/mobs.dm | 10 +- code/_globalvars/lists/flavor_misc.dm | 6 +- code/_globalvars/traits/_traits.dm | 6 +- code/_globalvars/traits/admin_tooling.dm | 2 - .../mutant_bodypart_overlay.dm | 16 ++- code/datums/components/irradiated.dm | 2 +- code/datums/diseases/dna_spread.dm | 2 +- code/datums/dna.dm | 84 +++++++++++---- code/datums/mutations/void_magnet.dm | 2 +- .../datums/quirks/negative_quirks/allergic.dm | 2 +- code/datums/sprite_accessories.dm | 6 +- code/datums/status_effects/debuffs/debuffs.dm | 8 +- .../debuffs/dna_transformation.dm | 91 ++++++++++++++++ .../status_effects/debuffs/drowsiness.dm | 2 +- code/datums/status_effects/debuffs/drunk.dm | 2 +- code/datums/status_effects/neutral.dm | 2 +- code/datums/wounds/bones.dm | 2 +- code/datums/wounds/burns.dm | 2 +- code/datums/wounds/pierce.dm | 2 +- code/datums/wounds/slash.dm | 2 +- code/game/machinery/stasis.dm | 6 +- code/modules/admin/create_mob.dm | 46 ++++---- .../antagonists/changeling/changeling.dm | 4 +- .../changeling/powers/tiny_prick.dm | 59 +++++++---- .../nightmare/nightmare_species.dm | 1 - .../bitrunning/components/netpod_healing.dm | 7 ++ code/modules/mapping/mapping_helpers.dm | 1 - .../mob/living/carbon/alien/larva/life.dm | 2 +- .../mob/living/carbon/human/_species.dm | 39 ++++--- code/modules/mob/living/carbon/human/dummy.dm | 22 ++-- .../mob/living/carbon/human/examine.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 4 +- code/modules/mob/living/carbon/human/life.dm | 2 +- .../carbon/human/species_types/android.dm | 11 +- .../carbon/human/species_types/ethereal.dm | 6 +- .../carbon/human/species_types/felinid.dm | 5 +- .../carbon/human/species_types/golems.dm | 13 ++- .../carbon/human/species_types/humans.dm | 4 - .../human/species_types/lizardpeople.dm | 5 +- .../carbon/human/species_types/monkeys.dm | 8 +- .../carbon/human/species_types/mothmen.dm | 7 +- .../carbon/human/species_types/plasmamen.dm | 5 +- .../carbon/human/species_types/podpeople.dm | 3 - .../carbon/human/species_types/skeletons.dm | 8 +- .../carbon/human/species_types/zombies.dm | 9 +- code/modules/mob/living/carbon/life.dm | 2 +- code/modules/mob/living/life.dm | 2 +- code/modules/mob/living/living.dm | 2 +- code/modules/surgery/bodyparts/_bodyparts.dm | 4 +- code/modules/surgery/organs/external/tails.dm | 14 ++- code/modules/unit_tests/_unit_tests.dm | 1 + code/modules/unit_tests/changeling.dm | 99 ++++++++++++++++++ .../transformation_sting_appearances.png | Bin 0 -> 1274 bytes .../changeling/powers/tiny_prick.dm | 3 + .../code/modules/client/preferences.dm | 11 +- .../client/preferences/mutant_parts.dm | 3 + .../code/modules/mob/living/human/species.dm | 2 +- .../modules/better_vox/code/vox_species.dm | 7 +- .../modules/customization/__DEFINES/lists.dm | 11 ++ .../customization/__HELPERS/global_lists.dm | 13 +++ .../modules/customization/datums/dna.dm | 63 ----------- .../mob/dead/new_player/preferences_setup.dm | 2 +- .../new_player/sprite_accessories/ears.dm | 3 +- .../new_player/sprite_accessories/tails.dm | 2 +- .../new_player/sprite_accessories/wings.dm | 2 +- .../modules/mob/living/carbon/human/human.dm | 5 +- .../mob/living/carbon/human/species.dm | 56 ++++++---- .../mob/living/carbon/human/species/akula.dm | 20 ++-- .../living/carbon/human/species/aquatic.dm | 26 +++-- .../mob/living/carbon/human/species/ghoul.dm | 12 ++- .../species/hemophage/hemophage_species.dm | 8 +- .../living/carbon/human/species/humanoid.dm | 20 ++-- .../mob/living/carbon/human/species/insect.dm | 24 +++-- .../mob/living/carbon/human/species/lizard.dm | 34 +++--- .../mob/living/carbon/human/species/mammal.dm | 35 ++++--- .../mob/living/carbon/human/species/monkey.dm | 6 +- .../mob/living/carbon/human/species/moth.dm | 18 ++-- .../living/carbon/human/species/podweak.dm | 10 +- .../carbon/human/species/roundstartslime.dm | 24 +++-- .../mob/living/carbon/human/species/skrell.dm | 16 ++- .../living/carbon/human/species/tajaran.dm | 23 ++-- .../mob/living/carbon/human/species/unathi.dm | 29 ++--- .../mob/living/carbon/human/species/vox.dm | 24 +++-- .../living/carbon/human/species/vulpkanin.dm | 23 ++-- .../mob/living/carbon/human/species/xeno.dm | 16 +-- .../code/wounds/synth/blunt/robotic_blunt.dm | 2 +- .../wounds/synth/blunt/secures_internals.dm | 2 +- .../code/wounds/synth/robotic_burns.dm | 2 +- .../code/wounds/synth/robotic_slash.dm | 2 +- .../modules/modular_implants/code/nifs.dm | 2 +- .../stasisrework/code/stasissleeper.dm | 6 +- .../modules/synths/code/species/synthetic.dm | 23 ++-- .../modules/teshari/code/_teshari.dm | 12 ++- tff_modular/modules/nabbers/code/_nabbers.dm | 8 +- .../modules/teshari_reborn/code/teshari.dm | 13 ++- tgstation.dme | 2 + 99 files changed, 801 insertions(+), 486 deletions(-) create mode 100644 code/datums/status_effects/debuffs/dna_transformation.dm create mode 100644 code/modules/unit_tests/changeling.dm create mode 100644 code/modules/unit_tests/screenshots/transformation_sting_appearances.png create mode 100644 modular_skyrat/master_files/code/modules/antagonists/changeling/powers/tiny_prick.dm diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 6c774453782..536b1023a5a 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -75,6 +75,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_GUN_NATURAL "gunnatural" /// Causes death-like unconsciousness #define TRAIT_DEATHCOMA "deathcoma" +/// The mob has the stasis effect. +/// Does nothing on its own, applied via status effect. +#define TRAIT_STASIS "in_stasis" /// Makes the owner appear as dead to most forms of medical examination #define TRAIT_FAKEDEATH "fakedeath" #define TRAIT_DISFIGURED "disfigured" @@ -161,8 +164,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_LIVERLESS_METABOLISM "liverless_metabolism" /// Humans with this trait cannot be turned into zombies #define TRAIT_NO_ZOMBIFY "no_zombify" -/// Humans with this trait cannot be affected by changeling transformation stings -#define TRAIT_NO_TRANSFORMATION_STING "no_transformation_sting" /// Carbons with this trait can't have their DNA copied by diseases nor changelings #define TRAIT_NO_DNA_COPY "no_dna_copy" /// Carbons with this trait cant have their dna scrambled by genetics or a disease retrovirus. diff --git a/code/__DEFINES/~skyrat_defines/DNA.dm b/code/__DEFINES/~skyrat_defines/DNA.dm index 8e9c220c9e1..6ac4d165ee6 100644 --- a/code/__DEFINES/~skyrat_defines/DNA.dm +++ b/code/__DEFINES/~skyrat_defines/DNA.dm @@ -34,6 +34,7 @@ // Defines for mutant bodyparts indexes #define MUTANT_INDEX_NAME "name" +#define MUTANT_INDEX_CAN_RANDOMIZE "can_randomize" #define MUTANT_INDEX_COLOR_LIST "color" #define MUTANT_INDEX_EMISSIVE_LIST "emissive" diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 8eacab9e2d5..c6fa9d09ac8 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -17,9 +17,9 @@ //SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION /* init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/tails, GLOB.tails_list, add_blank = TRUE) init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human, add_blank = TRUE) init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard, add_blank = TRUE) + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey, GLOB.tails_list_monkey, add_blank = TRUE) init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index df98ab953fa..5a408937a04 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -58,7 +58,7 @@ /proc/random_backpack() return pick(GLOB.backpacklist) -//SKYRAT EDIT REMOVAL - CUSTOMIZATION (moved to modular) +// SKYRAT EDIT REMOVAL - CUSTOMIZATION (moved to modular) /* /proc/random_features() if(!GLOB.tails_list.len) @@ -113,9 +113,8 @@ "tail_monkey" = "Monkey", "pod_hair" = pick(GLOB.pod_hair_list), )) - */ - //SKYRAT EDIT REMOVAL END - +*/ +//SKYRAT EDIT REMOVAL END /proc/random_hairstyle(gender) switch(gender) @@ -589,8 +588,6 @@ GLOBAL_LIST_EMPTY(species_list) #define ISADVANCEDTOOLUSER(mob) (HAS_TRAIT(mob, TRAIT_ADVANCEDTOOLUSER) && !HAS_TRAIT(mob, TRAIT_DISCOORDINATED_TOOL_USER)) -#define IS_IN_STASIS(mob) (mob.has_status_effect(/datum/status_effect/grouped/stasis) || mob.has_status_effect(/datum/status_effect/embryonic)) - /// Gets the client of the mob, allowing for mocking of the client. /// You only need to use this if you know you're going to be mocking clients somewhere else. #define GET_CLIENT(mob) (##mob.client || ##mob.mock_client) @@ -631,7 +628,6 @@ GLOBAL_LIST_EMPTY(species_list) moblist += mob_to_sort // SKYRAT EDIT END - SOULCATCHERS return moblist - ///returns a mob type controlled by a specified ckey /proc/get_mob_by_ckey(key) if(!key) diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index dbf9a47f9f7..afb15912694 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -30,9 +30,9 @@ GLOBAL_LIST_EMPTY(legs_list) GLOBAL_LIST_EMPTY(animated_spines_list) //Mutant Human bits -GLOBAL_LIST_EMPTY(tails_list) -GLOBAL_LIST_EMPTY(tails_list_human) //Only exists for preference choices. Use "tails_list" otherwise. -GLOBAL_LIST_EMPTY(tails_list_lizard) //See above! +GLOBAL_LIST_EMPTY(tails_list_human) +GLOBAL_LIST_EMPTY(tails_list_lizard) +GLOBAL_LIST_EMPTY(tails_list_monkey) GLOBAL_LIST_EMPTY(ears_list) GLOBAL_LIST_EMPTY(wings_list) GLOBAL_LIST_EMPTY(wings_open_list) diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index d76376ded36..b1d1c5eaac3 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -287,7 +287,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NO_JUMPSUIT" = TRAIT_NO_JUMPSUIT, "TRAIT_NO_MINDSWAP" = TRAIT_NO_MINDSWAP, "TRAIT_NO_MIRROR_REFLECTION" = TRAIT_NO_MIRROR_REFLECTION, - //"TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM, SKYRAT EDIT - TODO - These require transformation sting pr "TRAIT_NO_SLIP_ALL" = TRAIT_NO_SLIP_ALL, "TRAIT_NO_SLIP_ICE" = TRAIT_NO_SLIP_ICE, "TRAIT_NO_SLIP_SLIDE" = TRAIT_NO_SLIP_SLIDE, @@ -366,7 +365,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_ROCK_METAMORPHIC" = TRAIT_ROCK_METAMORPHIC, "TRAIT_ROD_SUPLEX" = TRAIT_ROD_SUPLEX, "TRAIT_SABRAGE_PRO" = TRAIT_SABRAGE_PRO, - "TRAIT_SACRIFICED" = TRAIT_SACRIFICED, // SKYRAT EDIT ADDITION + "TRAIT_SACRIFICED" = TRAIT_SACRIFICED, "TRAIT_SECURITY_HUD" = TRAIT_SECURITY_HUD, "TRAIT_SEE_GLASS_COLORS" = TRAIT_SEE_GLASS_COLORS, "TRAIT_SELF_AWARE" = TRAIT_SELF_AWARE, @@ -394,7 +393,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_SPRAY_PAINTABLE" = TRAIT_SPRAY_PAINTABLE, "TRAIT_STABLEHEART" = TRAIT_STABLEHEART, "TRAIT_STABLELIVER" = TRAIT_STABLELIVER, - //"TRAIT_STASIS" = TRAIT_STASIS, TODO - SKYRAT EDIT - TODO - These require transformation sting pr + "TRAIT_STASIS" = TRAIT_STASIS, "TRAIT_STRONG_GRABBER" = TRAIT_STRONG_GRABBER, "TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE, "TRAIT_SUCCUMB_OVERRIDE" = TRAIT_SUCCUMB_OVERRIDE, @@ -423,7 +422,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_UNBREAKABLE" = TRAIT_UNBREAKABLE, "TRAIT_UNDENSE" = TRAIT_UNDENSE, "TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE, - //"TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE, SKYRAT EDIT - TODO - These require transformation sting pr "TRAIT_UNINTELLIGIBLE_SPEECH" = TRAIT_UNINTELLIGIBLE_SPEECH, "TRAIT_UNKNOWN" = TRAIT_UNKNOWN, "TRAIT_UNNATURAL_RED_GLOWY_EYES" = TRAIT_UNNATURAL_RED_GLOWY_EYES, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 388ea89cc7e..b65a31c79f7 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -129,7 +129,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_NO_BLOOD_OVERLAY" = TRAIT_NO_BLOOD_OVERLAY, "TRAIT_NO_DNA_COPY" = TRAIT_NO_DNA_COPY, "TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE, - //"TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM, SKYRAT EDIT - TODO - These require transformation sting pr "TRAIT_NO_SLIP_ALL" = TRAIT_NO_SLIP_ALL, "TRAIT_NO_SLIP_ICE" = TRAIT_NO_SLIP_ICE, "TRAIT_NO_SLIP_SLIDE" = TRAIT_NO_SLIP_SLIDE, @@ -215,7 +214,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_UI_BLOCKED" = TRAIT_UI_BLOCKED, "TRAIT_UNDENSE" = TRAIT_UNDENSE, "TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE, - //"TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE, SKYRAT EDIT - TODO - These require transformation sting pr "TRAIT_UNINTELLIGIBLE_SPEECH" = TRAIT_UNINTELLIGIBLE_SPEECH, "TRAIT_UNKNOWN" = TRAIT_UNKNOWN, "TRAIT_UNNATURAL_RED_GLOWY_EYES" = TRAIT_UNNATURAL_RED_GLOWY_EYES, diff --git a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm index 486f9411934..7dd453163c5 100644 --- a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm +++ b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm @@ -123,12 +123,18 @@ ///Sprite accessories are singletons, stored list("Big Snout" = instance of /datum/sprite_accessory/snout/big), so here we get that singleton /datum/bodypart_overlay/mutant/proc/fetch_sprite_datum(datum/sprite_accessory/accessory_path) - var/list/feature_list = get_global_feature_list() - - return feature_list[initial(accessory_path.name)] + return fetch_sprite_datum_from_name(initial(accessory_path.name)) ///Get the singleton from the sprite name /datum/bodypart_overlay/mutant/proc/fetch_sprite_datum_from_name(accessory_name) var/list/feature_list = get_global_feature_list() - - return feature_list[accessory_name] + var/found = feature_list[accessory_name] + if(found) + return found + + if(!length(feature_list)) + CRASH("External organ [type] returned no sprite datums from get_global_feature_list(), so no accessories could be found!") + else if(accessory_name) + CRASH("External organ [type] couldn't find sprite accessory [accessory_name]!") + else + CRASH("External organ [type] had fetch_sprite_datum called with a null accessory name!") diff --git a/code/datums/components/irradiated.dm b/code/datums/components/irradiated.dm index c8a57f3761a..bffd56459bf 100644 --- a/code/datums/components/irradiated.dm +++ b/code/datums/components/irradiated.dm @@ -96,7 +96,7 @@ process_tox_damage(human_parent, seconds_per_tick) /datum/component/irradiated/proc/should_halt_effects(mob/living/carbon/human/target) - if (IS_IN_STASIS(target)) + if (HAS_TRAIT(target, TRAIT_STASIS)) return TRUE if (HAS_TRAIT(target, TRAIT_HALT_RADIATION_EFFECTS)) diff --git a/code/datums/diseases/dna_spread.dm b/code/datums/diseases/dna_spread.dm index 7783465aabd..48ca9506e2e 100644 --- a/code/datums/diseases/dna_spread.dm +++ b/code/datums/diseases/dna_spread.dm @@ -24,7 +24,7 @@ return FALSE //Only species that can be spread by transformation sting can be spread by the retrovirus - if(HAS_TRAIT(affected_mob, TRAIT_NO_TRANSFORMATION_STING) || HAS_TRAIT(affected_mob, TRAIT_NO_DNA_COPY)) + if(HAS_TRAIT(affected_mob, TRAIT_NO_DNA_COPY)) cure() return FALSE diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 2d745cb6290..d27779387ed 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -84,8 +84,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) var/blood_type ///The type of mutant race the player is if applicable (i.e. potato-man) var/datum/species/species = new /datum/species/human - ///first value is mutant color - var/list/features = list("FFF") + /// Assoc list of feature keys to their value + /// Note if you set these manually, and do not update [unique_features] afterwards, it will likely be reset. + var/list/features = list("mcolor" = "#FFFFFF") ///Stores the hashed values of the person's non-human features var/unique_features ///Stores the real name of the person who originally got this dna datum. Used primarely for changelings, @@ -135,12 +136,17 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) destination.dna.features = features.Copy() destination.dna.real_name = real_name destination.dna.temporary_mutations = temporary_mutations.Copy() + //SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION + destination.dna.mutant_bodyparts = mutant_bodyparts.Copy() + destination.dna.body_markings = body_markings.Copy() + destination.dna.update_body_size() + //SKYRAT EDIT ADDITION END if(transfer_SE) destination.dna.mutation_index = mutation_index destination.dna.default_mutation_genes = default_mutation_genes if(transfer_species) //destination.set_species(species.type, icon_update=0) - ORIGINAL - destination.set_species(species.type, TRUE, null, features.Copy(), mutant_bodyparts.Copy(), body_markings.Copy()) //SKYRAT EDIT CHANGE - CUSTOMIZATION + destination.set_species(species.type, TRUE, FALSE, features.Copy(), mutant_bodyparts.Copy(), body_markings.Copy()) //SKYRAT EDIT CHANGE - CUSTOMIZATION /datum/dna/proc/copy_dna(datum/dna/new_dna) new_dna.unique_enzymes = unique_enzymes @@ -381,7 +387,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(DNA_LIZARD_MARKINGS_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len)) if(DNA_TAIL_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list.Find(features["tail_lizard"]), GLOB.tails_list.len)) + set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_human.Find(features["tail_cat"]), GLOB.tails_list_human.len)) + if(DNA_LIZARD_TAIL_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len)) if(DNA_SNOUT_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.snouts_list.Find(features["snout"]), GLOB.snouts_list.len)) if(DNA_HORNS_BLOCK) @@ -468,25 +476,41 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(message) to_chat(holder, message) -//used to update dna UI, UE, and dna.real_name. +/// Updates the UI, UE, and UF of the DNA according to the features, appearance, name, etc. of the DNA / holder. /datum/dna/proc/update_dna_identity() unique_identity = generate_unique_identity() unique_enzymes = generate_unique_enzymes() unique_features = generate_unique_features() -//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular) -/* -/datum/dna/proc/initialize_dna(newblood_type, skip_index = FALSE) +/** + * Sets up DNA codes and initializes some features. + * + * * newblood_type - Optional, the blood type to set the DNA to + * * create_mutation_blocks - If true, generate_dna_blocks is called, which is used to set up mutation blocks (what a mob can naturally mutate). + * * randomize_features - If true, all entries in the features list will be randomized. + */ +/datum/dna/proc/initialize_dna(newblood_type, create_mutation_blocks = TRUE, randomize_features = TRUE) if(newblood_type) blood_type = newblood_type - unique_enzymes = generate_unique_enzymes() - unique_identity = generate_unique_identity() - if(!skip_index) //I hate this + if(create_mutation_blocks) //I hate this generate_dna_blocks() - features = random_features() - unique_features = generate_unique_features() -*/ -//SKYRAT EDIT REMOVAL END + mutant_bodyparts = species.get_mutant_bodyparts(features, existing_mutant_bodyparts = randomize_features ? list() : mutant_bodyparts) // SKYRAT EDIT ADDITION + if(randomize_features) + /* SKYRAT EDIT REMOVAL - We don't really want this, do we? We get the same effect from get_mutant_bodyparts() on our end, but without mixing up weird species features. + var/static/list/all_species_protoypes + if(isnull(all_species_protoypes)) + all_species_protoypes = list() + for(var/species_path in subtypesof(/datum/species)) + all_species_protoypes += new species_path() + + for(var/datum/species/random_species as anything in all_species_protoypes) + features |= random_species.randomize_features() + SKYRAT EDIT REMOVAL END */ + body_markings = species.get_random_body_markings(features) // SKYRAT EDIT ADDITION + + features["mcolor"] = "#[random_color()]" + + update_dna_identity() /datum/dna/stored //subtype used by brain mob's stored_dna @@ -519,9 +543,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) stored_dna.species = mrace //not calling any species update procs since we're a brain, not a monkey/human -//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular_skyrat/modules/customization/code/datums/dna.dm) -/* -/mob/living/carbon/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE) +/mob/living/carbon/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE, list/override_features, list/override_mutantparts, list/override_markings) // SKYRAT EDIT CHANGE - ORIGINAL: /mob/living/carbon/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE) if(QDELETED(src)) CRASH("You're trying to change your species post deletion, this is a recipe for madness") if(isnull(mrace)) @@ -547,10 +569,32 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if (old_species.properly_gained) old_species.on_species_loss(src, new_race, pref_load) + // SKYRAT EDIT ADDITION START - BODYPARTS AND FEATURES + // We need to instantiate the list with compatible mutant parts so we don't break things + + if(override_mutantparts && override_mutantparts.len) + for(var/feature in dna.mutant_bodyparts) + override_mutantparts[feature] = dna.mutant_bodyparts[feature] + dna.mutant_bodyparts = override_mutantparts + + if(override_markings && override_markings.len) + for(var/feature in dna.body_markings) + override_markings[feature] = dna.body_markings[feature] + dna.body_markings = override_markings + + if(override_features && override_features.len) + for(var/feature in dna.features) + override_features[feature] = dna.features[feature] + dna.features = override_features + + apply_customizable_dna_features_to_species() + dna.unique_features = dna.generate_unique_features() + + dna.update_body_size() + // SKYRAT EDIT ADDITION END + dna.species.on_species_gain(src, old_species, pref_load) log_mob_tag("TAG: [tag] SPECIES: [key_name(src)] \[[mrace]\]") -*/ -//SKYRAT EDIT REMOVAL END /mob/living/carbon/human/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE) ..() diff --git a/code/datums/mutations/void_magnet.dm b/code/datums/mutations/void_magnet.dm index d6636b0b630..48f04eda636 100644 --- a/code/datums/mutations/void_magnet.dm +++ b/code/datums/mutations/void_magnet.dm @@ -60,7 +60,7 @@ /datum/action/cooldown/spell/void/cursed/proc/on_life(mob/living/source, seconds_per_tick, times_fired) SIGNAL_HANDLER - if(!isliving(source) || IS_IN_STASIS(source) || source.stat == DEAD || HAS_TRAIT(source, TRAIT_NO_TRANSFORM)) + if(!isliving(source) || HAS_TRAIT(source, TRAIT_STASIS) || source.stat == DEAD || HAS_TRAIT(source, TRAIT_NO_TRANSFORM)) return if(!is_valid_target(source)) diff --git a/code/datums/quirks/negative_quirks/allergic.dm b/code/datums/quirks/negative_quirks/allergic.dm index d6a510f62b6..64b4c560bde 100644 --- a/code/datums/quirks/negative_quirks/allergic.dm +++ b/code/datums/quirks/negative_quirks/allergic.dm @@ -48,7 +48,7 @@ if(!iscarbon(quirk_holder)) return - if(IS_IN_STASIS(quirk_holder)) + if(HAS_TRAIT(quirk_holder, TRAIT_STASIS)) return if(quirk_holder.stat == DEAD) diff --git a/code/datums/sprite_accessories.dm b/code/datums/sprite_accessories.dm index 44f77fc1d76..c0c6578437e 100644 --- a/code/datums/sprite_accessories.dm +++ b/code/datums/sprite_accessories.dm @@ -1783,11 +1783,13 @@ color_src = HAIR_COLOR /datum/sprite_accessory/tails/monkey - name = "Monkey" icon = 'icons/mob/human/species/monkey/monkey_tail.dmi' - icon_state = "monkey" color_src = FALSE +/datum/sprite_accessory/tails/monkey/standard + name = "Monkey" + icon_state = "monkey" + /datum/sprite_accessory/pod_hair icon = 'icons/mob/human/species/podperson_hair.dmi' em_block = TRUE diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index fccb6a5d8f5..2865a230f43 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -278,8 +278,8 @@ . = ..() if(!.) return - owner.add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_NUMBED), TRAIT_STATUS_EFFECT(id))//SKYRAT EDIT START - STASIS APPLIES NUMBING - owner.throw_alert("stasis numbed", /atom/movable/screen/alert/numbed) //SKYRAT EDIT END + owner.add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_STASIS, TRAIT_NUMBED), TRAIT_STATUS_EFFECT(id)) // SKYRAT EDIT CHANGE - ORIGINAL: owner.add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_STASIS), TRAIT_STATUS_EFFECT(id)) + owner.throw_alert("stasis numbed", /atom/movable/screen/alert/numbed) //SKYRAT EDIT ADDITION - STASIS APPLIES NUMBED owner.add_filter("stasis_status_ripple", 2, list("type" = "ripple", "flags" = WAVE_BOUNDED, "radius" = 0, "size" = 2)) var/filter = owner.get_filter("stasis_status_ripple") animate(filter, radius = 0, time = 0.2 SECONDS, size = 2, easing = JUMP_EASING, loop = -1, flags = ANIMATION_PARALLEL) @@ -294,8 +294,8 @@ owner.Sleeping(15 SECONDS) //SKYRAT EDIT END /datum/status_effect/grouped/stasis/on_remove() - owner.remove_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_NUMBED), TRAIT_STATUS_EFFECT(id)) //SKYRAT EDIT START - STASIS END REMOVES NUMBING - owner.clear_alert("stasis numbed") //SKYRAT EDIT END + owner.remove_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_STASIS, TRAIT_NUMBED), TRAIT_STATUS_EFFECT(id)) // SKYRAT EDIT CHANGE - ORIGINAL: owner.remove_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_STASIS), TRAIT_STATUS_EFFECT(id)) + owner.clear_alert("stasis numbed") //SKYRAT EDIT ADDITION - STASIS APPLIED NUMBED owner.remove_filter("stasis_status_ripple") update_time_of_death() if(iscarbon(owner)) diff --git a/code/datums/status_effects/debuffs/dna_transformation.dm b/code/datums/status_effects/debuffs/dna_transformation.dm new file mode 100644 index 00000000000..33b6eb1d913 --- /dev/null +++ b/code/datums/status_effects/debuffs/dna_transformation.dm @@ -0,0 +1,91 @@ +/// Transforms a carbon mob into a new DNA for a set amount of time, +/// then turns them back to how they were before transformation. +/datum/status_effect/temporary_transformation + id = "temp_dna_transformation" + tick_interval = -1 + duration = 1 MINUTES // set in on creation, this just needs to be any value to process + alert_type = null + /// A reference to a COPY of the DNA that the mob will be transformed into. + var/datum/dna/new_dna + /// A reference to a COPY of the DNA of the mob prior to transformation. + var/datum/dna/old_dna + +/datum/status_effect/temporary_transformation/Destroy() + . = ..() // parent must be called first, so we clear DNA refs AFTER transforming back... yeah i know + QDEL_NULL(new_dna) + QDEL_NULL(old_dna) + +/datum/status_effect/temporary_transformation/on_creation(mob/living/new_owner, new_duration = 1 MINUTES, datum/dna/dna_to_copy) + src.duration = (new_duration == INFINITY) ? -1 : new_duration + src.new_dna = new() + src.old_dna = new() + dna_to_copy.copy_dna(new_dna) + return ..() + +/datum/status_effect/temporary_transformation/on_apply() + if(!iscarbon(owner)) + return FALSE + + var/mob/living/carbon/transforming = owner + if(!transforming.has_dna()) + return FALSE + + // Save the old DNA + transforming.dna.copy_dna(old_dna) + // Makes them into the new DNA + new_dna.transfer_identity(transforming) + transforming.real_name = new_dna.real_name + transforming.name = transforming.get_visible_name() + transforming.updateappearance(mutcolor_update = TRUE) + transforming.domutcheck() + return TRUE + +/datum/status_effect/temporary_transformation/on_remove() + var/mob/living/carbon/transforming = owner + + if(!QDELING(owner)) // Don't really need to do appearance stuff if we're being deleted + old_dna.transfer_identity(transforming) + transforming.updateappearance(mutcolor_update = TRUE) + transforming.domutcheck() + + transforming.real_name = old_dna.real_name // Name is fine though + transforming.name = transforming.get_visible_name() + +/datum/status_effect/temporary_transformation/trans_sting + /// Tracks the time left on the effect when the owner last died. Used to pause the effect. + var/time_before_pause = -1 + /// Signals which we react to to determine if we should pause the effect. + var/static/list/update_on_signals = list( + COMSIG_MOB_STATCHANGE, + SIGNAL_ADDTRAIT(TRAIT_STASIS), + SIGNAL_REMOVETRAIT(TRAIT_STASIS), + SIGNAL_ADDTRAIT(TRAIT_DEATHCOMA), + SIGNAL_REMOVETRAIT(TRAIT_DEATHCOMA), + ) + +/datum/status_effect/temporary_transformation/trans_sting/on_apply() + . = ..() + if(!.) + return + RegisterSignals(owner, update_on_signals, PROC_REF(pause_effect)) + pause_effect(owner) // for if we sting a dead guy + +/datum/status_effect/temporary_transformation/trans_sting/on_remove() + . = ..() + UnregisterSignal(owner, update_on_signals) + +/datum/status_effect/temporary_transformation/trans_sting/proc/pause_effect(mob/living/source) + SIGNAL_HANDLER + + // Pause if we're dead, appear dead, or in stasis + if(source.stat == DEAD || HAS_TRAIT(source, TRAIT_DEATHCOMA) || HAS_TRAIT(source, TRAIT_STASIS)) + if(duration == -1) + return // Already paused + + time_before_pause = duration - world.time + duration = -1 + + // Resume if we're none of the above and also were paused + else if(time_before_pause != -1) + duration = time_before_pause + world.time + time_before_pause = -1 diff --git a/code/datums/status_effects/debuffs/drowsiness.dm b/code/datums/status_effects/debuffs/drowsiness.dm index ebf1f43796c..cd99e879066 100644 --- a/code/datums/status_effects/debuffs/drowsiness.dm +++ b/code/datums/status_effects/debuffs/drowsiness.dm @@ -29,7 +29,7 @@ /datum/status_effect/drowsiness/tick(seconds_between_ticks) // You do not feel drowsy while unconscious or in stasis - if(owner.stat >= UNCONSCIOUS || IS_IN_STASIS(owner)) + if(owner.stat >= UNCONSCIOUS || HAS_TRAIT(owner, TRAIT_STASIS)) return // Resting helps against drowsiness diff --git a/code/datums/status_effects/debuffs/drunk.dm b/code/datums/status_effects/debuffs/drunk.dm index e46915922e5..061c008def8 100644 --- a/code/datums/status_effects/debuffs/drunk.dm +++ b/code/datums/status_effects/debuffs/drunk.dm @@ -65,7 +65,7 @@ /datum/status_effect/inebriated/tick(seconds_between_ticks) // Drunk value does not decrease while dead or in stasis - if(owner.stat == DEAD || IS_IN_STASIS(owner)) + if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_STASIS)) return // Every tick, the drunk value decrases by diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 48b14f36cd0..416fe031341 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -526,7 +526,7 @@ monkey_tail.Insert(human_mob, drop_if_replaced = FALSE) var/datum/species/human_species = human_mob.dna?.species if(human_species) - human_species.randomize_features(human_mob) + human_species.randomize_active_features(human_mob) human_species.randomize_active_underwear(human_mob) owner.remove_status_effect(/datum/status_effect/eigenstasium) diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index d4624acbb92..1df5ff689ff 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -75,7 +75,7 @@ /datum/wound/blunt/bone/handle_process(seconds_per_tick, times_fired) . = ..() - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return if(limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group && world.time > next_trauma_cycle) diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm index 39e91d06fb6..c041c4fd003 100644 --- a/code/datums/wounds/burns.dm +++ b/code/datums/wounds/burns.dm @@ -36,7 +36,7 @@ /datum/wound/burn/flesh/handle_process(seconds_per_tick, times_fired) - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return . = ..() diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index ec166584632..7304d21365c 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -64,7 +64,7 @@ return BLOOD_FLOW_STEADY /datum/wound/pierce/bleed/handle_process(seconds_per_tick, times_fired) - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW)) diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index 4475d95f508..d17b59cf80b 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -134,7 +134,7 @@ /datum/wound/slash/flesh/handle_process(seconds_per_tick, times_fired) - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return // in case the victim has the NOBLOOD trait, the wound will simply not clot on it's own diff --git a/code/game/machinery/stasis.dm b/code/game/machinery/stasis.dm index 8bcdba43d05..b3020c8d749 100644 --- a/code/game/machinery/stasis.dm +++ b/code/game/machinery/stasis.dm @@ -52,7 +52,7 @@ /obj/machinery/stasis/Exited(atom/movable/gone, direction) if(gone == occupant) var/mob/living/L = gone - if(IS_IN_STASIS(L)) + if(HAS_TRAIT(L, TRAIT_STASIS)) thaw_them(L) return ..() @@ -139,9 +139,9 @@ return var/mob/living/L_occupant = occupant if(stasis_running()) - if(!IS_IN_STASIS(L_occupant)) + if(!HAS_TRAIT(L_occupant, TRAIT_STASIS)) chill_out(L_occupant) - else if(IS_IN_STASIS(L_occupant)) + else if(HAS_TRAIT(L_occupant, TRAIT_STASIS)) thaw_them(L_occupant) /obj/machinery/stasis/screwdriver_act(mob/living/user, obj/item/I) diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index 36dd0416bde..8c574d207b2 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -10,36 +10,28 @@ user << browse(create_panel_helper(create_mob_html), "window=create_mob;size=425x475") -/proc/randomize_human(mob/living/carbon/human/human) - if(human.dna.species.sexes) - human.gender = pick(MALE, FEMALE, PLURAL, NEUTER) - else - human.gender = PLURAL +/** + * Randomizes everything about a human, including DNA and name + */ +/proc/randomize_human(mob/living/carbon/human/human, randomize_mutations = FALSE) + human.gender = human.dna.species.sexes ? pick(MALE, FEMALE, PLURAL, NEUTER) : PLURAL human.physique = human.gender human.real_name = human.dna?.species.random_name(human.gender) || random_unique_name(human.gender) - human.name = human.real_name - human.hairstyle = random_hairstyle(human.gender) - human.facial_hairstyle = random_facial_hairstyle(human.gender) - human.hair_color = "#[random_color()]" - human.facial_hair_color = human.hair_color - var/random_eye_color = random_eye_color() - human.eye_color_left = random_eye_color - human.eye_color_right = random_eye_color - human.dna.blood_type = random_blood_type() - human.dna.features["mcolor"] = "#[random_color()]" + human.name = human.get_visible_name() + human.set_hairstyle(random_hairstyle(human.gender), update = FALSE) + human.set_facial_hairstyle(random_facial_hairstyle(human.gender), update = FALSE) + human.set_haircolor("#[random_color()]", update = FALSE) + human.set_facial_haircolor(human.hair_color, update = FALSE) + human.eye_color_left = random_eye_color() + human.eye_color_right = human.eye_color_left + human.skin_tone = random_skin_tone() human.dna.species.randomize_active_underwear_only(human) - /*SKYRAT EDIT OLD - for(var/datum/species/species_path as anything in subtypesof(/datum/species)) - var/datum/species/new_species = new species_path - new_species.randomize_features(human) - SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION*/ - human.dna.species.randomize_features(human) - human.dna.mutant_bodyparts = human.dna.species.get_random_mutant_bodyparts(human.dna.features) - human.dna.body_markings = human.dna.species.get_random_body_markings(human.dna.features) + // Needs to be called towards the end to update all the UIs just set above + human.dna.initialize_dna(newblood_type = random_blood_type(), create_mutation_blocks = randomize_mutations, randomize_features = TRUE) + // SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION human.dna.species.mutant_bodyparts = human.dna.mutant_bodyparts.Copy() human.dna.species.body_markings = human.dna.body_markings.Copy() - //SKYRAT EDIT ADDITION END + // SKYRAT EDIT ADDITION END + // Snowflake stuff (ethereals) human.dna.species.spec_updatehealth(human) - human.dna.update_dna_identity() - human.updateappearance() - human.update_body(is_creating = TRUE) + human.updateappearance(mutcolor_update = TRUE) diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 808117057fd..e909fdfc0ad 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -940,11 +940,13 @@ attempted_fake_scar.fake = TRUE user.regenerate_icons() - + user.name = user.get_visible_name() + current_profile = chosen_profile // SKYRAT EDIT START chosen_dna.transfer_identity(user, TRUE) user.updateappearance(mutcolor_update = TRUE, eyeorgancolor_update = TRUE) user.regenerate_icons() + user.name = user.get_visible_name() current_profile = chosen_profile // SKYRAT EDIT END //THE FLUFFY FRONTIER EDIT ADDITION BEGIN - Blooper diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm index eb6ccccd8b5..f8c1bfc5160 100644 --- a/code/modules/antagonists/changeling/powers/tiny_prick.dm +++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -66,38 +66,61 @@ to_chat(target, span_warning("You feel a tiny prick.")) return 1 -//SKYRAT EDIT REMOVAL BEGIN - CHANGELING_TRANSFORMATION_REMOVAL -/* /datum/action/changeling/sting/transformation name = "Transformation Sting" - desc = "We silently sting a human, injecting a retrovirus that forces them to transform. Costs 50 chemicals." - helptext = "The victim will transform much like a changeling would. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human." + desc = "We silently sting an organism, injecting a retrovirus that forces them to transform." + helptext = "The victim will transform much like a changeling would. \ + For complex humanoids, the transformation is temporarily, but the duration is paused while the victim is dead or in stasis. \ + For more simple humanoids, such as monkeys, the transformation is permanent. \ + Does not provide a warning to others. Mutations will not be transferred." button_icon_state = "sting_transform" - chemical_cost = 50 - dna_cost = 3 - var/datum/changeling_profile/selected_dna = null + chemical_cost = 33 // Low enough that you can sting only two people in quick succession + dna_cost = 2 + /// A reference to our active profile, which we grab DNA from + VAR_FINAL/datum/changeling_profile/selected_dna + /// Duration of the sting + var/sting_duration = 8 MINUTES + +/datum/action/changeling/sting/transformation/Grant(mob/grant_to) + . = ..() + build_all_button_icons(UPDATE_BUTTON_NAME) -/datum/action/changeling/sting/transformation/Trigger(trigger_flags) - var/mob/user = usr +/datum/action/changeling/sting/transformation/update_button_name(atom/movable/screen/movable/action_button/button, force) + . = ..() + button.desc += " Lasts [DisplayTimeText(sting_duration)] for humans, but duration is paused while dead or in stasis." + button.desc += " Costs [chemical_cost] chemicals." + +/datum/action/changeling/sting/transformation/Destroy() + selected_dna = null + return ..() + +/datum/action/changeling/sting/transformation/set_sting(mob/user) + selected_dna = null var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) - if(changeling.chosen_sting) - unset_sting(user) + var/datum/changeling_profile/new_selected_dna = changeling.select_dna() + if(QDELETED(src) || QDELETED(changeling) || QDELETED(user)) return - selected_dna = changeling.select_dna() - if(!selected_dna) - return - if(HAS_TRAIT(user, TRAIT_NO_TRANSFORMATION_STING)) - user.balloon_alert(user, "incompatible DNA!") + if(!new_selected_dna || changeling.chosen_sting || selected_dna) // selected other sting or other DNA while sleeping return + selected_dna = new_selected_dna return ..() /datum/action/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target) . = ..() if(!.) return - if(!iscarbon(target) || HAS_TRAIT(target, TRAIT_HUSK) || HAS_TRAIT(target, TRAIT_NO_TRANSFORMATION_STING)) + // Similar checks here are ran to that of changeling can_absorb_dna - + // Logic being that if their DNA is incompatible with us, it's also bad for transforming + if(!iscarbon(target) \ + || !target.has_dna() \ + || HAS_TRAIT(target, TRAIT_HUSK) \ + || HAS_TRAIT(target, TRAIT_BADDNA) \ + || (HAS_TRAIT(target, TRAIT_NO_DNA_COPY) && !ismonkey(target))) // sure, go ahead, make a monk-clone user.balloon_alert(user, "incompatible DNA!") return FALSE + if(target.has_status_effect(/datum/status_effect/temporary_transformation/trans_sting)) + user.balloon_alert(user, "already transformed!") + return FALSE return TRUE /datum/action/changeling/sting/transformation/sting_action(mob/living/user, mob/living/target) @@ -113,8 +136,6 @@ to_chat(user, final_message) return TRUE return FALSE -*/ -//SKYRAT EDIT REMOVAL END /datum/action/changeling/sting/false_armblade name = "False Armblade Sting" diff --git a/code/modules/antagonists/nightmare/nightmare_species.dm b/code/modules/antagonists/nightmare/nightmare_species.dm index 2db4ca2bb2c..068bb2b6c5c 100644 --- a/code/modules/antagonists/nightmare/nightmare_species.dm +++ b/code/modules/antagonists/nightmare/nightmare_species.dm @@ -20,7 +20,6 @@ TRAIT_NOHUNGER, TRAIT_NOBLOOD, TRAIT_NO_DNA_COPY, - TRAIT_NO_TRANSFORMATION_STING, TRAIT_NODISMEMBER, TRAIT_NEVER_WOUNDED, ) diff --git a/code/modules/bitrunning/components/netpod_healing.dm b/code/modules/bitrunning/components/netpod_healing.dm index 8cb363517de..98fdb5ba021 100644 --- a/code/modules/bitrunning/components/netpod_healing.dm +++ b/code/modules/bitrunning/components/netpod_healing.dm @@ -49,6 +49,13 @@ id = "embryonic" alert_type = /atom/movable/screen/alert/status_effect/embryonic +/datum/status_effect/embryonic/on_apply() + ADD_TRAIT(owner, TRAIT_STASIS, TRAIT_STATUS_EFFECT(id)) + return TRUE + +/datum/status_effect/embryonic/on_remove() + REMOVE_TRAIT(owner, TRAIT_STASIS, TRAIT_STATUS_EFFECT(id)) + /atom/movable/screen/alert/status_effect/embryonic name = "Embryonic Stasis" icon_state = "netpod_stasis" diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index 359c3edf4ea..6494f4252e5 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -917,7 +917,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) if(new_human_species) new_human.set_species(new_human_species) new_human_species = new_human.dna.species - new_human_species.randomize_features(new_human) new_human.fully_replace_character_name(new_human.real_name, new_human_species.random_name(new_human.gender, TRUE, TRUE)) else stack_trace("failed to spawn cadaver with species ID [species_to_pick]") //if it's invalid they'll just be a human, so no need to worry too much aside from yelling at the server owner lol. diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm index 2e2674e14e7..147079ae720 100644 --- a/code/modules/mob/living/carbon/alien/larva/life.dm +++ b/code/modules/mob/living/carbon/alien/larva/life.dm @@ -3,7 +3,7 @@ /mob/living/carbon/alien/larva/Life(seconds_per_tick = SSMOBS_DT, times_fired) if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) return - if(!..() || IS_IN_STASIS(src) || (amount_grown >= max_grown)) + if(!..() || HAS_TRAIT(src, TRAIT_STASIS) || (amount_grown >= max_grown)) return // We're dead, in stasis, or already grown. // GROW! amount_grown = min(amount_grown + (0.5 * seconds_per_tick), max_grown) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index b847b7a73da..10c3288e0cd 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -858,19 +858,30 @@ GLOBAL_LIST_EMPTY(features_by_species) randomize_active_underwear_only(human_mob) human_mob.update_body() -///Proc that will randomize all the external organs (i.e. horns, frills, tails etc.) of a species' associated mob -/datum/species/proc/randomize_external_organs(mob/living/carbon/human/human_mob) +/datum/species/proc/randomize_active_features(mob/living/carbon/human/human_mob) + var/list/new_features = randomize_features() + for(var/feature_key in new_features) + human_mob.dna.features[feature_key] = new_features[feature_key] + human_mob.updateappearance(mutcolor_update = TRUE) + +/** + * Returns a list of features, randomized, to be used by DNA + */ +/datum/species/proc/randomize_features() + SHOULD_CALL_PARENT(TRUE) + + var/list/new_features = list() + var/static/list/organs_to_randomize = list() for(var/obj/item/organ/external/organ_path as anything in external_organs) - var/obj/item/organ/external/randomized_organ = human_mob.get_organ_by_type(organ_path) - if(randomized_organ) - var/datum/bodypart_overlay/mutant/overlay = randomized_organ.bodypart_overlay - var/new_look = pick(overlay.get_global_feature_list()) - human_mob.dna.features["[overlay.feature_key]"] = new_look - mutant_bodyparts["[overlay.feature_key]"] = new_look - -///Proc that randomizes all the appearance elements (external organs, markings, hair etc.) of a species' associated mob. Function set by child procs -/datum/species/proc/randomize_features(mob/living/carbon/human/human_mob) - return + var/overlay_path = initial(organ_path.bodypart_overlay) + var/datum/bodypart_overlay/mutant/sample_overlay = organs_to_randomize[overlay_path] + if(isnull(sample_overlay)) + sample_overlay = new overlay_path() + organs_to_randomize[overlay_path] = sample_overlay + + new_features["[sample_overlay.feature_key]"] = pick(sample_overlay.get_global_feature_list()) + + return new_features /datum/species/proc/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired) SHOULD_CALL_PARENT(TRUE) @@ -1307,7 +1318,7 @@ GLOBAL_LIST_EMPTY(features_by_species) return //Only stabilise core temp when alive and not in statis - if(humi.stat < DEAD && !IS_IN_STASIS(humi)) + if(humi.stat < DEAD && !HAS_TRAIT(humi, TRAIT_STASIS)) body_temperature_core(humi, seconds_per_tick, times_fired) //These do run in statis @@ -1315,7 +1326,7 @@ GLOBAL_LIST_EMPTY(features_by_species) body_temperature_alerts(humi, seconds_per_tick, times_fired) //Do not cause more damage in statis - if(!IS_IN_STASIS(humi)) + if(!HAS_TRAIT(humi, TRAIT_STASIS)) body_temperature_damage(humi, seconds_per_tick, times_fired) /** diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 3c29bf93847..44fe6d1a1c0 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -75,9 +75,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) cut_overlays(TRUE) /mob/living/carbon/human/dummy/setup_human_dna() - create_dna() - randomize_human(src) - dna.initialize_dna(skip_index = TRUE) //Skip stuff that requires full round init. + randomize_human(src, randomize_mutations = FALSE) /mob/living/carbon/human/dummy/log_mob_tag(text) return @@ -89,7 +87,6 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) return consistent_entry /proc/create_consistent_human_dna(mob/living/carbon/human/target) - target.dna.initialize_dna(skip_index = TRUE) /* SKYRAT EDIT START - Customization - ORIGINAL: target.dna.features["mcolor"] = COLOR_VIBRANT_LIME target.dna.features["ethcolor"] = COLOR_WHITE @@ -109,6 +106,17 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) target.dna.features["mcolor"] = COLOR_VIBRANT_LIME target.dna.features["ethcolor"] = COLOR_WHITE // SKYRAT EDIT END + target.dna.initialize_dna(create_mutation_blocks = FALSE, randomize_features = FALSE) + // UF and UI are nondeterministic, even though the features are the same some blocks will randomize slightly + // In practice this doesn't matter, but this is for the sake of 100%(ish) consistency + var/static/consistent_UF + var/static/consistent_UI + if(isnull(consistent_UF) || isnull(consistent_UI)) + consistent_UF = target.dna.unique_features + consistent_UI = target.dna.unique_identity + else + target.dna.unique_features = consistent_UF + target.dna.unique_identity = consistent_UI /// Provides a dummy that is consistently bald, white, naked, etc. /mob/living/carbon/human/dummy/consistent @@ -122,11 +130,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /mob/living/carbon/human/consistent/setup_human_dna() create_consistent_human_dna(src) - -/mob/living/carbon/human/consistent/update_body(is_creating) - ..() - if(is_creating) - fully_replace_character_name(real_name, "John Doe") + fully_replace_character_name(real_name, "John Doe") /mob/living/carbon/human/consistent/domutcheck() return // We skipped adding any mutations so this runtimes diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index b7b6456b775..94c7143060c 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -487,7 +487,7 @@ //SKYRAT EDIT ADDITION END //SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION - for(var/genital in possible_genitals) + for(var/genital in GLOB.possible_genitals) if(dna.species.mutant_bodyparts[genital]) var/datum/sprite_accessory/genital/G = GLOB.sprite_accessories[genital][dna.species.mutant_bodyparts[genital][MUTANT_INDEX_NAME]] if(G) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 0905a4ac40f..a75253e1517 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -54,9 +54,7 @@ ADD_TRAIT(src, TRAIT_AGEUSIA, NO_TONGUE_TRAIT) /mob/living/carbon/human/proc/setup_human_dna() - //initialize dna. for spawned humans; overwritten by other code - randomize_human(src) - dna.initialize_dna() + randomize_human(src, randomize_mutations = TRUE) /mob/living/carbon/human/Destroy() QDEL_NULL(physiology) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 2e061d32a6b..be355bddbea 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -28,7 +28,7 @@ //Body temperature stability and damage dna.species.handle_body_temperature(src, seconds_per_tick, times_fired) - if(!IS_IN_STASIS(src)) + if(!HAS_TRAIT(src, TRAIT_STASIS)) if(stat != DEAD) //handle active mutations for(var/datum/mutation/human/human_mutation as anything in dna.mutations) diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index 55f13dbfabf..af21d304cb7 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -3,24 +3,23 @@ id = SPECIES_ANDROID examine_limb_id = SPECIES_HUMAN inherent_traits = list( - TRAIT_NO_UNDERWEAR, TRAIT_GENELESS, TRAIT_LIMBATTACHMENT, + TRAIT_LIVERLESS_METABOLISM, + TRAIT_NOBLOOD, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, TRAIT_NOFIRE, TRAIT_NOHUNGER, - TRAIT_LIVERLESS_METABOLISM, + TRAIT_NO_DNA_COPY, + TRAIT_NO_UNDERWEAR, TRAIT_PIERCEIMMUNE, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_RESISTHEAT, - TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, TRAIT_TOXIMMUNE, - TRAIT_NOBLOOD, - TRAIT_NO_DNA_COPY, - TRAIT_NO_TRANSFORMATION_STING, TRAIT_NOCRITDAMAGE, ) diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index 4c28d190eff..abe7d058181 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -104,8 +104,10 @@ return randname -/datum/species/ethereal/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] +/datum/species/ethereal/randomize_features() + var/list/features = ..() + features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] + return features /datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/ethereal) . = ..() diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 4773cf769ad..e22940db2ad 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -48,8 +48,9 @@ return ..() /datum/species/human/felinid/randomize_features(mob/living/carbon/human/human_mob) - randomize_external_organs(human_mob) - return ..() + var/list/features = ..() + features["ears"] = pick("None", "Cat") + return features /proc/mass_purrbation() for(var/mob in GLOB.human_list) diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 91ec9dfe0c5..c86b8c9a276 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -3,19 +3,18 @@ name = "Golem" id = SPECIES_GOLEM inherent_traits = list( - TRAIT_NO_UNDERWEAR, TRAIT_GENELESS, TRAIT_LAVA_IMMUNE, - TRAIT_NOBREATH, + TRAIT_NEVER_WOUNDED, TRAIT_NOBLOOD, + TRAIT_NOBREATH, + TRAIT_NODISMEMBER, TRAIT_NOFIRE, + TRAIT_NO_AUGMENTS, + TRAIT_NO_DNA_COPY, + TRAIT_NO_UNDERWEAR, TRAIT_PIERCEIMMUNE, TRAIT_RADIMMUNE, - TRAIT_NO_DNA_COPY, - TRAIT_NO_TRANSFORMATION_STING, - TRAIT_NO_AUGMENTS, - TRAIT_NODISMEMBER, - TRAIT_NEVER_WOUNDED ) mutantheart = null mutantlungs = null diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index b169beba940..c7a181027e6 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -13,9 +13,6 @@ human.set_haircolor("#bb9966", update = FALSE) // brown human.set_hairstyle("Business Hair", update = TRUE) -/datum/species/human/randomize_features(mob/living/carbon/human/human_mob) - human_mob.skin_tone = random_skin_tone() - /datum/species/human/get_scream_sound(mob/living/carbon/human/human) if(human.physique == MALE) if(prob(1)) @@ -82,4 +79,3 @@ )) return to_add - diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 5f91cbb2830..45e34d96bfd 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -75,8 +75,9 @@ //SKYRAT EDIT REMOVAL BEGIN /* /datum/species/lizard/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["body_markings"] = pick(GLOB.body_markings_list) - randomize_external_organs(human_mob) + var/list/features = ..() + features["body_markings"] = pick(GLOB.body_markings_list) + return features */ //SKYRAT EDIT REMOVAL END diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index df289c514dc..8fb36e7c4e2 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -12,13 +12,13 @@ meat = /obj/item/food/meat/slab/monkey knife_butcher_results = list(/obj/item/food/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1) inherent_traits = list( - TRAIT_NO_UNDERWEAR, - TRAIT_NO_BLOOD_OVERLAY, TRAIT_GUN_NATURAL, + TRAIT_NO_AUGMENTS, + TRAIT_NO_BLOOD_OVERLAY, + TRAIT_NO_DNA_COPY, + TRAIT_NO_UNDERWEAR, TRAIT_VENTCRAWLER_NUDE, TRAIT_WEAK_SOUL, - TRAIT_NO_TRANSFORMATION_STING, - TRAIT_NO_AUGMENTS, ) no_equip_flags = ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_SUITSTORE changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN | SLIME_EXTRACT diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index df816fbca35..8f3cd84e1e5 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -59,9 +59,10 @@ if(istype(attacking_item, /obj/item/melee/flyswatter)) damage_mods += 10 // Yes, a 10x damage modifier -/datum/species/moth/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["moth_markings"] = pick(GLOB.moth_wings_list) - randomize_external_organs(human_mob) +/datum/species/moth/randomize_features() + var/list/features = ..() + features["moth_markings"] = pick(GLOB.moth_wings_list) // SKYRAT EDIT CHANGE - ORIGINAL: features["moth_markings"] = pick(GLOB.moth_markings_list) + return features /datum/species/moth/get_scream_sound(mob/living/carbon/human/human) return 'sound/voice/moth/scream_moth.ogg' diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 67f57f75a5a..9facc517c1c 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -8,11 +8,10 @@ inherent_traits = list( TRAIT_GENELESS, TRAIT_HARDLY_WOUNDED, - TRAIT_RADIMMUNE, - TRAIT_RESISTCOLD, TRAIT_NOBLOOD, TRAIT_NO_DNA_COPY, - TRAIT_NO_TRANSFORMATION_STING, + TRAIT_RADIMMUNE, + TRAIT_RESISTCOLD, ) inherent_biotypes = MOB_HUMANOID|MOB_MINERAL diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index 0b645fd120a..5cf2355c86c 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -105,6 +105,3 @@ )) return to_add - -/datum/species/pod/randomize_features(mob/living/carbon/human_mob) - randomize_external_organs(human_mob) diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index a63afeeea29..f2682da2eba 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -10,19 +10,19 @@ TRAIT_FAKEDEATH, TRAIT_GENELESS, TRAIT_LIMBATTACHMENT, + TRAIT_NOBLOOD, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, - TRAIT_RADIMMUNE, + TRAIT_NO_DNA_COPY, + TRAIT_NO_UNDERWEAR, TRAIT_PIERCEIMMUNE, + TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_RESISTHEAT, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_TOXIMMUNE, TRAIT_XENO_IMMUNE, - TRAIT_NOBLOOD, - TRAIT_NO_DNA_COPY, - TRAIT_NO_TRANSFORMATION_STING, ) inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID mutanttongue = /obj/item/organ/internal/tongue/bone diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 14c4c4d1c15..e567b1a292b 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -7,22 +7,22 @@ mutanttongue = /obj/item/organ/internal/tongue/zombie inherent_traits = list( // SHARED WITH ALL ZOMBIES - TRAIT_NO_ZOMBIFY, TRAIT_EASILY_WOUNDED, TRAIT_EASYDISMEMBER, TRAIT_FAKEDEATH, TRAIT_LIMBATTACHMENT, + TRAIT_LIVERLESS_METABOLISM, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, TRAIT_NODEATH, TRAIT_NOHUNGER, - TRAIT_LIVERLESS_METABOLISM, + TRAIT_NO_DNA_COPY, + TRAIT_NO_ZOMBIFY, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_TOXIMMUNE, - TRAIT_NO_TRANSFORMATION_STING, // HIGH FUNCTIONING UNIQUE TRAIT_NOBLOOD, TRAIT_SUCCUMB_OVERRIDE, @@ -105,11 +105,12 @@ TRAIT_EASYDISMEMBER, TRAIT_FAKEDEATH, TRAIT_LIMBATTACHMENT, + TRAIT_LIVERLESS_METABOLISM, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, TRAIT_NODEATH, TRAIT_NOHUNGER, - TRAIT_LIVERLESS_METABOLISM, + TRAIT_NO_DNA_COPY, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index a6b766289c0..182eba52b71 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -13,7 +13,7 @@ damageoverlaytemp = 0 update_damage_hud() - if(IS_IN_STASIS(src)) + if(HAS_TRAIT(src, TRAIT_STASIS)) . = ..() reagents.handle_stasis_chems(src, seconds_per_tick, times_fired) else diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 446e92f09f0..356653745e8 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -40,7 +40,7 @@ if(isnull(loc) || HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) return - if(!IS_IN_STASIS(src)) + if(!HAS_TRAIT(src, TRAIT_STASIS)) if(stat != DEAD) //Mutations and radiation diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 6095638318d..5e4a564125c 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -509,7 +509,7 @@ return TRUE if(!(flags & IGNORE_GRAB) && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE) return TRUE - if(!(flags & IGNORE_STASIS) && IS_IN_STASIS(src)) + if(!(flags & IGNORE_STASIS) && HAS_TRAIT(src, TRAIT_STASIS)) return TRUE return FALSE diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 00f66b370be..c24e9f8ceca 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -1267,12 +1267,12 @@ if(BLEED_OVERLAY_LOW to BLEED_OVERLAY_MED) new_bleed_icon = "[body_zone]_1" if(BLEED_OVERLAY_MED to BLEED_OVERLAY_GUSH) - if(owner.body_position == LYING_DOWN || IS_IN_STASIS(owner) || owner.stat == DEAD) + if(owner.body_position == LYING_DOWN || HAS_TRAIT(owner, TRAIT_STASIS) || owner.stat == DEAD) new_bleed_icon = "[body_zone]_2s" else new_bleed_icon = "[body_zone]_2" if(BLEED_OVERLAY_GUSH to INFINITY) - if(IS_IN_STASIS(owner) || owner.stat == DEAD) + if(HAS_TRAIT(owner, TRAIT_STASIS) || owner.stat == DEAD) new_bleed_icon = "[body_zone]_2s" else new_bleed_icon = "[body_zone]_3" diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index e21f277ecf6..bfeb128eb7a 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -7,11 +7,12 @@ zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_EXTERNAL_TAIL - bodypart_overlay = /datum/bodypart_overlay/mutant/tail - //dna_block = DNA_TAIL_BLOCK // SKYRAT EDIT REMOVAL - Customization - We have our own system to handle DNA. restyle_flags = EXTERNAL_RESTYLE_FLESH + // defaults to cat, but the parent type shouldn't be created regardless + bodypart_overlay = /datum/bodypart_overlay/mutant/tail/cat + ///Does this tail have a wagging sprite, and is it currently wagging? var/wag_flags = NONE ///The original owner of this tail @@ -83,7 +84,7 @@ organ_owner.update_body_parts() UnregisterSignal(organ_owner, COMSIG_LIVING_DEATH) -///Tail parent type (which is MONKEEEEEEEEEEE by default), with wagging functionality +///Tail parent type, with wagging functionality /datum/bodypart_overlay/mutant/tail layers = EXTERNAL_FRONT|EXTERNAL_BEHIND feature_key = "tail" // SKYRAT EDIT - Customization - ORIGINAL: feature_key = "tail_monkey" @@ -92,8 +93,10 @@ /datum/bodypart_overlay/mutant/tail/get_base_icon_state() return (wagging ? "wagging_" : "") + sprite_datum.icon_state //add the wagging tag if we be wagging +// SKYRAT EDIT ADDITION - CUSTOMIZATION /datum/bodypart_overlay/mutant/tail/get_global_feature_list() - return GLOB.sprite_accessories["tail"] // SKYRAT EDIT - Customization - ORIGINAL: return GLOB.tails_list + return GLOB.sprite_accessories["tail"] +// SKYRAT EDIT ADDITION END /datum/bodypart_overlay/mutant/tail/can_draw_on_bodypart(mob/living/carbon/human/human) if(human.wear_suit && (human.wear_suit.flags_inv & HIDEJUMPSUIT)) @@ -124,6 +127,9 @@ color_source = NONE feature_key = "tail" // SKYRAT EDIT - Customization - ORIGINAL: feature_key = "tail_monkey" +/datum/bodypart_overlay/mutant/tail/monkey/get_global_feature_list() + return GLOB.sprite_accessories["tail"] // SKYRAT EDIT CHANGE - ORIGINAL: return GLOB.tails_list_monkey + /obj/item/organ/external/tail/lizard name = "lizard tail" desc = "A severed lizard tail. Somewhere, no doubt, a lizard hater is very pleased with themselves." diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index d9d163b8702..56c10327441 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -109,6 +109,7 @@ #include "card_mismatch.dm" #include "cardboard_cutouts.dm" #include "chain_pull_through_space.dm" +#include "changeling.dm" #include "chat_filter.dm" #include "circuit_component_category.dm" #include "client_colours.dm" diff --git a/code/modules/unit_tests/changeling.dm b/code/modules/unit_tests/changeling.dm new file mode 100644 index 00000000000..449188a75fd --- /dev/null +++ b/code/modules/unit_tests/changeling.dm @@ -0,0 +1,99 @@ +/// Tests transformation sting goes back and forth correctly +/datum/unit_test/transformation_sting + var/ling_name = "Is-A-Changeling" + var/base_victim_name + var/last_frame = 1 + var/icon/final_icon + +/datum/unit_test/transformation_sting/Run() + var/mob/living/carbon/human/ling = setup_ling() + var/mob/living/carbon/human/victim = setup_victim() + var/datum/antagonist/changeling/ling_datum = ling.mind.has_antag_datum(/datum/antagonist/changeling) + + // Get the ability we're testing + ling_datum.give_power(/datum/action/changeling/sting/transformation) // SKYRAT EDIT CHANGE - Transformation sting not purchasable here - ORIGINAL : ling_datum.purchase_power(/datum/action/changeling/sting/transformation) + var/datum/action/changeling/sting/transformation/sting_action = locate() in ling.actions + sting_action.selected_dna = ling_datum.current_profile + sting_action.sting_duration = 0.5 SECONDS // just makes sure everything settles. + + // Check that they look different before stinging + add_to_screenshot(ling, victim, both_species = TRUE) + + // Do the sting, make the transformation + sting_action.sting_action(ling, victim) + // Check their name and species align + TEST_ASSERT(victim.has_status_effect(/datum/status_effect/temporary_transformation), "Victim did not get temporary transformation status effect on being transformation stung.") + TEST_ASSERT_EQUAL(victim.real_name, ling_name, "Victim real name did not change on being transformation stung.") + TEST_ASSERT_EQUAL(victim.name, ling_name, "Victim name did not change on being transformation stung.") + TEST_ASSERT_EQUAL(victim.dna.species.type, ling.dna.species.type, "Victim species did not change on being transformation stung.") + TEST_ASSERT_EQUAL(victim.dna.features["mcolor"], ling.dna.features["mcolor"], "Victim mcolor did not change on being transformation stung.") + // Check they actually look the same + add_to_screenshot(ling, victim) + + // Make sure we give it enough time such that the status effect process ticks over and finishes + sleep(sting_action.sting_duration + 0.5 SECONDS) + + // Check their name and species reset correctly + TEST_ASSERT_EQUAL(victim.name, base_victim_name, "Victim name did not change back after transformation sting expired.") + TEST_ASSERT_EQUAL(victim.real_name, base_victim_name, "Victim real name did not change back after transformation sting expired.") + TEST_ASSERT_NOTEQUAL(victim.dna.species.type, ling.dna.species.type, "Victim species did not change back after transformation sting expired.") + TEST_ASSERT_NOTEQUAL(victim.dna.features["mcolor"], ling.dna.features["mcolor"], "Victim mcolor did not reset after transformation sting expired.") + // Check they actually look different again + add_to_screenshot(ling, victim, both_species = TRUE) + + test_screenshot("appearances", final_icon) + +/// Adds both mobs to the screenshot test, if both_species is TRUE, it also adds the victim in lizard form +/datum/unit_test/transformation_sting/proc/add_to_screenshot(mob/living/carbon/human/ling, mob/living/carbon/human/victim, both_species = FALSE) + if(isnull(final_icon)) + final_icon = icon('icons/effects/effects.dmi', "nothing") + + // If we have a lot of dna features with a lot of parts (icons) + // This'll eventually runtime into a bad icon operation + // So we're recaching the icons here to prevent it from failing + final_icon = icon(final_icon) + final_icon.Insert(getFlatIcon(ling, no_anim = TRUE), dir = SOUTH, frame = last_frame) + final_icon.Insert(getFlatIcon(victim, no_anim = TRUE), dir = NORTH, frame = last_frame) + + if(both_species) + var/prior_species = victim.dna.species.type + victim.set_species(/datum/species/lizard) + final_icon.Insert(getFlatIcon(victim, no_anim = TRUE), dir = EAST, frame = last_frame) + victim.set_species(prior_species) + + last_frame += 1 + +/datum/unit_test/transformation_sting/proc/setup_victim() + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent) + base_victim_name = victim.real_name + victim.mind_initialize() + return victim + +/datum/unit_test/transformation_sting/proc/setup_ling() + var/mob/living/carbon/human/ling = allocate(/mob/living/carbon/human/consistent) + // Because we use two consistent humans, we need to change some of the features to know they're actually updating to new values. + // The more DNA features and random things we change, the more likely we are to catch something not updating correctly. + // Yeah guess who/what this is, I dare you. + ling.dna.features["mcolor"] = "#886600" + ling.dna.mutant_bodyparts["tail"] = list(MUTANT_INDEX_NAME = "Smooth", MUTANT_INDEX_COLOR_LIST = list("#886600", "#886600", "#886600")) // SKYRAT EDIT CHANGE - ORIGINAL: ling.dna.features["tail_lizard"] = "Smooth" + ling.dna.mutant_bodyparts["snout"] = list(MUTANT_INDEX_NAME = "Sharp + Light", MUTANT_INDEX_COLOR_LIST = list("#886600", "#886600", "#886600")) // SKYRAT EDIT CHANGE - ORIGINAL: ling.dna.features["snout"] = "Sharp + Light" + ling.dna.mutant_bodyparts["horns"] = list(MUTANT_INDEX_NAME = "Curled", MUTANT_INDEX_COLOR_LIST = list("#292826", "#292826", "#8292826")) // SKYRAT EDIT CHANGE - ORIGINAL: ling.dna.features["horns"] = "Curved" + ling.dna.mutant_bodyparts["frills"] = list(MUTANT_INDEX_NAME = "Short", MUTANT_INDEX_COLOR_LIST = list("#886600", "#886600", "#886600")) // SKYRAT EDIT CHANGE - ORIGINAL: ling.dna.features["frills"] = "Sort" + ling.dna.mutant_bodyparts["spines"] = list(MUTANT_INDEX_NAME = "Long + Membrane", MUTANT_INDEX_COLOR_LIST = list("#886600", "#886600", "#886600")) // SKYRAT EDIT CHANGE - ORIGINAL: ling.dna.features["spines"] = "Long + Membrane" + ling.dna.body_markings["chest"] = list("Light Belly" = list("#886600", 0)) // SKYRAT EDIT CHANGE - ORIGINAL : ling.dna.features[body_markings] = list("Light Belly") + ling.dna.features["legs"] = DIGITIGRADE_LEGS + ling.eye_color_left = "#FFFFFF" + ling.eye_color_right = "#FFFFFF" + ling.dna.update_ui_block(DNA_EYE_COLOR_LEFT_BLOCK) + ling.dna.update_ui_block(DNA_EYE_COLOR_RIGHT_BLOCK) + ling.set_species(/datum/species/lizard) + + ling.real_name = ling_name + ling.dna.real_name = ling_name + ling.name = ling_name + ling.dna.initialize_dna(create_mutation_blocks = FALSE, randomize_features = FALSE) + + ling.mind_initialize() + ling.mind.add_antag_datum(/datum/antagonist/changeling) + + return ling diff --git a/code/modules/unit_tests/screenshots/transformation_sting_appearances.png b/code/modules/unit_tests/screenshots/transformation_sting_appearances.png new file mode 100644 index 0000000000000000000000000000000000000000..ce0545d1b568cb767f1495f255fc69581b34cc9b GIT binary patch literal 1274 zcmZ`(e>l?#7=O2~Hu;gYaToR2{3wgmv?o(B<8WDM4aGgW#`2@c7Ov#y)R7TMl4EtH zAJijsl}mTAG@a`FSV}vgFItp(&`pN1TiqY`*S*j4zMuE=yzl3I-@jflC*WIS0}BHH zF!tTz#nqum=RAEx7l$t8rRpGo;}_&D{bDxO6t)YPl8FABp!Zxc6hTfTFzg|52WU|_ zyZ}KE?D7Gq1Fcs3BOhku4+rb6=w_ttg4`&87D(C&@0xG5=A>=g4Es0`?hDZYz;Oi+ zC&=6l4itdxu-p`2J($)MX6uxgByK<;u-+(iauB8jg(P`JCh`;Z3X}E<;sKH+fjfi= zKTN9vg_BdS?YBDGcl_BISRYK2)6tg9aDa*@q{j-Mwkh{KK9zii# zAIifMD`-YJjjI|At-5;mQwiO*{R`UNeX+-s39Sve?eXNO1B)BQ6_$H^yQafT|B8P< z_-2l*s8zVr9$J1bQne>p-`i=^{|5EI{ zpb=Z~%peX2Csc6W*^2X9=Oq&;s`ukmZRLwF zr`v5 z5K~4+k)ne{w!2i48n9QGVdqE!EzebShT!^~3o>KI9Uuv$BheYN7A<(iu!;EDZXOSEMoyPlUBbi`rvRVn#&VFL26kQL?FGZBY}$S{^F; z?bV~Q#V6j)Ntlk%u@)O?i8SCQe9%1Y^Yl=Vj9c+`&WRsr9;7YAhh4>x2xO(^2}{!w zp4TNAhqi;UCCrI4QwWM ze{N>6boxv~Jx?-a>gXQ$0>*G;7Os-xfbi_|Qu)72TXgqW%u^iGIOLEjvTe@v7~(K> zH0Giz>-4OLr}{jz{yX=!hHT|La#+h6a4(uRdHw&XG_x@iWfa?1AsK#d{kjhVzTN>| JwVu2q{{UWrFERiC literal 0 HcmV?d00001 diff --git a/modular_skyrat/master_files/code/modules/antagonists/changeling/powers/tiny_prick.dm b/modular_skyrat/master_files/code/modules/antagonists/changeling/powers/tiny_prick.dm new file mode 100644 index 00000000000..0eaf7f50f9f --- /dev/null +++ b/modular_skyrat/master_files/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -0,0 +1,3 @@ +// Transformation sting is not able to be purchased +/datum/action/changeling/sting/transformation + dna_cost = CHANGELING_POWER_UNOBTAINABLE diff --git a/modular_skyrat/master_files/code/modules/client/preferences.dm b/modular_skyrat/master_files/code/modules/client/preferences.dm index bc97b467cd9..2532bc4c308 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences.dm @@ -111,28 +111,29 @@ return language /datum/preferences/proc/validate_species_parts() - var/list/target_bodyparts = pref_species.default_mutant_bodyparts.Copy() + var/list/default_bodyparts = GLOB.default_mutant_bodyparts[pref_species.name] + var/list/target_bodyparts = default_bodyparts.Copy() // Remove all "extra" accessories for(var/key in mutant_bodyparts) if(!GLOB.sprite_accessories[key]) // That accessory no longer exists, remove it mutant_bodyparts -= key continue - if(!pref_species.default_mutant_bodyparts[key]) + if(!GLOB.default_mutant_bodyparts[pref_species.name][key]) mutant_bodyparts -= key continue if(!GLOB.sprite_accessories[key][mutant_bodyparts[key][MUTANT_INDEX_NAME]]) // The individual accessory no longer exists - mutant_bodyparts[key][MUTANT_INDEX_NAME] = pref_species.default_mutant_bodyparts[key] + mutant_bodyparts[key][MUTANT_INDEX_NAME] = GLOB.default_mutant_bodyparts[pref_species.name[key][MUTANT_INDEX_NAME]] validate_color_keys_for_part(key) // Validate the color count of each accessory that wasnt removed // Add any missing accessories for(var/key in target_bodyparts) if(!mutant_bodyparts[key]) var/datum/sprite_accessory/SA - if(target_bodyparts[key] == ACC_RANDOM) + if(target_bodyparts[key][MUTANT_INDEX_CAN_RANDOMIZE]) SA = random_accessory_of_key_for_species(key, pref_species) else - SA = GLOB.sprite_accessories[key][target_bodyparts[key]] + SA = GLOB.sprite_accessories[key][target_bodyparts[key][MUTANT_INDEX_NAME]] var/final_list = list() final_list[MUTANT_INDEX_NAME] = SA.name final_list[MUTANT_INDEX_COLOR_LIST] = SA.get_default_color(features, pref_species) diff --git a/modular_skyrat/master_files/code/modules/client/preferences/mutant_parts.dm b/modular_skyrat/master_files/code/modules/client/preferences/mutant_parts.dm index fd11a6bd3b5..57c26e4dd37 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences/mutant_parts.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences/mutant_parts.dm @@ -164,6 +164,9 @@ . = ..() var/obj/item/bodypart/head/our_head = target.get_bodypart(BODY_ZONE_HEAD) + if(isnull(our_head)) // dullahans. + return + if(.) our_head.bodytype |= BODYTYPE_SNOUTED else diff --git a/modular_skyrat/master_files/code/modules/mob/living/human/species.dm b/modular_skyrat/master_files/code/modules/mob/living/human/species.dm index 30df82a7f11..1bb68a1f10f 100644 --- a/modular_skyrat/master_files/code/modules/mob/living/human/species.dm +++ b/modular_skyrat/master_files/code/modules/mob/living/human/species.dm @@ -14,7 +14,7 @@ var/datum/preference/preference = GLOB.preference_entries[preference_type] if ( \ - (preference.relevant_mutant_bodypart in default_mutant_bodyparts) \ + (preference.relevant_mutant_bodypart in GLOB.default_mutant_bodyparts[name]) \ || (preference.relevant_inherent_trait in inherent_traits) \ || (preference.relevant_head_flag && check_head_flags(preference.relevant_head_flag)) \ ) diff --git a/modular_skyrat/modules/better_vox/code/vox_species.dm b/modular_skyrat/modules/better_vox/code/vox_species.dm index 4d3f1b237c9..8fdd3506cc0 100644 --- a/modular_skyrat/modules/better_vox/code/vox_species.dm +++ b/modular_skyrat/modules/better_vox/code/vox_species.dm @@ -17,9 +17,6 @@ breathid = "n2" mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/vox - default_mutant_bodyparts = list( - "tail" = "Vox Primalis Tail", - ) payday_modifier = 1.0 outfit_important_for_life = /datum/outfit/vox species_language_holder = /datum/language_holder/vox @@ -50,6 +47,10 @@ LOADOUT_ITEM_EARS = VOX_PRIMALIS_EARS_ICON, ) +/datum/species/vox_primalis/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Vox Primalis Tail", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /datum/species/vox_primalis/pre_equip_species_outfit(datum/job/job, mob/living/carbon/human/equipping, visuals_only) . = ..() diff --git a/modular_skyrat/modules/customization/__DEFINES/lists.dm b/modular_skyrat/modules/customization/__DEFINES/lists.dm index b0877b91b76..6c5d6bf496b 100644 --- a/modular_skyrat/modules/customization/__DEFINES/lists.dm +++ b/modular_skyrat/modules/customization/__DEFINES/lists.dm @@ -2,6 +2,17 @@ GLOBAL_LIST_EMPTY(sprite_accessories) GLOBAL_LIST_EMPTY(generic_accessories) GLOBAL_LIST_EMPTY(genetic_accessories) +/// What accessories can a species have as well as their default accessory of such type e.g. "frills" = "Aquatic". Default accessory colors is dictated by the accessory properties and mutcolors of the specie +GLOBAL_LIST_EMPTY(default_mutant_bodyparts) +GLOBAL_LIST_INIT(possible_genitals, list( + ORGAN_SLOT_VAGINA, + ORGAN_SLOT_WOMB, + ORGAN_SLOT_TESTICLES, + ORGAN_SLOT_BREASTS, + ORGAN_SLOT_ANUS, + ORGAN_SLOT_PENIS +)) + GLOBAL_LIST_EMPTY(body_markings) GLOBAL_LIST_EMPTY_TYPED(body_markings_per_limb, /list) GLOBAL_LIST_EMPTY(body_marking_sets) diff --git a/modular_skyrat/modules/customization/__HELPERS/global_lists.dm b/modular_skyrat/modules/customization/__HELPERS/global_lists.dm index a2dca2e39be..cc2c6c9e3e8 100644 --- a/modular_skyrat/modules/customization/__HELPERS/global_lists.dm +++ b/modular_skyrat/modules/customization/__HELPERS/global_lists.dm @@ -1,5 +1,6 @@ /proc/make_skyrat_datum_references() make_sprite_accessory_references() + make_default_mutant_bodypart_references() make_body_marking_references() make_body_marking_set_references() make_body_marking_dna_block_references() @@ -30,6 +31,18 @@ if(P.generic && !GLOB.generic_accessories[P.key]) GLOB.generic_accessories[P.key] = P.generic +/proc/make_default_mutant_bodypart_references() + // Build the global list for default species' mutant_bodyparts + for(var/path in subtypesof(/datum/species)) + var/datum/species/species_type = path + var/datum/species/species_instance = new species_type + if(!isnull(species_instance.name)) + GLOB.default_mutant_bodyparts[species_instance.name] = species_instance.get_default_mutant_bodyparts() + if(species_instance.can_have_genitals) + for(var/genital in GLOB.possible_genitals) + GLOB.default_mutant_bodyparts[species_instance.name] += list((genital) = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE)) + qdel(species_instance) + /proc/make_body_marking_references() // Here we build the global list for all body markings for(var/path in subtypesof(/datum/body_marking)) diff --git a/modular_skyrat/modules/customization/datums/dna.dm b/modular_skyrat/modules/customization/datums/dna.dm index 7e0fb14838c..e29e403e97b 100644 --- a/modular_skyrat/modules/customization/datums/dna.dm +++ b/modular_skyrat/modules/customization/datums/dna.dm @@ -57,16 +57,6 @@ GLOBAL_LIST_EMPTY(total_uf_len_by_block) ///Current body size, used for proper re-sizing and keeping track of that var/current_body_size = BODY_SIZE_NORMAL -/datum/dna/proc/initialize_dna(newblood_type, skip_index = FALSE) - if(newblood_type) - blood_type = newblood_type - unique_enzymes = generate_unique_enzymes() - unique_identity = generate_unique_identity() - if(!skip_index) //I hate this - generate_dna_blocks() - mutant_bodyparts = species.get_random_mutant_bodyparts(features) - unique_features = generate_unique_features() - /datum/dna/proc/generate_unique_features() var/list/data = list() @@ -186,59 +176,6 @@ GLOBAL_LIST_EMPTY(total_uf_len_by_block) holder.maptext_height = 32 * features["body_size"] // Adjust runechat height current_body_size = features["body_size"] -/mob/living/carbon/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE, list/override_features, list/override_mutantparts, list/override_markings, retain_features = FALSE, retain_mutantparts = FALSE) - if(QDELETED(src)) - CRASH("You're trying to change your species post deletion, this is a recipe for madness") - if(isnull(mrace)) - CRASH("set_species called without a species to set to") - if(!has_dna()) - return - - var/datum/species/new_race - if(ispath(mrace)) - new_race = new mrace - else if(istype(mrace)) - if(QDELING(mrace)) - CRASH("someone is calling set_species() and is passing it a qdeling species datum, this is VERY bad, stop it") - new_race = mrace - else - CRASH("set_species called with an invalid mrace [mrace]") - - death_sound = new_race.death_sound - - var/datum/species/old_species = dna.species - dna.species = new_race - - if (old_species.properly_gained) - old_species.on_species_loss(src, new_race, pref_load) - - //BODYPARTS AND FEATURES - We need to instantiate the list with compatible mutant parts so we don't break things - - if(override_mutantparts && override_mutantparts.len) - for(var/feature in dna.mutant_bodyparts) - override_mutantparts[feature] = dna.mutant_bodyparts[feature] - dna.mutant_bodyparts = override_mutantparts - - if(override_markings && override_markings.len) - for(var/feature in dna.body_markings) - override_markings[feature] = dna.body_markings[feature] - dna.body_markings = override_markings - - if(override_features && override_features.len) - for(var/feature in dna.features) - override_features[feature] = dna.features[feature] - dna.features = override_features - //END OF BODYPARTS AND FEATURES - - apply_customizable_dna_features_to_species() - dna.unique_features = dna.generate_unique_features() - - dna.update_body_size() - - dna.species.on_species_gain(src, old_species, pref_load) - log_mob_tag("TAG: [tag] SPECIES: [key_name(src)] \[[mrace]\]") - - /mob/living/carbon/proc/apply_customizable_dna_features_to_species() if(!has_dna()) CRASH("[src] does not have DNA") diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/preferences_setup.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/preferences_setup.dm index 543a0c15cc1..c2bfd6c7d49 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/preferences_setup.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/preferences_setup.dm @@ -162,7 +162,7 @@ var/list/new_features = pref_species.get_random_features() //We do this to keep flavor text, genital sizes etc. for(var/key in new_features) features[key] = new_features[key] - mutant_bodyparts = pref_species.get_random_mutant_bodyparts(features) + mutant_bodyparts = pref_species.get_mutant_bodyparts(features) body_markings = pref_species.get_random_body_markings(features) if(pref_species.use_skintones) features["uses_skintones"] = TRUE diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm index b27d27bae0a..e4f05a3b205 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm @@ -34,7 +34,6 @@ /datum/sprite_accessory/ears/fox color_src = USE_ONE_COLOR - /datum/sprite_accessory/ears/mutant icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/ears.dmi' organ_type = /obj/item/organ/external/ears // SET BACK TO THIS AS SOON AS WE GET EARS AS EXTERNAL ORGANS: organ_type = /obj/item/organ/internal/ears/mutant @@ -289,7 +288,7 @@ icon_state = "deerear" /datum/sprite_accessory/ears/mutant/teshari - recommended_species = list(SPECIES_TESHARI) + recommended_species = list(SPECIES_TESHARI, SPECIES_TESHARI_ALT) //FLUFFY FRONTIER EDIT - TESHARI_REBORN /datum/sprite_accessory/ears/mutant/teshari/regular name = "Teshari Regular" diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm index 4831414ca85..ef9212cb509 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -78,7 +78,7 @@ recommended_species = list(SPECIES_MAMMAL, SPECIES_HUMAN, SPECIES_SYNTH, SPECIES_TAJARAN, SPECIES_HUMANOID, SPECIES_GHOUL) /datum/sprite_accessory/tails/mammal/teshari - recommended_species = list(SPECIES_TESHARI) + recommended_species = list(SPECIES_TESHARI, SPECIES_TESHARI_ALT) //FLUFFY FRONTIER EDIT - TESHARI_REBORN /datum/sprite_accessory/tails/mammal/wagging/vulpkanin recommended_species = list(SPECIES_MAMMAL, SPECIES_HUMAN, SPECIES_SYNTH, SPECIES_VULP, SPECIES_HUMANOID, SPECIES_GHOUL) diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm index c21b8859d21..03a68cb6925 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm @@ -313,7 +313,7 @@ icon_state = "brown" /datum/sprite_accessory/wings/moth/burnt - name = "Moth (Burnt)" + name = "Burnt Off" icon_state = "burnt_off" locked = TRUE diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm index 78c597e7864..a8499e2fcdb 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm @@ -1,9 +1,6 @@ // This DMI holds our radial icons for the 'hide mutant parts' verb #define HIDING_RADIAL_DMI 'modular_skyrat/modules/customization/modules/mob/living/carbon/human/MOD_sprite_accessories/icons/radial.dmi' -/mob/living/carbon/human - var/static/list/possible_genitals = list(ORGAN_SLOT_PENIS, ORGAN_SLOT_TESTICLES, ORGAN_SLOT_VAGINA, ORGAN_SLOT_BREASTS, ORGAN_SLOT_ANUS) - /mob/living/carbon/human/Topic(href, href_list) . = ..() @@ -11,7 +8,7 @@ switch(href_list["lookup_info"]) if("genitals") var/list/line = list() - for(var/genital in possible_genitals) + for(var/genital in GLOB.possible_genitals) if(!dna.species.mutant_bodyparts[genital]) continue var/datum/sprite_accessory/genital/G = GLOB.sprite_accessories[genital][dna.species.mutant_bodyparts[genital][MUTANT_INDEX_NAME]] diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm index 357e827e744..08d83bd7313 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm @@ -27,32 +27,37 @@ GLOBAL_LIST_EMPTY(customizable_races) var/list/custom_worn_icons = list() ///Is this species restricted from changing their body_size in character creation? var/body_size_restricted = FALSE - ///What accessories can a species have aswell as their default accessory of such type e.g. "frills" = "Aquatic". Default accessory colors is dictated by the accessory properties and mutcolors of the specie - var/list/default_mutant_bodyparts = list() - /// A static list of all genital slot possibilities. - var/static/list/genitals_list = list(ORGAN_SLOT_VAGINA, ORGAN_SLOT_WOMB, ORGAN_SLOT_TESTICLES, ORGAN_SLOT_BREASTS, ORGAN_SLOT_ANUS, ORGAN_SLOT_PENIS) /// Are we lore protected? This prevents people from changing the species lore or species name. var/lore_protected = FALSE +/// Returns a list of the default mutant bodyparts, and whether or not they can be randomized or not +/datum/species/proc/get_default_mutant_bodyparts() + return list() + /datum/species/proc/handle_mutant_bodyparts(mob/living/carbon/human/owner, forced_colour, force_update = FALSE) return -/datum/species/New() - . = ..() - if(can_have_genitals) - for(var/genital in genitals_list) - default_mutant_bodyparts[genital] = "None" - /datum/species/dullahan mutant_bodyparts = list() /datum/species/human/felinid mutant_bodyparts = list() - default_mutant_bodyparts = list("tail" = "Cat", "ears" = "Cat") + +/datum/species/human/felinid/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Cat", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "Cat", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /datum/species/human mutant_bodyparts = list() - default_mutant_bodyparts = list("ears" = "None", "tail" = "None", "wings" = "None") + +/datum/species/human/get_default_mutant_bodyparts() + return list( + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /datum/species/mush mutant_bodyparts = list() @@ -75,20 +80,35 @@ GLOBAL_LIST_EMPTY(customizable_races) always_customizable = TRUE /datum/species/randomize_features(mob/living/carbon/human/human_mob) - return + var/list/features = ..() + return features -/datum/species/proc/get_random_mutant_bodyparts(list/features) //Needs features to base the colour off of +/** + * Returns a list of mutant_bodyparts + * + * Gets the default species mutant_bodyparts list for the given species datum and sets up its sprite accessories. + * + * Arguments: + * * features - Features are needed for the part color + * * existing_mutant_bodyparts - When passed a list of existing mutant bodyparts, the existing ones will not get overwritten + */ +/datum/species/proc/get_mutant_bodyparts(list/features, list/existing_mutant_bodyparts) //Needs features to base the colour off of var/list/mutantpart_list = list() - var/list/bodyparts_to_add = default_mutant_bodyparts.Copy() + if(LAZYLEN(existing_mutant_bodyparts)) + mutantpart_list = existing_mutant_bodyparts.Copy() + var/list/default_bodypart_data = GLOB.default_mutant_bodyparts[name] + var/list/bodyparts_to_add = default_bodypart_data.Copy() if(CONFIG_GET(flag/disable_erp_preferences)) - for(var/genital in genitals_list) + for(var/genital in GLOB.possible_genitals) bodyparts_to_add.Remove(genital) for(var/key in bodyparts_to_add) + if(LAZYLEN(existing_mutant_bodyparts) && existing_mutant_bodyparts[key]) + continue var/datum/sprite_accessory/SP - if(bodyparts_to_add[key] == ACC_RANDOM) + if(default_bodypart_data[key][MUTANT_INDEX_CAN_RANDOMIZE]) SP = random_accessory_of_key_for_species(key, src) else - SP = GLOB.sprite_accessories[key][bodyparts_to_add[key]] + SP = GLOB.sprite_accessories[key][bodyparts_to_add[key][MUTANT_INDEX_NAME]] if(!SP) CRASH("Cant find accessory of [key] key, [bodyparts_to_add[key]] name, for species [id]") var/list/color_list = SP.get_default_color(features, src) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm index 19492ef4456..95733d3df2b 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm @@ -29,10 +29,6 @@ ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "legs" = "Normal Legs" - ) outfit_important_for_life = /datum/outfit/akula payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT @@ -47,6 +43,12 @@ /// This variable stores the timer datum which appears if the mob becomes wet var/dry_up_timer = TIMER_ID_NULL +/datum/species/akula/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Akula", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/akula/get_species_description() return placeholder_description @@ -60,7 +62,8 @@ "Yet, despite their differences, all Agurkrral citizens swim freely in their kingdom's waters. Even the most controlling border princes, even those in the Old Principalities working the slave trade, know better than to openly erode a citizen's right to life, property, and speech. Any alien species can become an Agurkrral citizen, and even non-citizens enjoy the right to life, with executions outright banned. The aristocracy remains well-educated, even the edgerunner warlords of the New Principalities, and the Kingdom as a whole enjoys its status as a nation that's now a true rival to Sol. Larger, more populated, and better developed; though, having to 'integrate' Solarian technologies, goods, and peoples to fully succeed. The Azuleans are even known as an environmentally-focused people; although they hold no care for lands they cannot make use of, modern nobles are still in charge of maintaining the biosphere of lands they control, to allow their strangely engineered flora and fauna to thrive, and for the people to have healthy and clean waters to live in.", ) -/datum/species/akula/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/akula/randomize_features() + var/list/features = ..() var/main_color var/secondary_color var/tertiary_color @@ -82,9 +85,10 @@ main_color = "#DB35DE" secondary_color = "#BE3AFE" tertiary_color = "#F5E2EE" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = secondary_color - human_mob.dna.features["mcolor3"] = tertiary_color + features["mcolor"] = main_color + features["mcolor2"] = secondary_color + features["mcolor3"] = tertiary_color + return features /datum/species/akula/prepare_human_for_preview(mob/living/carbon/human/akula) var/main_color = "#1CD3E5" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm index 80aa57ca8ca..2fa8525ff48 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm @@ -11,14 +11,6 @@ inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/aquatic - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "horns" = "None", - "ears" = ACC_RANDOM, - "legs" = "Normal Legs", - "wings" = "None" - ) payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT examine_limb_id = SPECIES_AKULA @@ -31,6 +23,16 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant/aquatic, ) +/datum/species/aquatic/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Shark", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Shark", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "horns" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "Hammerhead", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /obj/item/organ/internal/tongue/aquatic liked_foodtypes = SEAFOOD | MEAT | FRUIT | GORE disliked_foodtypes = CLOTH | GROSS @@ -38,6 +40,7 @@ /datum/species/aquatic/randomize_features(mob/living/carbon/human/human_mob) + var/list/features = ..() var/main_color var/second_color var/random = rand(1,5) @@ -58,9 +61,10 @@ if(5) main_color = "#444444" second_color = "#DDDDEE" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = second_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = second_color + return features /datum/species/aquatic/get_random_body_markings(list/passed_features) var/name = "Shark" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm index 0b615d6bfc1..f0b2c18d297 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm @@ -4,11 +4,6 @@ examine_limb_id = SPECIES_GHOUL can_have_genitals = FALSE //WHY WOULD YOU WANT TO FUCK ONE OF THESE THINGS? mutant_bodyparts = list("ghoulcolor" = "Tan Necrotic") - default_mutant_bodyparts = list( - "tail" = "None", - "ears" = "None", - "legs" = "Normal Legs" - ) mutanttongue = /obj/item/organ/internal/tongue/ghoul inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, @@ -36,6 +31,13 @@ //i dont have to worry about sprites due to limbs_icon, thank god //also the head needs to be normal for hair to work +/datum/species/ghoul/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /proc/proof_ghoul_features(list/inFeatures) // Missing Defaults in DNA? Randomize! if(inFeatures["ghoulcolor"] == null || inFeatures["ghoulcolor"] == "") diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm index 6f721354cd5..a74eb02b7fd 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm @@ -17,9 +17,6 @@ TRAIT_USES_SKINTONES, ) inherent_biotypes = MOB_HUMANOID | MOB_ORGANIC - default_mutant_bodyparts = list( - "legs" = "Normal Legs" - ) exotic_bloodtype = "U" mutantheart = /obj/item/organ/internal/heart/hemophage mutantliver = /obj/item/organ/internal/liver/hemophage @@ -31,6 +28,10 @@ skinned_type = /obj/item/stack/sheet/animalhide/human veteran_only = TRUE +/datum/species/hemophage/get_default_mutant_bodyparts() + return list( + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /datum/species/hemophage/check_roundstart_eligible() if(check_holidays(HALLOWEEN)) @@ -38,7 +39,6 @@ return ..() - /datum/species/hemophage/on_species_gain(mob/living/carbon/human/new_hemophage, datum/species/old_species, pref_load) . = ..() to_chat(new_hemophage, HEMOPHAGE_SPAWN_TEXT) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm index 41f3715e8ca..33d15682332 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm @@ -9,19 +9,21 @@ ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = "None", - "snout" = "None", - "ears" = "None", - "legs" = "Normal Legs", - "wings" = "None", - "taur" = "None", - "horns" = "None" - ) changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT payday_modifier = 1.0 examine_limb_id = SPECIES_HUMAN +/datum/species/humanoid/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "snout" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "horns" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/humanoid/get_species_description() return "This is a template species for your own creations!" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm index 50f2cbec142..880ecec4ca4 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm @@ -9,17 +9,6 @@ ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = "None", - "snout" = "None", - "horns" = "None", - "ears" = "None", - "legs" = "Normal Legs", - "taur" = "None", - "fluff" = "None", - "wings" = "Bee", - "moth_antennae" = "None" - ) mutanttongue = /obj/item/organ/internal/tongue/insect payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT @@ -34,6 +23,19 @@ ) eyes_icon = 'modular_skyrat/modules/organs/icons/insect_eyes.dmi' +/datum/species/insect/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "snout" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "horns" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "fluff" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "Bee", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "moth_antennae" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/insect/get_species_description() return placeholder_description diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm index dd938a43e21..82ea0cf9c31 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm @@ -1,20 +1,23 @@ /datum/species/lizard mutant_bodyparts = list() external_organs = list() - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "spines" = ACC_RANDOM, - "frills" = ACC_RANDOM, - "horns" = ACC_RANDOM, - "body_markings" = ACC_RANDOM, - "legs" = DIGITIGRADE_LEGS, - "taur" = "None", - "wings" = "None", - ) payday_modifier = 1.0 -/datum/species/lizard/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/lizard/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Smooth", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Sharp + Light", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "spines" = list(MUTANT_INDEX_NAME = "Long + Membrane", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "frills" = list(MUTANT_INDEX_NAME = "Short", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "horns" = list(MUTANT_INDEX_NAME = "Curled", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "body_markings" = list(MUTANT_INDEX_NAME = "Light Belly", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = DIGITIGRADE_LEGS, MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + +/datum/species/lizard/randomize_features() + var/list/features = ..() var/main_color = "#[random_color()]" var/second_color var/third_color @@ -29,9 +32,10 @@ if(3) //Third case, more randomisation second_color = "#[random_color()]" third_color = "#[random_color()]" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = third_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = third_color + return features /datum/species/lizard/prepare_human_for_preview(mob/living/carbon/human/lizard, lizard_color = "#009999") lizard.dna.features["mcolor"] = lizard_color diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm index 801695b4274..7bf7d0014d6 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm @@ -10,18 +10,6 @@ inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/mammal - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "horns" = "None", - "ears" = ACC_RANDOM, - "legs" = ACC_RANDOM, - "taur" = "None", - "fluff" = "None", - "wings" = "None", - "head_acc" = "None", - "neck_acc" = "None" - ) payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT bodypart_overrides = list( @@ -33,6 +21,19 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant, ) +/datum/species/mammal/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Husky", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Husky", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "horns" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "Husky", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "fluff" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "head_acc" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "neck_acc" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /obj/item/organ/internal/tongue/mammal liked_foodtypes = GRAIN | MEAT @@ -40,7 +41,8 @@ toxic_foodtypes = TOXIC -/datum/species/mammal/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/mammal/randomize_features() + var/list/features = ..() var/main_color var/second_color var/third_color @@ -74,9 +76,10 @@ main_color = "#[random_color()]" second_color = "#[random_color()]" third_color = "#[random_color()]" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = third_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = third_color + return features /datum/species/mammal/get_random_body_markings(list/passed_features) var/name = "None" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/monkey.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/monkey.dm index 2b46cb02c21..fdcb5630d31 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/monkey.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/monkey.dm @@ -1,5 +1,7 @@ -/datum/species/monkey - default_mutant_bodyparts = list("tail" = "Monkey") +/datum/species/monkey/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Monkey", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /datum/species/monkey/prepare_human_for_preview(mob/living/carbon/human/monke) regenerate_organs(monke, src, visual_only = TRUE) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm index 6628060ee92..04a452712a4 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm @@ -1,10 +1,5 @@ /datum/species/moth mutant_bodyparts = list() - default_mutant_bodyparts = list( - "fluff" = "None", - "wings" = ACC_RANDOM, - "moth_antennae" = ACC_RANDOM, - ) inherent_traits = list( TRAIT_HAS_MARKINGS, TRAIT_TACKLING_WINGED_ATTACKER, @@ -12,8 +7,17 @@ TRAIT_MUTANT_COLORS, ) -/datum/species/moth/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["mcolor"] = "#E5CD99" +/datum/species/moth/get_default_mutant_bodyparts() + return list( + "fluff" = list(MUTANT_INDEX_NAME = "Plain", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "Moth (Plain)", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "moth_antennae" = list(MUTANT_INDEX_NAME = "Plain", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + ) + +/datum/species/moth/randomize_features() + var/list/features = ..() + features["mcolor"] = "#E5CD99" + return features /datum/species/moth/get_random_body_markings(list/passed_features) var/name = "None" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/podweak.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/podweak.dm index 90a4e4298a7..73b66a22c57 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/podweak.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/podweak.dm @@ -7,12 +7,14 @@ TRAIT_LITERATE, ) mutant_bodyparts = list() - default_mutant_bodyparts = list( - "pod_hair" = ACC_RANDOM, - "legs" = "Normal Legs" - ) payday_modifier = 1.0 +/datum/species/pod/get_default_mutant_bodyparts() + return list( + "pod_hair" = list(MUTANT_INDEX_NAME = "Ivy", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/pod/podweak name = "Podperson" id = SPECIES_PODPERSON_WEAK diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm index 422c1fd12cd..eec5fb6e5c7 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm @@ -1,20 +1,22 @@ /datum/species/jelly - default_mutant_bodyparts = list( - "tail" = "None", - "snout" = "None", - "ears" = "None", - "taur" = "None", - "wings" = "None", - "legs" = "Normal Legs", - "horns" = "None", - "spines" = "None", - "frills" = "None", - ) mutant_bodyparts = list() hair_color = "mutcolor" hair_alpha = 160 //a notch brighter so it blends better. facial_hair_alpha = 160 +/datum/species/jelly/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "snout" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "horns" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "spines" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "frills" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/jelly/get_species_description() return placeholder_description diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm index 47cd5be08c0..b489e6a1c74 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm @@ -16,7 +16,6 @@ mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/skrell payday_modifier = 1.0 - default_mutant_bodyparts = list("skrell_hair" = ACC_RANDOM) changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT eyes_icon = 'modular_skyrat/modules/organs/icons/skrell_eyes.dmi' mutantbrain = /obj/item/organ/internal/brain/skrell @@ -34,13 +33,19 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant/skrell, ) +/datum/species/skrell/get_default_mutant_bodyparts() + return list( + "skrell_hair" = list(MUTANT_INDEX_NAME = "Male", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + ) + /datum/species/skrell/get_species_description() return placeholder_description /datum/species/skrell/get_species_lore() return list(placeholder_lore) -/datum/species/skrell/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/skrell/randomize_features() + var/list/features = ..() var/main_color var/random = rand(1,6) //Choose from a range of green-blue colors @@ -57,9 +62,10 @@ main_color = "#22BBFF" if(6) main_color = "#2266FF" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = main_color - human_mob.dna.features["mcolor3"] = main_color + features["mcolor"] = main_color + features["mcolor2"] = main_color + features["mcolor3"] = main_color + return features /datum/species/skrell/prepare_human_for_preview(mob/living/carbon/human/skrell) var/skrell_color = "#22BBFF" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm index e5739b23624..e26208ec567 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm @@ -11,12 +11,6 @@ mutanttongue = /obj/item/organ/internal/tongue/cat/tajaran inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "ears" = ACC_RANDOM, - "legs" = "Normal Legs" - ) payday_modifier = 1.0 species_language_holder = /datum/language_holder/tajaran changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT @@ -30,13 +24,21 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant, ) +/datum/species/tajaran/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Cat (Big)", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Cat, normal", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "ears" = list(MUTANT_INDEX_NAME = "Cat, normal", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /obj/item/organ/internal/tongue/cat/tajaran liked_foodtypes = GRAIN | MEAT disliked_foodtypes = CLOTH -/datum/species/tajaran/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/tajaran/randomize_features() + var/list/features = ..() var/main_color var/second_color var/random = rand(1,5) @@ -57,9 +59,10 @@ if(5) main_color = "#DDCC99" second_color = "#DDCCAA" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = second_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = second_color + return features /datum/species/tajaran/get_random_body_markings(list/passed_features) var/name = pick("Tajaran", "Floof", "Floofer") diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm index c744097639a..e2638e06e3e 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm @@ -10,15 +10,6 @@ inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/unathi - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "spines" = "None", - "frills" = "None", - "horns" = ACC_RANDOM, - "body_markings" = ACC_RANDOM, - "legs" = "Normal Legs" - ) payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT examine_limb_id = SPECIES_LIZARD @@ -33,6 +24,16 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/lizard, ) +/datum/species/unathi/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Smooth", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Sharp + Light", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "spines" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "frills" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "horns" = list(MUTANT_INDEX_NAME = "Curled", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "body_markings" = list(MUTANT_INDEX_NAME = "Smooth Belly", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /obj/item/organ/internal/tongue/unathi liked_foodtypes = GORE | MEAT | SEAFOOD | NUTS @@ -40,7 +41,8 @@ toxic_foodtypes = TOXIC -/datum/species/unathi/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/unathi/randomize_features() + var/list/features = ..() var/main_color var/second_color var/random = rand(1,5) @@ -61,9 +63,10 @@ if(5) main_color = "#33BB11" second_color = "#339911" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = second_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = second_color + return features /datum/species/unathi/get_species_description() return placeholder_description diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm index 059019f249e..ecf2d84f623 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm @@ -16,12 +16,6 @@ mutantbrain = /obj/item/organ/internal/brain/vox breathid = "n2" mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = "Vox Tail", - "legs" = DIGITIGRADE_LEGS, - "snout" = "Vox Snout", - "spines" = ACC_RANDOM - ) payday_modifier = 1.0 outfit_important_for_life = /datum/outfit/vox species_language_holder = /datum/language_holder/vox @@ -51,6 +45,14 @@ LOADOUT_ITEM_EARS = VOX_EARS_ICON ) +/datum/species/vox/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Vox Tail", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = DIGITIGRADE_LEGS, MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "snout" = list(MUTANT_INDEX_NAME = "Vox Snout", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "spines" = list(MUTANT_INDEX_NAME = "Vox Bands", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + ) + /datum/species/vox/pre_equip_species_outfit(datum/job/job, mob/living/carbon/human/equipping, visuals_only) . = ..() if(job?.vox_outfit) @@ -69,10 +71,12 @@ return randname -/datum/species/vox/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["mcolor"] = pick("#77DD88", "#77DDAA", "#77CCDD", "#77DDCC") - human_mob.dna.features["mcolor2"] = pick("#EEDD88", "#EECC88") - human_mob.dna.features["mcolor3"] = pick("#222222", "#44EEFF", "#44FFBB", "#8844FF", "#332233") +/datum/species/vox/randomize_features() + var/list/features = ..() + features["mcolor"] = pick("#77DD88", "#77DDAA", "#77CCDD", "#77DDCC") + features["mcolor2"] = pick("#EEDD88", "#EECC88") + features["mcolor3"] = pick("#222222", "#44EEFF", "#44FFBB", "#8844FF", "#332233") + return features /datum/species/vox/get_random_body_markings(list/passed_features) var/name = pick(list("Vox", "Vox Hive", "Vox Nightling", "Vox Heart", "Vox Tiger")) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm index 62e001c5f74..410d5200eed 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm @@ -10,12 +10,6 @@ inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/vulpkanin - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "ears" = ACC_RANDOM, - "legs" = "Normal Legs" - ) species_language_holder = /datum/language_holder/vulpkanin payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT @@ -29,6 +23,13 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant, ) +/datum/species/vulpkanin/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Fox", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Mammal, Long", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "ears" = list(MUTANT_INDEX_NAME = "Fox", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /obj/item/organ/internal/tongue/vulpkanin liked_foodtypes = RAW | MEAT @@ -36,7 +37,8 @@ toxic_foodtypes = TOXIC -/datum/species/vulpkanin/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/vulpkanin/randomize_features() + var/list/features = ..() var/main_color var/second_color var/random = rand(1,5) @@ -57,9 +59,10 @@ if(5) main_color = "#999999" second_color = "#EEEEEE" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = second_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = second_color + return features /datum/species/vulpkanin/get_random_body_markings(list/passed_features) var/name = pick("Fox", "Floof", "Floofer") diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm index b4dbe252503..cb73afdc4e1 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm @@ -12,13 +12,6 @@ inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutanttongue = /obj/item/organ/internal/tongue/xeno_hybrid mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = "Xenomorph Tail", - "xenodorsal" = ACC_RANDOM, - "xenohead" = ACC_RANDOM, - "legs" = DIGITIGRADE_LEGS, - "taur" = "None" - ) external_organs = list() payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT @@ -34,6 +27,15 @@ meat = /obj/item/food/meat/slab/xeno skinned_type = /obj/item/stack/sheet/animalhide/xeno +/datum/species/xeno/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Xenomorph Tail", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "xenodorsal" = list(MUTANT_INDEX_NAME = "Standard", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "xenohead" = list(MUTANT_INDEX_NAME = "Standard", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = DIGITIGRADE_LEGS, MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/xeno/get_species_description() return placeholder_description diff --git a/modular_skyrat/modules/medical/code/wounds/synth/blunt/robotic_blunt.dm b/modular_skyrat/modules/medical/code/wounds/synth/blunt/robotic_blunt.dm index 52995365b01..66cbbb510b2 100644 --- a/modular_skyrat/modules/medical/code/wounds/synth/blunt/robotic_blunt.dm +++ b/modular_skyrat/modules/medical/code/wounds/synth/blunt/robotic_blunt.dm @@ -140,7 +140,7 @@ /datum/wound/blunt/robotic/handle_process(seconds_per_tick, times_fired) . = ..() - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return if (limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group && world.time > next_trauma_cycle) diff --git a/modular_skyrat/modules/medical/code/wounds/synth/blunt/secures_internals.dm b/modular_skyrat/modules/medical/code/wounds/synth/blunt/secures_internals.dm index e9e9ce3cb68..d4483dafb0b 100644 --- a/modular_skyrat/modules/medical/code/wounds/synth/blunt/secures_internals.dm +++ b/modular_skyrat/modules/medical/code/wounds/synth/blunt/secures_internals.dm @@ -20,7 +20,7 @@ /datum/wound/blunt/robotic/secures_internals/handle_process(seconds_per_tick, times_fired) . = ..() - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return if (gelled) diff --git a/modular_skyrat/modules/medical/code/wounds/synth/robotic_burns.dm b/modular_skyrat/modules/medical/code/wounds/synth/robotic_burns.dm index 24ac18eeab6..16540ac9f36 100644 --- a/modular_skyrat/modules/medical/code/wounds/synth/robotic_burns.dm +++ b/modular_skyrat/modules/medical/code/wounds/synth/robotic_burns.dm @@ -126,7 +126,7 @@ if (outgoing_bodytemp_coeff <= 0) return var/statis_mult = 1 - if (IS_IN_STASIS(victim)) // stasis heavily reduces the ingoing and outgoing transfer of heat + if (HAS_TRAIT(victim, TRAIT_STASIS)) // stasis heavily reduces the ingoing and outgoing transfer of heat statis_mult *= OVERHEAT_ON_STASIS_HEAT_MULT var/difference_from_average = max((BODYTEMP_NORMAL - victim.bodytemperature), 0) diff --git a/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm b/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm index 1a0c730c68c..2d20b0edbb2 100644 --- a/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm +++ b/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm @@ -194,7 +194,7 @@ var/base_mult = 1 if (victim) - if (IS_IN_STASIS(victim)) + if (HAS_TRAIT(victim, TRAIT_STASIS)) base_mult *= ELECTRICAL_DAMAGE_ON_STASIS_MULT if (victim.body_position == LYING_DOWN) base_mult *= ELECTRICAL_DAMAGE_LYING_DOWN_MULT diff --git a/modular_skyrat/modules/modular_implants/code/nifs.dm b/modular_skyrat/modules/modular_implants/code/nifs.dm index 12d9c67ad81..5d2b1aabd4a 100644 --- a/modular_skyrat/modules/modular_implants/code/nifs.dm +++ b/modular_skyrat/modules/modular_implants/code/nifs.dm @@ -185,7 +185,7 @@ /obj/item/organ/internal/cyberimp/brain/nif/process(seconds_per_tick) . = ..() - if(!linked_mob || broken || IS_IN_STASIS(linked_mob)) + if(!linked_mob || broken || HAS_TRAIT(linked_mob, TRAIT_STASIS)) return FALSE if(calibrating) diff --git a/modular_skyrat/modules/stasisrework/code/stasissleeper.dm b/modular_skyrat/modules/stasisrework/code/stasissleeper.dm index ffeb12dc56e..3510fa5c269 100644 --- a/modular_skyrat/modules/stasisrework/code/stasissleeper.dm +++ b/modular_skyrat/modules/stasisrework/code/stasissleeper.dm @@ -75,7 +75,7 @@ visible_message(span_notice("[occupant] emerges from [src]!"), span_notice("You climb out of [src]!")) open_machine() - if(IS_IN_STASIS(user)) + if(HAS_TRAIT(user, TRAIT_STASIS)) thaw_them(user) /obj/machinery/stasissleeper/proc/stasis_running() @@ -112,9 +112,9 @@ return var/mob/living/L_occupant = occupant if(stasis_running()) - if(!IS_IN_STASIS(L_occupant)) + if(!HAS_TRAIT(L_occupant, TRAIT_STASIS)) chill_out(L_occupant) - else if(IS_IN_STASIS(L_occupant)) + else if(HAS_TRAIT(L_occupant, TRAIT_STASIS)) thaw_them(L_occupant) /obj/machinery/stasissleeper/screwdriver_act(mob/living/user, obj/item/used_item) diff --git a/modular_skyrat/modules/synths/code/species/synthetic.dm b/modular_skyrat/modules/synths/code/species/synthetic.dm index 124985d73da..e3167ab4a4f 100644 --- a/modular_skyrat/modules/synths/code/species/synthetic.dm +++ b/modular_skyrat/modules/synths/code/species/synthetic.dm @@ -18,19 +18,8 @@ TRAIT_LITERATE, TRAIT_NOCRITDAMAGE, // We do our own handling of crit damage. TRAIT_ROBOTIC_DNA_ORGANS, - TRAIT_NO_TRANSFORMATION_STING, ) mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = "None", - "ears" = "None", - "legs" = "Normal Legs", - "snout" = "None", - MUTANT_SYNTH_ANTENNA = "None", - MUTANT_SYNTH_SCREEN = "None", - MUTANT_SYNTH_CHASSIS = "Default Chassis", - MUTANT_SYNTH_HEAD = "Default Head", - ) changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT reagent_flags = PROCESS_SYNTHETIC payday_modifier = 1.0 // Matches the rest of the pay penalties the non-human crew have @@ -63,6 +52,18 @@ /// This is the screen that is given to the user after they get revived. On death, their screen is temporarily set to BSOD before it turns off, hence the need for this var. var/saved_screen = "Blank" +/datum/species/synthetic/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "snout" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + MUTANT_SYNTH_ANTENNA = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + MUTANT_SYNTH_SCREEN = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + MUTANT_SYNTH_CHASSIS = list(MUTANT_INDEX_NAME = "Default Chassis", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + MUTANT_SYNTH_HEAD = list(MUTANT_INDEX_NAME = "Default Head", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/synthetic/spec_life(mob/living/carbon/human/human) . = ..() diff --git a/modular_skyrat/modules/teshari/code/_teshari.dm b/modular_skyrat/modules/teshari/code/_teshari.dm index 84dc35e59c2..ed1663d6f9a 100644 --- a/modular_skyrat/modules/teshari/code/_teshari.dm +++ b/modular_skyrat/modules/teshari/code/_teshari.dm @@ -14,11 +14,6 @@ TRAIT_NO_UNDERWEAR, TRAIT_HAS_MARKINGS, ) - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "ears" = ACC_RANDOM, - "legs" = "Normal Legs" - ) digitigrade_customization = DIGITIGRADE_NEVER changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT payday_modifier = 1.0 @@ -53,6 +48,13 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant/teshari, ) +/datum/species/teshari/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Teshari (Default)", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "ears" = list(MUTANT_INDEX_NAME = "Teshari Regular", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /obj/item/organ/internal/tongue/teshari liked_foodtypes = MEAT diff --git a/tff_modular/modules/nabbers/code/_nabbers.dm b/tff_modular/modules/nabbers/code/_nabbers.dm index b18982429cd..79c98824c84 100644 --- a/tff_modular/modules/nabbers/code/_nabbers.dm +++ b/tff_modular/modules/nabbers/code/_nabbers.dm @@ -87,6 +87,7 @@ H.apply_damage(NABBER_DAMAGE_ONBURNING, OXY) /datum/species/nabber/randomize_features(mob/living/carbon/human/human_mob) + var/list/features = ..() var/main_color var/random = rand(1,6) switch(random) @@ -102,9 +103,10 @@ main_color = "#c0ad00" if(6) main_color = "#e6ff03" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = main_color - human_mob.dna.features["mcolor3"] = main_color + features["mcolor"] = main_color + features["mcolor2"] = main_color + features["mcolor3"] = main_color + return features /datum/species/nabber/prepare_human_for_preview(mob/living/carbon/human/nabber) var/nabber_color = "#00ac1d" diff --git a/tff_modular/modules/teshari_reborn/code/teshari.dm b/tff_modular/modules/teshari_reborn/code/teshari.dm index e6317be4a4f..5c16af2ad85 100644 --- a/tff_modular/modules/teshari_reborn/code/teshari.dm +++ b/tff_modular/modules/teshari_reborn/code/teshari.dm @@ -41,9 +41,6 @@ LOADOUT_ITEM_ACCESSORY = TESHARI_ACCESSORIES_ICON, LOADOUT_ITEM_EARS = TESHARI_EARS_ICON ) - default_mutant_bodyparts = list( - "legs" = "Normal Legs" - ) coldmod = TESHARI_ALT_COLDMOD heatmod = TESHARI_ALT_HEATMOD bodytemp_normal = BODYTEMP_NORMAL + (TEHSARI_ALT_TEMP_OFFSET/2) @@ -76,15 +73,17 @@ . = ..() teshari_agility.Destroy() teshari_echolocation.Destroy() + qdel(C.GetComponent(/datum/component/weak_body)) C.mob_size = initial(C.mob_size) /datum/species/teshari/alt/randomize_features(mob/living/carbon/human/human_mob) - . = ..() + var/list/features = ..() var/main_color = pick(COLOR_GRAY, COLOR_DARK_BROWN, COLOR_ALMOST_BLACK, COLOR_DARK_RED, COLOR_DARK_CYAN) var/second_color = pick(COLOR_WHITE, COLOR_BLACK, COLOR_BLUE, COLOR_VIOLET) - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = second_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = second_color + return features /datum/species/teshari/alt/create_pref_unique_perks() var/list/perk_descriptions = list() diff --git a/tgstation.dme b/tgstation.dme index f12d1d4b3dc..4ea0689bc46 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1834,6 +1834,7 @@ #include "code\datums\status_effects\debuffs\debuffs.dm" #include "code\datums\status_effects\debuffs\decloning.dm" #include "code\datums\status_effects\debuffs\dizziness.dm" +#include "code\datums\status_effects\debuffs\dna_transformation.dm" #include "code\datums\status_effects\debuffs\drowsiness.dm" #include "code\datums\status_effects\debuffs\drugginess.dm" #include "code\datums\status_effects\debuffs\drunk.dm" @@ -6173,6 +6174,7 @@ #include "modular_skyrat\master_files\code\modules\antagonists\_common\antag_datum.dm" #include "modular_skyrat\master_files\code\modules\antagonists\ashwalker\ashwalker.dm" #include "modular_skyrat\master_files\code\modules\antagonists\changeling\changeling.dm" +#include "modular_skyrat\master_files\code\modules\antagonists\changeling\powers\tiny_prick.dm" #include "modular_skyrat\master_files\code\modules\antagonists\cult\cult_items.dm" #include "modular_skyrat\master_files\code\modules\antagonists\ert\ert.dm" #include "modular_skyrat\master_files\code\modules\antagonists\pirate\pirate_outfits.dm"