Files
Batrachophreno 0c342878e5 Engineering spriting (detailing & port), portable shield balance, bugfixes (#21862)
EXTREMELY MINOR MISCELLANEOUS CHANGES TEEHEE

changes:
- imageadd: "Adds +bolted, +welded, +lights overlays to several large
machines for easier visual identification of whether or not clicking on
that emitter will kill you or not, etc."
- imageadd: "Modifies the base of the Shield Wall Generator sprite to
better match that of the Emergency Shield Projector (and so they can use
the same overlays mentioned above)."
- imageadd: "Tweaks the Emitter's directional sprites slightly so that
the base doesn't seem to change shape quite so drastically when
rotated."
- imageadd: "Ports very pretty space heater sprites made by Wallemations
and vinylspiders from /tg/."
  - imageadd: "Adds unique sprites for Old and Heavy-Duty power cells."
- balance: "Increases power draw and range of Emergency Shield
Projectors."
  - balance: "Increases power draw of Shield Wall Generators."
- balance: "Greatly reduces time for debugger to fix APCs corrupted by
electrical storms."
- balance: "Increases multi-z shield capacitor reserve charge and
maximum throughput, so that high-strength shields can actually be run
(at high power draw)."
- balance: "Tweaks the INDRA power output formula to scale better with
increasing temperature."
- balance: "Slight adjustments to space heater efficiency formula with a
friendly handwave to entropy."
- balance: "Old power cells have a 5% chance to be defective and have
slightly lower maxcharge than standard cells."
  - qol: "Adds extended examine hints to engineering objects."
- qol: "Extends list of object types which INDRA core field will
interact peacefully with."
- qol: "Improved space heater UX (chat msgs changed to balloon alerts,
audible feedback, etc.)"
  - code_imp: "Updates many code comments to use DMdocs."
- code_imp: "Consolidates various shield generation machine sprites in
scattered across multiple files into a single shield generator machines
sprite file."
  - bugfix: "Fixes Emergency Shield Projector hard del issue."
- bugfix: "Emergency Shield Projector now shuts down as intended if the
area's APC gets completely drained."
- bugfix: "Firing the gyrotron into the INDRA while no reactants are
present will no longer generate heat."
  - bugfix: "Fixes INDRA runtime."
- bugfix: "Fixes Power Monitoring app not displaying grid sensors when
run from a modular computer held in-hand."
  
  Bolted/welded down Emitter:
<img width="130" height="101" alt="Screenshot 2026-02-13 123842"
src="https://github.com/user-attachments/assets/8357b5ea-77e6-46f7-b4a0-724aaa141cef"
/>

Modified shieldwall sprites (with old ones for comparison)
<img width="667" height="103" alt="Screenshot 2026-02-13 111422"
src="https://github.com/user-attachments/assets/2b1e849e-f955-49cb-b094-0bef098a754f"
/>

Shields actually useful for damage control now (though they'll blow
through APC charge if you go as crazy as this):
<img width="804" height="891" alt="Screenshot 2026-02-13 124245"
src="https://github.com/user-attachments/assets/39268b42-5abe-4a3b-ba8a-a18bdc63873e"
/>

### Asset Licenses
The following assets that **have not** been created by myself are
included in this PR:

| Path | Original Author | License |
| --- | --- | --- |
| icons/obj/atmos.dmi (all "sheater*") | [Wallemations, VinylSpiders
(/tg/station #93800)](https://github.com/tgstation/tgstation/pull/93800)
| CC-BY-SA |

---------

Signed-off-by: Batrachophreno <Batrochophreno@gmail.com>
Co-authored-by: SleepyGemmy <99297919+SleepyGemmy@users.noreply.github.com>
2026-03-11 16:39:54 +00:00

297 lines
8.3 KiB
Plaintext

/**
* Open turf class.
*
* All atoms are able to pass through this, and also to see under it.
*/
/turf/simulated/open
name = "open space"
icon = 'icons/turf/space.dmi'
icon_state = "opendebug"
density = 0
pathweight = 100000 //Seriously, don't try and path over this one numbnuts
is_hole = TRUE
roof_type = null
footstep_sound = null
explosion_resistance = 3
z_flags = ZM_MIMIC_DEFAULTS | ZM_MIMIC_OVERWRITE | ZM_MIMIC_NO_AO | ZM_ALLOW_ATMOS
turf_flags = TURF_FLAG_BACKGROUND
pathing_pass_method = TURF_PATHING_PASS_NO //You'll fall down most likely, unless no gravity, but not worth the processing just for this special case
// A lazy list to contain a list of mobs who are currently scaling
// up this turf. Used in human/can_fall.
var/tmp/list/climbers
/**
* An override of turf/Enter() to make it so that magboots allow you to stop
* falling off the damned rock.
*/
/turf/simulated/open/Enter(mob/living/carbon/human/mover, atom/oldloc)
if (istype(mover) && isturf(oldloc))
if (mover.Check_Shoegrip(FALSE) && mover.can_fall(below, src))
to_chat(mover, SPAN_NOTICE("You are stopped from falling off the edge by \the [mover.shoes] you're wearing!"))
return FALSE
return ..()
/turf/proc/CanZPass(atom/A, direction)
if(z == A.z) //moving FROM this turf
return direction == UP //can't go below
else
if(direction == UP) //on a turf below, trying to enter
return 0
if(direction == DOWN) //on a turf above, trying to enter
return !density
/turf/proc/GetZPassBlocker()
return src
/turf/simulated/open/CanZPass(atom/A, direction)
if(locate(/obj/structure/lattice/catwalk, src))
if(z == A.z)
if(direction == DOWN)
return FALSE
else if(direction == UP)
return FALSE
return 1
/turf/simulated/open/GetZPassBlocker()
var/obj/structure/lattice/catwalk/catwalk = locate(/obj/structure/lattice/catwalk, src)
if(catwalk)
return catwalk
return src
/turf/space/CanZPass(atom/A, direction)
if(locate(/obj/structure/lattice/catwalk, src))
if(z == A.z)
if(direction == DOWN)
return 0
else if(direction == UP)
return 0
return 1
/turf/space/GetZPassBlocker()
var/obj/structure/lattice/catwalk/catwalk = locate(/obj/structure/lattice/catwalk, src)
if(catwalk)
return catwalk
return src
/**
* Add a falling atom by default. Even if it's not an atom that can actually fall.
* SSfalling will check this on its own and remove if necessary. This is saner, as it
* centralizes control to SSfalling.
*/
/turf/simulated/open/Entered(atom/movable/mover)
..()
if (is_hole)
ADD_FALLING_ATOM(mover)
// Override to deny a climber exit if they're set to adhere to CLIMBER_NO_EXIT
/turf/simulated/open/Exit(atom/movable/mover, atom/newloc)
var/flags = remove_climber(mover)
if (flags & CLIMBER_NO_EXIT)
if (is_hole)
ADD_FALLING_ATOM(mover)
return FALSE
return ..()
// Remove from climbers just in case.
/turf/simulated/open/Exited(atom/movable/mover, atom/newloc)
..()
LAZYREMOVE(climbers, mover)
/turf/simulated/open/Destroy()
LAZYCLEARLIST(climbers)
UNSETEMPTY(climbers)
return ..()
/**
* Used to add a climber to the climbers list. Climbers do not fall down this specific tile.
*
* @param climber The atom to be added as a climber.
* @param flags Bitflags to control the status of the climber. Should always be non-0!
*
* @return TRUE if a climber was successfully added. FALSE if the climber is already
* present or an error occured.
*/
/turf/simulated/open/proc/add_climber(atom/climber, flags = CLIMBER_DEFAULT)
if (!flags)
return FALSE
if (LAZYACCESS(climbers, climber))
return FALSE
LAZYINITLIST(climbers)
climbers[climber] = flags
return TRUE
/**
* Used to remove a climber from the climbers list. Returns the flags the climber
* was assigned.
*
* @param climber The atom to be removed from climbers.
*
* @return The flags assigned to the climber if it was present in the list. 0 otherwise.
*/
/turf/simulated/open/proc/remove_climber(atom/climber)
. = 0
if (LAZYACCESS(climbers, climber))
. = climbers[climber]
LAZYREMOVE(climbers, climber)
/turf/simulated/open/airless
initial_gas = null
temperature = TCMB
icon_state = "opendebug_airless"
/turf/simulated/open/chasm
icon = 'icons/turf/smooth/chasms_seethrough.dmi'
icon_state = "debug"
smoothing_flags = SMOOTH_TRUE | SMOOTH_BORDER | SMOOTH_NO_CLEAR_ICON
smoothing_hints = SMOOTHHINT_CUT_F | SMOOTHHINT_ONLY_MATCH_TURF | SMOOTHHINT_TARGETS_NOT_UNIQUE
z_flags = ZM_MIMIC_BELOW
name = "hole"
/turf/simulated/open/chasm/airless
initial_gas = null
temperature = TCMB
icon_state = "debug_airless"
/turf/simulated/open/chasm/Initialize()
. = ..()
icon_state = "Fill"
/turf/simulated/open/chasm/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
underlay_appearance.icon = 'icons/turf/basalt.dmi'
underlay_appearance.icon_state = "basalt"
if (prob(20))
underlay_appearance.icon_state += "[rand(0,12)]"
return TRUE
/turf/simulated/open/post_change()
..()
update()
/turf/simulated/open/Initialize(mapload)
. = ..()
icon_state = "" // Clear out the debug icon.
ADD_TRAIT(src, TURF_Z_TRANSPARENT_TRAIT, TRAIT_SOURCE_INHERENT)
update(mapload)
/**
* Updates the turf with open turf's variables and basically resets it properly.
*/
/turf/simulated/open/proc/update(mapload = FALSE)
var/turf/T = get_turf(src)
below = GET_TURF_BELOW(T)
// Edge case for when an open turf is above space on the lowest level.
if (below)
below.above = src
if (mapload)
for (var/obj/O in src) // We're not going to try to make mobs fall here for performance reasons - they shouldn't be mapped in on openturfs anyways.
if (is_hole && O.simulated)
ADD_FALLING_ATOM(O)
else
for (var/thing in src)
var/obj/O = thing // This might not be an obj.
if (isobj(O))
O.hide(0)
if (is_hole && O.simulated)
ADD_FALLING_ATOM(O)
/turf/simulated/open/update_dirt()
return 0
// override to make sure nothing is hidden
/turf/simulated/open/levelupdate()
for(var/obj/O in src)
O.hide(0)
/turf/simulated/open/examine(mob/user, distance, is_adjacent, infix, suffix, show_extended)
. = ..()
if(isliving(user))
var/mob/living/looker = user
if(looker.Adjacent(src) && !looker.incapacitated())
looker.look_down_open_space(src)
/turf/simulated/open/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
. = ..()
if(distance <= 2)
var/depth = 1
var/turf/current_turf = get_turf(src)
for(var/turf/T = GET_TURF_BELOW(current_turf); isopenspace(T); T = GET_TURF_BELOW(T))
depth += 1
. += "It is about [depth] level\s deep."
/turf/simulated/open/is_open()
return TRUE
/turf/simulated/open/update_icon(mapload)
update_mimic(!mapload)
/turf/simulated/open/attackby(obj/item/attacking_item, mob/user)
if (istype(attacking_item, /obj/item/stack/rods))
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
if(L)
return
var/obj/item/stack/rods/R = attacking_item
if (R.use(1))
to_chat(user, SPAN_NOTICE("You lay down the support lattice."))
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
new /obj/structure/lattice(locate(src.x, src.y, src.z))
return
if (istype(attacking_item, /obj/item/stack/tile))
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
if(L)
var/obj/item/stack/tile/floor/S = attacking_item
if (S.get_amount() < 1)
return
qdel(L)
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
S.use(1)
ChangeTurf(/turf/simulated/floor/airless)
return
else
to_chat(user, SPAN_WARNING("The plating is going to need some support."))
//To lay cable.
if(attacking_item.tool_behaviour == TOOL_CABLECOIL)
var/obj/item/stack/cable_coil/coil = attacking_item
coil.turf_place(src, user)
return
return
/turf/simulated/open/attack_hand(var/mob/user)
if(ishuman(user) && user.a_intent == I_GRAB)
var/mob/living/carbon/human/H = user
var/turf/T = get_turf(H)
var/turf/climbing_wall = GET_TURF_BELOW(T)
var/climb_bonus = 0
if(istype(climbing_wall, /turf/simulated/mineral))
climb_bonus = 20
else
climb_bonus = 0
H.climb(DOWN, src, climb_bonus)
//Most things use is_plating to test if there is a cover tile on top (like regular floors)
/turf/simulated/open/is_plating()
return TRUE
/turf/simulated/open/add_tracks(var/list/DNA, var/comingdir, var/goingdir, var/bloodcolor=COLOR_HUMAN_BLOOD)
return
//Returns the roof type of the turf below
/turf/simulated/open/get_roof_type()
var/turf/t = GET_TURF_BELOW(src)
if(!t)
return null
return t.roof_type