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

140 lines
4.7 KiB
Plaintext

#define REMOVE_AND_CONTINUE \
falling -= victim; \
victim.multiz_falling = 0; \
if (MC_TICK_CHECK) return; \
continue;
/**
* Notes for potential future development.
*
* Falling subsystem currently treats 'falling' as a event that happens instantly in the presence of gravity, which (presently) is a binary true/false condition.
* To handle more strengths of gravity beyond 0g and 1g, falling logic will need to be able to handle things falling 'slowly'. The easiest way to implement this
* will probably be to provide handling for an component/element (if pending fall in low-g, give an AM an additional highlight or examine-able info), and also
* provide in-game feedback in some way to the player- ideally through a UI grav condition button like /tg/'s, that indicates how long it'll take before you drift
* down a Z-level.
*
* This would also give us more granular control over levels of sub-1 gravity. Instead of 'no grav, low grav, standard grav', we could have 0.0 -> 1.0 grav just be
* the the delay factor on the falling subsystem's fire() logic, and the thresholds over which that a z-level fall happens gently (or not gently).
*/
SUBSYSTEM_DEF(falling)
name = "Falling"
flags = SS_NO_INIT
wait = 1
var/list/falling = list()
var/list/currentrun
/datum/controller/subsystem/falling/stat_entry(msg)
msg = "F:[falling.len]"
return ..()
/datum/controller/subsystem/falling/fire(resumed = 0)
if (!resumed)
currentrun = falling.Copy()
var/list/curr = currentrun
while (curr.len)
var/atom/movable/victim = curr[curr.len]
curr.len--
if (QDELETED(victim))
falling -= victim
if (MC_TICK_CHECK)
return
continue
// The call_fall checks that are executed for every atom forever. These
// should not be overwritten/there shouldn't be a need to overwrite them.
// For specialty conditions, edit CanZPass and can_fall procs.
var/turf/mob_loc = victim.loc
if (!isturf(mob_loc))
REMOVE_AND_CONTINUE
// Get the below turf.
var/turf/below = GET_TURF_BELOW(mob_loc)
if (!below)
REMOVE_AND_CONTINUE
// Check if we can fall through the current tile and onto the next one.
if (!mob_loc.CanZPass(victim, DOWN) || !below.CanZPass(victim, DOWN))
REMOVE_AND_CONTINUE
// Check if the victim's current position is affected by gravity.
var/area/mob_area = get_area(mob_loc)
if (!mob_area.has_gravity())
REMOVE_AND_CONTINUE
// Thrown objects don't fall, generally speaking.
if (victim.throwing)
REMOVE_AND_CONTINUE
// can_fall check to see if we can fall. Current position is accessible
// via src.loc, destination by the param. So should be customizable enough.
if (!victim.can_fall(below))
// In case the stop is called in a situation when we're already falling.
// The still want to call fall_impact, due to the fact they've fallen.
if (falling[victim])
victim.fall_impact(falling[victim], TRUE)
victim.fall_collateral(falling[victim], TRUE)
REMOVE_AND_CONTINUE
// Iterate the falling counter. This is how many levels the mob has fallen
// thus far.
falling[victim]++
// Open turfs. Handle falling through them.
// Invokes fall_through() after the atom is moved to
// its new destination this cycle. Immediately invokes fall_impact and
// fall_collateral if the next turf is not open space.
if (isopenturf(victim.loc))
var/turf/simulated/open/mob_openturf = victim.loc
if(mob_openturf.is_hole)
victim.begin_falling(victim.loc, below)
victim.forceMove(below)
if(victim.pulledby && victim.pulledby.z != victim.z)
var/mob/M = victim.pulledby
M.stop_pulling()
if (locate(/obj/structure/stairs) in victim.loc) // If there's stairs, we're probably going down them.
if (falling[victim] <= 1) // Just moving down a flight, skip damage.
victim.multiz_falling = 0
falling -= victim
for(var/obj/item/grab/grab in victim)
if(grab.affecting)
grab.affecting.forceMove(victim.loc)
else
// Falling more than a level, fuck 'em up.
victim.fall_impact(falling[victim], FALSE)
victim.fall_collateral(falling[victim], FALSE)
victim.multiz_falling = 0
falling -= victim
else if (isopenturf(victim.loc))
victim.fall_through()
else
// This is a lookahead. It removes any lag from being moved onto
// the destination turf, and calling fall_impact.
victim.fall_impact(falling[victim], FALSE)
victim.fall_collateral(falling[victim], FALSE)
victim.multiz_falling = 0
falling -= victim
if (MC_TICK_CHECK)
return
continue
// This shouldn't actually happen. But for safety, here it is.
victim.fall_impact(falling[victim], FALSE)
victim.fall_collateral(falling[victim], FALSE)
victim.multiz_falling = 0
falling -= victim
if (MC_TICK_CHECK)
return
#undef REMOVE_AND_CONTINUE