Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e15528c
Move brain-machine interfaces into a modpack
out-of-phaze Nov 28, 2025
e2be5e8
Fix turret control panels
Typhin May 9, 2026
e079488
Heat Exchange pipes can now radiate to space at half efficiency on no…
Typhin May 9, 2026
7cdb881
Make gases use alist
out-of-phaze Jan 1, 2026
e97af25
Merge pull request #5358 from Typhin/stable
out-of-phaze May 9, 2026
78ac787
Fix nutriment being HAAAAARDEEEEEEER THAN STEEEEL
out-of-phaze May 9, 2026
02ed0b6
Apply traits via mob snapshots in character creation
out-of-phaze May 12, 2026
0f69fe3
Fix excessive mannequin regeneration on character slot save
out-of-phaze May 12, 2026
bac1544
Fix supplied mob snapshot not being used in create_missing_organs
out-of-phaze May 12, 2026
f0906d6
Fix antlers biomod not being an animal biomod
out-of-phaze May 12, 2026
39d18b3
Merge pull request #5360 from MistakeNot4892/stable
out-of-phaze May 12, 2026
12bf7a9
Minor hood fixes.
MistakeNot4892 May 13, 2026
789ccc5
Adding a skip_update param to set_color() and set_markings_color().
MistakeNot4892 May 13, 2026
3a0ddcd
Closing doors cannot be walked through.
MistakeNot4892 May 13, 2026
337669d
Prevents pull damage if you are buckled to something (rollerbed, trav…
MistakeNot4892 May 13, 2026
3111398
Update inducers to accept cells
Typhin May 13, 2026
f2ad919
Merge branch 'inducer-fix' of https://github.com/Typhin/Nebula into i…
Typhin May 13, 2026
25a6e8a
Add null checks to cell_loaded
Typhin May 13, 2026
604a8ea
Background helpers are now usable on /mob not /mob/living.
MistakeNot4892 May 13, 2026
4896ef1
Tweaks to the ability system and ability targeters.
MistakeNot4892 May 13, 2026
36d2550
ChangeArea() is now a /turf proc.
MistakeNot4892 May 13, 2026
99fb26f
Merge pull request #5362 from out-of-phaze/fix/setup-traits
MistakeNot4892 May 14, 2026
1cfc7c2
Merge pull request #5367 from Typhin/inducer-fix
out-of-phaze May 14, 2026
778d982
Merge pull request #5361 from MistakeNot4892/fix/ears
out-of-phaze May 14, 2026
5172b30
Merge pull request #5365 from MistakeNot4892/fix/misc
out-of-phaze May 16, 2026
6627771
Merge pull request #5363 from MistakeNot4892/fix/hoods
out-of-phaze May 16, 2026
7349565
Merge pull request #5369 from MistakeNot4892/tweak/culture
out-of-phaze May 16, 2026
e00eb58
Merge pull request #5366 from MistakeNot4892/fix/travois
out-of-phaze May 16, 2026
32d5bc8
Merge pull request #5370 from MistakeNot4892/tweak/abilities
out-of-phaze May 16, 2026
ba2c1f4
Merge branch 'stable' of github.com:NebulaSS13/Nebula into devupdate
MistakeNot4892 May 16, 2026
17821ec
Merge pull request #5374 from MistakeNot4892/devupdate
MistakeNot4892 May 16, 2026
3d4459a
Offsets mob modifers to centre, Prone -> Lying
MistakeNot4892 May 16, 2026
179cebf
Mech UI and code cleanup.
MistakeNot4892 May 16, 2026
906e155
Merge pull request #5248 from out-of-phaze/experiment/gas-alist
MistakeNot4892 May 16, 2026
b21f939
Removing unused tallness var.
MistakeNot4892 May 16, 2026
4772d11
Cleaning up citizenship vars.
MistakeNot4892 May 16, 2026
fccea6a
Merge pull request #5368 from MistakeNot4892/tweak/changearea
out-of-phaze May 17, 2026
a782f24
Merge pull request #5210 from out-of-phaze/modpack/brain-interface
MistakeNot4892 May 17, 2026
784b36e
Merge pull request #5375 from MistakeNot4892/tweak/mechui
MistakeNot4892 May 18, 2026
754918d
Merge pull request #5376 from MistakeNot4892/fix/modifiers
MistakeNot4892 May 18, 2026
769e3c4
Merge pull request #5378 from MistakeNot4892/tweak/tallness
MistakeNot4892 May 18, 2026
7efbe99
Merge branch 'dev' of github.com:NebulaSS13/Nebula into pyrelight
MistakeNot4892 May 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions code/__defines/_byond_version_compat.dm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#define REQUIRED_DM_VERSION 515
#define REQUIRED_DM_VERSION 516

#if DM_VERSION < REQUIRED_DM_VERSION
#warn Nebula is not tested on BYOND versions older than 515. The code may not compile, and if it does compile it may have severe problems.
#warn Nebula is not tested on BYOND versions older than 516. The code may not compile, and if it does compile it may have severe problems.
#endif
2 changes: 1 addition & 1 deletion code/__defines/math_physics.dm
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#define ATM *ONE_ATMOSPHERE

#define ATMOS_PRECISION 0.0001
#define QUANTIZE(variable) (round(variable, ATMOS_PRECISION))
#define QUANTIZE(variable) (NONUNIT_FLOOR(variable, ATMOS_PRECISION))

#define INFINITY 1.#INF

Expand Down
7 changes: 7 additions & 0 deletions code/_helpers/lists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,13 @@ Checks if a list has the same entries and values as an element of big.
else
.[key] = call(merge_method)(.[key], b_value)

// Picks a key in an alist. This is awful but hey, what can you do?
/proc/apick(alist/target_alist)
var/index = rand(1, length(target_alist))
for(var/key in target_alist)
if(--index == 0)
return key

//Pretends to pick an element based on its weight but really just seems to pick a random element.
/proc/pickweight(list/target_list)
var/total = 0
Expand Down
2 changes: 1 addition & 1 deletion code/_helpers/serde.dm
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
if(!area)
area = new load_path(null)
instanced_areas[load_path] = area
ChangeArea(spawn_loc, area)
spawn_loc.ChangeArea(area)

else if(ispath(load_path, /atom))
created_instance = new load_path(spawn_loc)
Expand Down
4 changes: 2 additions & 2 deletions code/_helpers/turfs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@

if(target)
if(base_area)
ChangeArea(target, get_area(source))
target.ChangeArea(get_area(source))
. += transport_turf_contents(source, target, ignore_background, translate_air, angle = angle)
ChangeArea(source, base_area)
source.ChangeArea(base_area)
else
. += transport_turf_contents(source, target, ignore_background, translate_air, angle = angle)
//change the old turfs
Expand Down
4 changes: 2 additions & 2 deletions code/_onclick/hud/hud_types/_hud.dm
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,9 @@
mymob.remove_mob_modifier(/decl/mob_modifier/restrained, source = mymob)

if(mymob.current_posture?.prone)
mymob.add_mob_modifier(/decl/mob_modifier/prone, source = mymob)
mymob.add_mob_modifier(/decl/mob_modifier/lying, source = mymob)
else
mymob.remove_mob_modifier(/decl/mob_modifier/prone, source = mymob)
mymob.remove_mob_modifier(/decl/mob_modifier/lying, source = mymob)

for(var/obj/screen/elem as anything in hud_elements_update_in_life)
elem.update_icon()
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/hud/screen/_screen.dm
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
/obj/screen/get_color()
return color

/obj/screen/set_color(new_color)
/obj/screen/set_color(new_color, skip_update)
if(color != new_color)
color = new_color
return TRUE
Expand Down
4 changes: 3 additions & 1 deletion code/_onclick/hud/screen/screen_exosuit.dm
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
maptext_x = -16
maptext_width = 64
maptext_y = -8
screen_loc = "RIGHT-2:28,CENTER+1:22"

/obj/screen/exosuit/toggle
name = "toggle"
Expand Down Expand Up @@ -363,9 +364,9 @@
/obj/screen/exosuit/heat
name = "heat probe"
icon_state = "heatprobe"
screen_loc = "RIGHT-2:28,CENTER+1:12"
var/celsius = TRUE
var/obj/screen/exosuit/needle/gauge_needle = null
desc = "TEST"

/obj/screen/exosuit/heat/Initialize(mapload, mob/_owner, ui_style, ui_color, ui_alpha)
. = ..()
Expand Down Expand Up @@ -417,6 +418,7 @@
/obj/screen/exosuit/health
name = "exosuit integrity"
icon_state = "health"
screen_loc = "RIGHT-2:28,CENTER:12"

/obj/screen/exosuit/health/handle_click(mob/user, params)
if(!..())
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/hud/screen/screen_mob_modifier.dm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/obj/screen/mob_modifiers
screen_loc = "CENTER,TOP"
screen_loc = "CENTER:8,TOP"
icon_state = "blank"
requires_ui_style = FALSE

Expand Down
9 changes: 3 additions & 6 deletions code/controllers/subsystems/initialization/robots.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,19 @@ SUBSYSTEM_DEF(robots)
var/list/robot_alt_titles = list()

var/list/mob_types_by_title = list(
"cyborg, flying" = /mob/living/silicon/robot/flying,
"robot, flying" = /mob/living/silicon/robot/flying
)

var/list/mmi_types_by_title = list(
"cyborg" = /obj/item/organ/internal/brain_interface,
var/list/processor_types_by_title = list(
"robot" = /obj/item/organ/internal/brain/robotic,
"cyborg, flying" = /obj/item/organ/internal/brain_interface,
"robot, flying" = /obj/item/organ/internal/brain/robotic
)

/datum/controller/subsystem/robots/Initialize()
. = ..()

// This is done via loop instead of just assignment in order to trim associations.
for(var/title in (mob_types_by_title|mmi_types_by_title))
for(var/title in (mob_types_by_title|processor_types_by_title))
robot_alt_titles |= capitalize(title)
sortTim(robot_alt_titles, /proc/cmp_text_asc)

Expand Down Expand Up @@ -58,7 +55,7 @@ SUBSYSTEM_DEF(robots)
.[include_override] = modules[include_override]

/datum/controller/subsystem/robots/proc/get_brain_type_by_title(var/check_title)
. = mmi_types_by_title[lowertext(trim(check_title))] || /obj/item/organ/internal/brain/robotic
. = processor_types_by_title[lowertext(trim(check_title))] || /obj/item/organ/internal/brain/robotic

/datum/controller/subsystem/robots/proc/get_mob_type_by_title(var/check_title)
. = mob_types_by_title[lowertext(trim(check_title))] || /mob/living/silicon/robot
2 changes: 1 addition & 1 deletion code/datums/extensions/abilities/ability_button.dm
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
/obj/screen/ability/button/handle_click(mob/user, params)
if(owning_handler.prepared_ability == ability)
owning_handler.cancel_prepared_ability()
else if(ability.use_ability(user, get_turf(user), owning_handler)) // tmp, needs better/multi-step target selection
else if(ability.use_ability(user, user, owning_handler)) // tmp, needs better/multi-step target selection
update_icon()
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), ability.get_cooldown_time(ability.get_metadata_for_user(user)) + 1)

Expand Down
8 changes: 4 additions & 4 deletions code/datums/extensions/abilities/ability_decl.dm
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@

else
// Otherwise, just apply to the target directly.
apply_effect(user, target, metadata)
apply_ability_effect(user, target, metadata)

if(end_prep_on_cast && handler.prepared_ability == src)
handler.cancel_prepared_ability()
Expand Down Expand Up @@ -325,7 +325,7 @@

return TRUE

/decl/ability/proc/apply_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile)
/decl/ability/proc/apply_ability_effect(mob/user, atom/hit_target, list/metadata, obj/item/projectile/ability/projectile)
SHOULD_CALL_PARENT(TRUE)
if(use_sound)
playsound(get_turf(user), use_sound, use_sound_volume, 1)
Expand All @@ -339,7 +339,7 @@
show_ability_cast_msg(user, targets, metadata)
while(length(targets))
var/target = targets[1]
apply_effect_to(user, target, metadata)
apply_ability_effect_to(user, target, metadata)
targets = prune_targets(user, target, targets, metadata)
finish_casting(user, hit_target, metadata)

Expand All @@ -366,7 +366,7 @@
ability_overlay.set_density(FALSE)
QDEL_IN(ability_overlay, overlay_lifespan)

/decl/ability/proc/apply_effect_to(mob/user, atom/target, list/metadata)
/decl/ability/proc/apply_ability_effect_to(mob/living/user, atom/target, list/metadata)
SHOULD_CALL_PARENT(TRUE)
SHOULD_NOT_SLEEP(TRUE)
apply_visuals(user, target, metadata)
Expand Down
6 changes: 3 additions & 3 deletions code/datums/extensions/abilities/ability_handler.dm
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
add_screen_element(category_toggle, "toggle", TRUE)
toggle_category_visibility(TRUE)

/datum/ability_handler/proc/refresh_element_positioning(row = 1, col = 1)
/datum/ability_handler/proc/refresh_element_positioning(row = 1, col = 0)
if(!LAZYLEN(screen_elements))
return 0
var/button_pos = col
Expand All @@ -134,14 +134,14 @@
for(var/ability in screen_elements)
var/obj/screen/element = screen_elements[ability]
if(istype(element, /obj/screen/ability/category))
element.screen_loc = "RIGHT-[col]:-4,TOP-[row]"
element.screen_loc = "RIGHT-[col]:-4,TOP-[row]:-24"
else if(!element.invisibility)
button_pos++
if((button_pos-col) > 5)
button_row++
.++
button_pos = col+1
element.screen_loc = "RIGHT-[button_pos]:-4,TOP-[button_row]"
element.screen_loc = "RIGHT-[button_pos]:-4,TOP-[button_row]:-24"

/datum/ability_handler/proc/toggle_category_visibility(force_state)
showing_abilities = isnull(force_state) ? !showing_abilities : force_state
Expand Down
4 changes: 2 additions & 2 deletions code/datums/extensions/abilities/ability_item.dm
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
// Fire a projectile if that is how this ability works.
ability.fire_projectile_at(user, target, metadata)
else
// Otherwise, apply to the target. Range checking etc. will be handled in apply_effect().
ability.apply_effect(user, target, metadata)
// Otherwise, apply to the target. Range checking etc. will be handled in apply_ability_effect().
ability.apply_ability_effect(user, target, metadata)

// Clean up our item if needed.
if(ability.item_end_on_cast)
Expand Down
4 changes: 2 additions & 2 deletions code/datums/extensions/abilities/ability_projectile.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@

/obj/item/projectile/ability/Bump(var/atom/A, forced=0)
if(loc && carried_ability && !expended)
carried_ability.apply_effect(owner, A, ability_metadata, src)
carried_ability.apply_ability_effect(owner, A, ability_metadata, src)
return TRUE

/obj/item/projectile/ability/on_impact(var/atom/A)
if(loc && carried_ability && !expended)
carried_ability.apply_effect(owner, A, ability_metadata, src)
carried_ability.apply_ability_effect(owner, A, ability_metadata, src)
return TRUE
26 changes: 21 additions & 5 deletions code/datums/extensions/abilities/ability_targeting.dm
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,35 @@
return FALSE
return TRUE

/decl/ability_targeting/target_self
target_turf = FALSE

/decl/ability_targeting/target_self/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability)
return target == user

/decl/ability_targeting/target_self/get_affected(mob/user, atom/hit_target, list/metadata, decl/ability/ability, obj/item/projectile/ability/projectile)
return list(user)

/decl/ability_targeting/clear_turf
ignore_dense_turfs = TRUE

/decl/ability_targeting/clear_turf/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability)
. = ..() && isturf(target)
if(.)
var/turf/target_turf = target
return !target_turf.contains_dense_objects(user)
var/turf/turf_to_target = target
return !turf_to_target.contains_dense_objects(user)

/decl/ability_targeting/single_atom
target_turf = FALSE
user_is_immune = TRUE

/decl/ability_targeting/single_atom/can_target_user
user_is_immune = FALSE

/decl/ability_targeting/living_mob
target_turf = FALSE
/decl/ability_targeting/single_atom/get_affected(mob/user, atom/hit_target, list/metadata, decl/ability/ability, obj/item/projectile/ability/projectile)
return list(hit_target)

/decl/ability_targeting/living_mob/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability)
/decl/ability_targeting/single_atom/living_mob/validate_target(mob/user, atom/target, list/metadata, decl/ability/ability)
. = ..() && isliving(target)
if(.)
var/mob/living/victim = target
Expand Down
1 change: 0 additions & 1 deletion code/datums/trading/traders/goods.dm
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ Sells devices, odds and ends, and medical stuff
/obj/item/synthesized_instrument/violin = TRADER_THIS_TYPE,
/obj/item/hailer = TRADER_THIS_TYPE,
/obj/item/uv_light = TRADER_THIS_TYPE,
/obj/item/organ/internal/brain_interface = TRADER_SUBTYPES_ONLY,
/obj/item/robotanalyzer = TRADER_THIS_TYPE,
/obj/item/chems/toner_cartridge = TRADER_THIS_TYPE,
/obj/item/camera_film = TRADER_THIS_TYPE,
Expand Down
2 changes: 2 additions & 0 deletions code/datums/traits/_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@
var/available_at_map_tech = MAP_TECH_LEVEL_ANY
/// Whether or not a rejuvenation should apply this aspect.
var/reapply_on_rejuvenation = FALSE
/// Whether this trait should be copied and applied by mob snapshots.
var/is_heritable = TRUE
/// What species can select this trait in chargen?
var/list/permitted_species
/// What species cannot select this trait in chargen?
Expand Down
1 change: 1 addition & 0 deletions code/datums/traits/maluses/amputations.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
category = "Missing Limbs"
abstract_type = /decl/trait/malus/amputation
reapply_on_rejuvenation = TRUE
is_heritable = FALSE
var/list/apply_to_limbs
var/list/ban_traits_relating_to_limbs

Expand Down
1 change: 1 addition & 0 deletions code/datums/traits/prosthetics/prosthetic_limbs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
available_at_map_tech = MAP_TECH_LEVEL_ANY // the base trait must be available so that wooden prostheses are available
abstract_type = /decl/trait/prosthetic_limb
reapply_on_rejuvenation = TRUE
is_heritable = FALSE
var/fullbody_synthetic_only = FALSE
var/replace_children = TRUE
var/check_bodytype
Expand Down
1 change: 1 addition & 0 deletions code/datums/traits/prosthetics/prosthetic_organs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
available_at_map_tech = MAP_TECH_LEVEL_SPACE
category = "Prosthetic Organs"
reapply_on_rejuvenation = TRUE
is_heritable = FALSE
var/synthetic_bodytype_restricted = FALSE
var/apply_to_organ

Expand Down
36 changes: 18 additions & 18 deletions code/game/area/areas.dm
Original file line number Diff line number Diff line change
Expand Up @@ -137,46 +137,46 @@ var/global/list/areas = list()
..()
return QDEL_HINT_HARDDEL

// Changes the area of T to A. Do not do this manually.
// Changes the area of src to A. Do not do this manually.
// Area is expected to be a non-null instance.
/proc/ChangeArea(var/turf/T, var/area/A)
/turf/proc/ChangeArea(var/area/A)
if(!istype(A))
CRASH("Area change attempt failed: invalid area supplied.")
var/old_outside = T.is_outside()
var/area/old_area = get_area(T)
var/old_outside = is_outside()
var/area/old_area = get_area(src)
if(old_area == A)
return

var/old_area_ambience = old_area?.interior_ambient_light_modifier

A.contents.Add(T)
A.contents.Add(src)
if(old_area)
old_area.Exited(T, A)
for(var/atom/movable/AM as anything in T)
old_area.Exited(src, A)
for(var/atom/movable/AM as anything in src)
old_area.Exited(AM, A) // Note: this _will_ raise exited events.
A.Entered(T, old_area)
for(var/atom/movable/AM as anything in T)
A.Entered(src, old_area)
for(var/atom/movable/AM as anything in src)
A.Entered(AM, old_area) // Note: this will _not_ raise moved or entered events. If you change this, you must also change everything which uses them.

for(var/obj/machinery/M in T)
for(var/obj/machinery/M in src)
M.area_changed(old_area, A) // They usually get moved events, but this is the one way an area can change without triggering one.

T.update_registrations_on_adjacent_area_change()
update_registrations_on_adjacent_area_change()
for(var/direction in global.cardinal)
var/turf/adjacent_turf = get_step(T, direction)
var/turf/adjacent_turf = get_step(src, direction)
if(adjacent_turf)
adjacent_turf.update_registrations_on_adjacent_area_change()

// Handle updating weather and atmos if the outside status of the turf changed.
if(T.is_outside == OUTSIDE_AREA)
T.update_external_atmos_participation() // Refreshes outside status and adds exterior air to turf air if necessary.
if(is_outside == OUTSIDE_AREA)
update_external_atmos_participation() // Refreshes outside status and adds exterior air to turf air if necessary.

if(T.is_outside() != old_outside)
T.update_weather()
if(is_outside() != old_outside)
update_weather()
if(SSambience.initialized) // if not initialized, we'll loop over all turfs anyway
AMBIENCE_QUEUE_TURF(T)
AMBIENCE_QUEUE_TURF(src)
else if(A.interior_ambient_light_modifier != old_area_ambience && SSambience.initialized)
AMBIENCE_QUEUE_TURF(T)
AMBIENCE_QUEUE_TURF(src)

/turf/proc/update_registrations_on_adjacent_area_change()
for(var/obj/machinery/door/firedoor/door in src)
Expand Down
2 changes: 1 addition & 1 deletion code/game/atoms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@

/* Set the atom colour. This is a stub effectively due to the broad use of direct setting. */
// TODO: implement this everywhere that it should be used instead of direct setting.
/atom/proc/set_color(var/new_color)
/atom/proc/set_color(new_color, skip_update)
if(isnull(new_color))
return reset_color()
if(color != new_color)
Expand Down
Loading
Loading