", "\[logo_nt\]")
+ t = replacetext(t, "
", "\[logo_nt_small\]")
+ t = replacetext(t, "
", "\[logo_zh\]")
+ t = replacetext(t, "
", "\[logo_idris\]")
+ t = replacetext(t, "
", "\[logo_eridani\]")
+ t = replacetext(t, "
", "\[logo_zavod\]")
+ t = replacetext(t, "
", "\[logo_hp\]")
+ t = replacetext(t, "
", "\[flag_be\]")
+ t = replacetext(t, "
", "\[flag_elyra\]")
+ t = replacetext(t, "
", "\[flag_sol\]")
+ t = replacetext(t, "
", "\[flag_coc\]")
+ t = replacetext(t, "
", "\[flag_dom\]")
+ t = replacetext(t, "
", "\[flag_jargon\]")
+ t = replacetext(t, "
", "\[flag_pra\]")
+ t = replacetext(t, "
", "\[flag_dpra\]")
+ t = replacetext(t, "
", "\[flag_nka\]")
+ t = replacetext(t, "
", "\[flag_izweski\]")
+
return t
//Used for applying byonds text macros to strings that are loaded at runtime
@@ -638,3 +658,10 @@
if(ending && !correct_punctuation[ending])
string += "."
return string
+
+/proc/num2loadingbar(percent as num, numSquares = 20, reverse = FALSE)
+ var/loadstring = ""
+ var/limit = reverse ? numSquares - percent*numSquares : percent*numSquares
+ for (var/i in 1 to numSquares)
+ loadstring += i <= limit ? "█" : "░"
+ return "\[[loadstring]\]"
\ No newline at end of file
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index f2fb8cf740c..4995a5ddc96 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -647,6 +647,13 @@ Turf and target are seperate in case you want to teleport some distance from a t
if (progbar)
qdel(progbar)
+/proc/atom_maintain_position(var/atom/A, var/atom/location)
+ if(QDELETED(A) || QDELETED(location))
+ return FALSE
+ if(A.loc != location)
+ return FALSE
+ return TRUE
+
//Takes: Anything that could possibly have variables and a varname to check.
//Returns: 1 if found, 0 if not.
/proc/hasvar(var/datum/A, var/varname)
@@ -811,23 +818,6 @@ var/global/list/common_tools = list(
return 1
return 0
-//Returns 1 if the given item is capable of popping things like balloons, inflatable barriers, or cutting police tape.
-/proc/can_puncture(obj/item/W as obj) // For the record, WHAT THE HELL IS THIS METHOD OF DOING IT?
- if(!W)
- return 0
- if(W.sharp)
- return 1
- return ( \
- W.sharp || \
- W.isscrewdriver() || \
- W.ispen() || \
- W.iswelder() || \
- istype(W, /obj/item/flame/lighter/zippo) || \
- istype(W, /obj/item/flame/match) || \
- istype(W, /obj/item/clothing/mask/smokable/cigarette) || \
- istype(W, /obj/item/shovel) \
- )
-
/proc/is_surgery_tool(obj/item/W)
return istype(W, /obj/item/surgery)
@@ -838,7 +828,7 @@ var/global/list/common_tools = list(
/proc/can_operate(mob/living/carbon/M) //If it's 2, commence surgery, if it's 1, fail surgery, if it's 0, attack
var/surgery_attempt = SURGERY_IGNORE
var/located = FALSE
- if(locate(/obj/machinery/optable, M.loc))
+ if(istype(M.buckled_to, /obj/machinery/stasis_bed) || locate(/obj/machinery/optable, M.loc))
located = TRUE
surgery_attempt = SURGERY_SUCCESS
else if(locate(/obj/structure/bed/roller, M.loc))
@@ -1037,6 +1027,10 @@ var/global/known_proc = new /proc/get_type_ref_bytes
colour += temp_col
return "#[colour]"
+/proc/color_square(red, green, blue, hex)
+ var/color = hex ? hex : "#[num2hex(red, 2)][num2hex(green, 2)][num2hex(blue, 2)]"
+ return "___"
+
// call to generate a stack trace and print to runtime logs
/proc/crash_with(msg)
CRASH(msg)
diff --git a/code/_helpers/visual_filters.dm b/code/_helpers/visual_filters.dm
new file mode 100644
index 00000000000..ed9284d8f2a
--- /dev/null
+++ b/code/_helpers/visual_filters.dm
@@ -0,0 +1,58 @@
+// These involve BYOND's built in filters that do visual effects, and not stuff that distinguishes between things.
+
+// All of this ported from TG.
+// And then ported to Nebula from Polaris.
+// And then ported to Aurora
+/atom/movable
+ var/list/filter_data // For handling persistent filters
+
+/proc/cmp_filter_data_priority(list/A, list/B)
+ return A["priority"] - B["priority"]
+
+/atom/movable/proc/add_filter(filter_name, priority, list/params)
+ LAZYINITLIST(filter_data)
+ var/list/p = params.Copy()
+ p["priority"] = priority
+ filter_data[filter_name] = p
+ update_filters()
+
+/atom/movable/proc/update_filters()
+ filters = null
+ filter_data = sortTim(filter_data, /proc/cmp_filter_data_priority, TRUE)
+ for(var/f in filter_data)
+ var/list/data = filter_data[f]
+ var/list/arguments = data.Copy()
+ arguments -= "priority"
+ filters += filter(arglist(arguments))
+ UPDATE_OO_IF_PRESENT
+
+/atom/movable/proc/get_filter(filter_name)
+ if(filter_data && filter_data[filter_name])
+ return filters[filter_data.Find(filter_name)]
+
+// Polaris Extensions
+/atom/movable/proc/remove_filter(filter_name)
+ var/thing = get_filter(filter_name)
+ if(thing)
+ LAZYREMOVE(filter_data, filter_name)
+ filters -= thing
+ update_filters()
+
+/// Animate a given filter on this atom. All params after the first are passed to animate().
+/atom/movable/proc/animate_filter(filter_name, list/params)
+ if (!filter_data || !filter_data[filter_name])
+ return
+
+ var/list/monkeypatched_params = params.Copy()
+ monkeypatched_params.Insert(1, null)
+ var/index = filter_data.Find(filter_name)
+
+ // First, animate ourselves.
+ monkeypatched_params[1] = filters[index]
+ animate(arglist(monkeypatched_params))
+
+ // If we're being copied by Z-Mimic, update mimics too.
+ if (bound_overlay)
+ for (var/atom/movable/AM as anything in get_above_oo())
+ monkeypatched_params[1] = AM.filters[index]
+ animate(arglist(monkeypatched_params))
\ No newline at end of file
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 6c4b5b282cb..bf534e43b02 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -222,9 +222,10 @@
animals lunging, etc.
*/
/mob/proc/RangedAttack(var/atom/A, var/params)
- if(!mutations.len) return
- if((LASER_EYES in mutations) && a_intent == I_HURT)
+ if(length(mutations) && (LASER_EYES in mutations) && a_intent == I_HURT)
LaserEyes(A, params) // moved into a proc below
+ return
+ A.attack_ranged(src, params)
/*
Restrained ClickOn
diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm
index 65f78384ac8..5dee3687852 100644
--- a/code/_onclick/drag_drop.dm
+++ b/code/_onclick/drag_drop.dm
@@ -5,14 +5,14 @@
recieving object instead, so that's the default action. This allows you to drag
almost anything into a trash can.
*/
-/atom/MouseDrop(atom/over)
- if(!usr || !over) return
- if(!Adjacent(usr) || !over.Adjacent(usr)) return // should stop you from dragging through windows
+/atom/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params)
+ if(!usr || !over)
+ return
+ if(!Adjacent(usr) || !over.Adjacent(usr))
+ return // should stop you from dragging through windows
- spawn(0)
- over.MouseDrop_T(src,usr)
- return
+ INVOKE_ASYNC(over, /atom/.proc/MouseDrop_T, src, usr, src_location, over_location, src_control, over_control, params)
// receive a mousedrop
-/atom/proc/MouseDrop_T(atom/dropping, mob/user)
- return
+/atom/proc/MouseDrop_T(atom/dropping, mob/user, src_location, over_location, src_control, over_control, params)
+ return
\ No newline at end of file
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index be78ab8d8c6..3cee01c4d1e 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -61,7 +61,7 @@
#define ui_acti_alt "EAST-1:28,SOUTH:5" //alternative intent switcher for when the interface is hidden (F12)
// vampire
-#define ui_suck "EAST-4:22,SOUTH:5"
+#define ui_suck "EAST-3:24,SOUTH+1:7"
#define ui_borg_pull "EAST-3:24,SOUTH+1:7"
#define ui_borg_module "EAST-2:26,SOUTH+1:7"
@@ -81,6 +81,8 @@
#define ui_oxygen "EAST-1:28,NORTH-4:23"
#define ui_pressure "EAST-1:28,NORTH-5:21"
#define ui_paralysis "EAST-1:28,NORTH-10:23"
+#define ui_energy_display "EAST-1:28,NORTH-6:50"
+#define ui_instability_display "EAST-1:28,NORTH-5:50"
#define ui_alien_toxin "EAST-1:28,NORTH-2:25"
#define ui_alien_fire "EAST-1:28,NORTH-3:25"
diff --git a/code/_onclick/hud/ability_screen_objects.dm b/code/_onclick/hud/ability_screen_objects.dm
new file mode 100644
index 00000000000..138d8b4d553
--- /dev/null
+++ b/code/_onclick/hud/ability_screen_objects.dm
@@ -0,0 +1,314 @@
+/obj/screen/movable/ability_master
+ name = "Abilities"
+ icon = 'icons/mob/screen_spells.dmi'
+ icon_state = "grey_spell_ready"
+ var/list/obj/screen/ability/ability_objects = list()
+ var/showing = FALSE // If we're 'open' or not.
+
+ var/open_state = "master_open" // What the button looks like when it's 'open', showing the other buttons.
+ var/closed_state = "master_closed" // Button when it's 'closed', hiding everything else.
+
+ screen_loc = ui_spell_master // TODO: Rename
+
+ var/mob/my_mob // The mob that possesses this hud object.
+
+/obj/screen/movable/ability_master/Initialize(mapload, owner)
+ . = ..()
+ if(owner)
+ my_mob = owner
+ update_abilities(0, owner)
+
+/obj/screen/movable/ability_master/Destroy()
+ . = ..()
+ //Get rid of the ability objects.
+ remove_all_abilities()
+ ability_objects.Cut()
+
+ // After that, remove ourselves from the mob seeing us, so we can qdel cleanly.
+ if(my_mob)
+ my_mob.ability_master = null
+ if(my_mob.client && my_mob.client.screen)
+ my_mob.client.screen -= src
+ my_mob = null
+
+/obj/screen/movable/ability_master/MouseDrop()
+ if(showing)
+ return
+
+ return ..()
+
+/obj/screen/movable/ability_master/Click()
+ if(!ability_objects.len) // If we're empty for some reason.
+ return
+
+ toggle_open()
+
+/obj/screen/movable/ability_master/proc/toggle_open(var/forced_state = 0)
+ if(showing && (forced_state != 2)) // We are closing the ability master, hide the abilities.
+ for(var/obj/screen/ability/O in ability_objects)
+ if(my_mob && my_mob.client)
+ my_mob.client.screen -= O
+ showing = FALSE
+ overlays.len = 0
+ overlays.Add(closed_state)
+ else if(forced_state != 1) // We're opening it, show the icons.
+ open_ability_master()
+ update_abilities(1)
+ showing = TRUE
+ overlays.len = 0
+ overlays.Add(open_state)
+ update_icon()
+
+/obj/screen/movable/ability_master/proc/open_ability_master()
+ var/list/screen_loc_xy = splittext(screen_loc,",")
+
+ //Create list of X offsets
+ var/list/screen_loc_X = splittext(screen_loc_xy[1],":")
+ var/x_position = decode_screen_X(screen_loc_X[1])
+ var/x_pix = screen_loc_X[2]
+
+ //Create list of Y offsets
+ var/list/screen_loc_Y = splittext(screen_loc_xy[2],":")
+ var/y_position = decode_screen_Y(screen_loc_Y[1])
+ var/y_pix = screen_loc_Y[2]
+
+ for(var/i = 1; i <= ability_objects.len; i++)
+ var/obj/screen/ability/A = ability_objects[i]
+ var/xpos = x_position + (x_position < 8 ? 1 : -1)*(i%7)
+ var/ypos = y_position + (y_position < 8 ? round(i/7) : -round(i/7))
+ A.screen_loc = "[encode_screen_X(xpos)]:[x_pix],[encode_screen_Y(ypos)]:[y_pix]"
+ if(my_mob && my_mob.client)
+ my_mob.client.screen += A
+
+/obj/screen/movable/ability_master/proc/update_abilities(forced = 0, mob/user)
+ update_icon()
+ if(user && user.client)
+ if(!(src in user.client.screen))
+ user.client.screen += src
+ var/i = 1
+ for(var/obj/screen/ability/ability in ability_objects)
+ ability.update_icon(forced)
+ ability.index = i
+ ability.maptext = "[ability.index]" // Slot number
+ i++
+
+/obj/screen/movable/ability_master/update_icon()
+ if(ability_objects.len)
+ invisibility = 0
+ else
+ invisibility = 101
+
+/obj/screen/movable/ability_master/proc/add_ability(var/name_given)
+ if(!name)
+ return
+
+ var/obj/screen/ability/new_button = new /obj/screen/ability
+ new_button.ability_master = src
+ new_button.name = name_given
+ new_button.ability_icon_state = name_given
+ new_button.update_icon(1)
+ ability_objects.Add(new_button)
+ if(my_mob.client)
+ toggle_open(2) //forces the icons to refresh on screen
+
+/obj/screen/movable/ability_master/proc/remove_ability(var/obj/screen/ability/ability)
+ if(!ability)
+ return
+ ability_objects.Remove(ability)
+ qdel(ability)
+
+
+ if(ability_objects.len)
+ toggle_open(showing + 1)
+ update_icon()
+
+/obj/screen/movable/ability_master/proc/remove_all_abilities()
+ for(var/obj/screen/ability/A in ability_objects)
+ remove_ability(A)
+
+/obj/screen/movable/ability_master/proc/get_ability_by_name(name_to_search)
+ for(var/obj/screen/ability/A in ability_objects)
+ if(A.name == name_to_search)
+ return A
+ return
+
+/obj/screen/movable/ability_master/proc/get_ability_by_proc_ref(proc_ref)
+ for(var/obj/screen/ability/verb_based/V in ability_objects)
+ if(V.verb_to_call == proc_ref)
+ return V
+ return
+
+/obj/screen/movable/ability_master/proc/get_ability_by_instance(var/obj/instance/)
+ for(var/obj/screen/ability/obj_based/O in ability_objects)
+ if(O.object == instance)
+ return O
+ return
+
+/mob/Login()
+ ..()
+ if(ability_master)
+ ability_master.toggle_open(1)
+ client.screen -= ability_master
+
+/mob/Initialize()
+ . = ..()
+ ability_master = new /obj/screen/movable/ability_master(FALSE, src)
+
+///////////ACTUAL ABILITIES////////////
+//This is what you click to do things//
+///////////////////////////////////////
+/obj/screen/ability
+ icon = 'icons/mob/screen_spells.dmi'
+ icon_state = "grey_spell_base"
+ maptext_x = 3
+ var/background_base_state = "grey"
+ var/ability_icon_state = null
+ var/index = 0
+
+ var/obj/screen/movable/ability_master/ability_master
+
+/obj/screen/ability/Destroy()
+ if(ability_master)
+ ability_master.ability_objects -= src
+ if(ability_master.my_mob && ability_master.my_mob.client)
+ ability_master.my_mob.client.screen -= src
+ if(ability_master && !ability_master.ability_objects.len)
+ ability_master.update_icon()
+ ability_master = null
+ ..()
+
+/obj/screen/ability/update_icon()
+ overlays.Cut()
+ icon_state = "[background_base_state]_spell_base"
+
+ overlays += ability_icon_state
+
+/obj/screen/ability/Click()
+ if(!usr)
+ return
+
+ activate()
+
+/obj/screen/ability/MouseDrop(var/atom/A)
+ if(!A || A == src)
+ return
+ if(istype(A, /obj/screen/ability))
+ var/obj/screen/ability/ability = A
+ if(ability.ability_master && ability.ability_master == src.ability_master)
+ ability_master.ability_objects.Swap(src.index, ability.index)
+ ability_master.toggle_open(2) // To update the UI.
+
+
+// Makes the ability be triggered. The subclasses of this are responsible for carrying it out in whatever way it needs to.
+/obj/screen/ability/proc/activate()
+ log_debug("[src] had activate() called.")
+
+// This checks if the ability can be used.
+/obj/screen/ability/proc/can_activate()
+ return TRUE
+
+/client/verb/activate_ability(var/slot as num)
+ set name = ".activate_ability"
+ if(!mob)
+ return // Paranoid.
+ if(isnull(slot) || !isnum(slot))
+ to_chat(src, ".activate_ability requires a number as input, corrisponding to the slot you wish to use.")
+ return // Bad input.
+ if(!mob.ability_master)
+ return // No abilities.
+ if(slot > mob.ability_master.ability_objects.len || slot <= 0)
+ return // Out of bounds.
+ var/obj/screen/ability/A = mob.ability_master.ability_objects[slot]
+ A.activate()
+
+//////////Verb Abilities//////////
+//Buttons to trigger verbs/procs//
+//////////////////////////////////
+
+/obj/screen/ability/verb_based
+ var/verb_to_call = null
+ var/object_used = null
+ var/arguments_to_use = list()
+
+/obj/screen/ability/verb_based/activate()
+ if(object_used && verb_to_call)
+ call(object_used,verb_to_call)(arguments_to_use) //TODOMATT: WHY GOD WHY
+
+/obj/screen/movable/ability_master/proc/add_verb_ability(var/object_given, var/verb_given, var/name_given, var/ability_icon_given, var/arguments)
+ if(!object_given)
+ message_admins("ERROR: add_verb_ability() was not given an object in its arguments.")
+ if(!verb_given)
+ message_admins("ERROR: add_verb_ability() was not given a verb/proc in its arguments.")
+ if(get_ability_by_proc_ref(verb_given))
+ return // Duplicate
+ var/obj/screen/ability/verb_based/A = new /obj/screen/ability/verb_based()
+ A.ability_master = src
+ A.object_used = object_given
+ A.verb_to_call = verb_given
+ A.ability_icon_state = ability_icon_given
+ A.name = name_given
+ if(arguments)
+ A.arguments_to_use = arguments
+ ability_objects.Add(A)
+ if(my_mob.client)
+ toggle_open(2) //forces the icons to refresh on screen
+
+//Changeling Abilities
+/obj/screen/ability/verb_based/changeling
+ icon_state = "ling_spell_base"
+ background_base_state = "ling"
+
+/obj/screen/movable/ability_master/proc/add_ling_ability(var/object_given, var/verb_given, var/name_given, var/ability_icon_given, var/arguments)
+ if(!object_given)
+ message_admins("ERROR: add_ling_ability() was not given an object in its arguments.")
+ if(!verb_given)
+ message_admins("ERROR: add_ling_ability() was not given a verb/proc in its arguments.")
+ if(get_ability_by_proc_ref(verb_given))
+ return // Duplicate
+ var/obj/screen/ability/verb_based/changeling/A = new /obj/screen/ability/verb_based/changeling()
+ A.ability_master = src
+ A.object_used = object_given
+ A.verb_to_call = verb_given
+ A.ability_icon_state = ability_icon_given
+ A.name = name_given
+ if(arguments)
+ A.arguments_to_use = arguments
+ ability_objects.Add(A)
+ if(my_mob.client)
+ toggle_open(2) //forces the icons to refresh on screen
+
+
+/////////Obj Abilities////////
+//Buttons to trigger objects//
+//////////////////////////////
+
+/obj/screen/ability/obj_based
+ var/obj/object = null
+
+/obj/screen/ability/obj_based/activate()
+ if(object)
+ object.Click()
+
+// Technomancer
+/obj/screen/ability/obj_based/technomancer
+ icon_state = "wiz_spell_base"
+ background_base_state = "wiz"
+
+/obj/screen/ability/obj_based/technomancer/activate()
+ if(ability_master.my_mob.incapacitated())
+ return
+ . = ..()
+
+/obj/screen/movable/ability_master/proc/add_technomancer_ability(var/obj/object_given, var/ability_icon_given)
+ if(!object_given)
+ message_admins("ERROR: add_technomancer_ability() was not given an object in its arguments.")
+ if(get_ability_by_instance(object_given))
+ return // Duplicate
+ var/obj/screen/ability/obj_based/technomancer/A = new /obj/screen/ability/obj_based/technomancer()
+ A.ability_master = src
+ A.object = object_given
+ A.ability_icon_state = ability_icon_given
+ A.name = object_given.name
+ ability_objects.Add(A)
+ if(my_mob.client)
+ toggle_open(2) //forces the icons to refresh on screen
\ No newline at end of file
diff --git a/code/_onclick/hud/action.dm b/code/_onclick/hud/action.dm
index 4498c7406f1..57599be68d2 100644
--- a/code/_onclick/hud/action.dm
+++ b/code/_onclick/hud/action.dm
@@ -234,6 +234,10 @@
if(istype(O))
O.refresh_action_button()
+/datum/action/item_action/organ/night_eyes
+ check_flags = AB_CHECK_STUNNED|AB_CHECK_ALIVE|AB_CHECK_INSIDE
+ button_icon_state = "night_eyes"
+
#undef AB_WEST_OFFSET
#undef AB_NORTH_OFFSET
#undef AB_MAX_COLUMNS
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index e8cbf08c352..42f2d8e7838 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -140,6 +140,8 @@ var/list/global_huds
var/hotkey_ui_hidden = 0 //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons)
var/obj/screen/lingchemdisplay
+ var/obj/screen/instability_display //Technomancer.
+ var/obj/screen/energy_display //Technomancer.
var/obj/screen/blobpwrdisplay
var/obj/screen/blobhealthdisplay
var/obj/screen/r_hand_hud_object
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 50d7b09a2a7..3dfe12f394c 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -341,6 +341,16 @@
mymob.pain = new /obj/screen/fullscreen/pain(null)
hud_elements |= mymob.pain
+ mymob.instability_display = new /obj/screen/instability()
+ mymob.instability_display.screen_loc = ui_instability_display
+ mymob.instability_display.icon_state = "wiz_instability_none"
+ hud_elements |= mymob.instability_display
+
+ mymob.energy_display = new /obj/screen/energy()
+ mymob.energy_display.screen_loc = ui_energy_display
+ mymob.energy_display.icon_state = "wiz_energy"
+ hud_elements |= mymob.energy_display
+
mymob.zone_sel = new /obj/screen/zone_sel(null)
mymob.zone_sel.icon = ui_style
mymob.zone_sel.color = ui_color
@@ -513,3 +523,15 @@
to_chat(usr, SPAN_WARNING("You are completely paralyzed and cannot move!"))
else
to_chat(usr, SPAN_NOTICE("You are walking around completely fine."))
+
+/obj/screen/instability
+ name = "instability"
+ icon = 'icons/mob/screen_gen.dmi'
+ icon_state = "instability-1"
+ invisibility = 101
+
+/obj/screen/energy
+ name = "energy"
+ icon = 'icons/mob/screen_gen.dmi'
+ icon_state = "wiz_energy"
+ invisibility = 101
diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm
index 783ce41a372..8987251c062 100644
--- a/code/_onclick/hud/radial.dm
+++ b/code/_onclick/hud/radial.dm
@@ -254,7 +254,7 @@ var/global/list/radial_menus = list()
current_user = M.client
//Blank
menu_holder = image(icon = 'icons/effects/effects.dmi', loc = anchor, icon_state = "nothing", layer = HUD_LAYER)
- menu_holder.appearance_flags |= KEEP_APART
+ menu_holder.appearance_flags |= KEEP_APART|RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM
menu_holder.vis_contents += elements + close_button
current_user.images += menu_holder
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 4e3f7b801c6..2f27b4aeb76 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -30,7 +30,10 @@
A.attack_hand(src)
-/atom/proc/attack_hand(mob/user as mob)
+/atom/proc/attack_hand(mob/user)
+ return
+
+/atom/proc/attack_ranged(mob/user, params)
return
/mob/proc/attack_empty_hand(var/bp_hand)
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 409884ea627..61f8493b1d8 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -321,6 +321,8 @@ var/list/gamemode_cache = list()
var/lore_summary
+ var/current_space_sector
+
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L)
@@ -895,6 +897,9 @@ var/list/gamemode_cache = list()
if("time_to_call_emergency_shuttle")
config.time_to_call_emergency_shuttle = text2num(value)
+ if("current_space_sector")
+ config.current_space_sector = value
+
if("force_map")
override_map = value
diff --git a/code/controllers/subsystems/arrivals.dm b/code/controllers/subsystems/arrivals.dm
index 0285a511c05..cd3ed8b9449 100644
--- a/code/controllers/subsystems/arrivals.dm
+++ b/code/controllers/subsystems/arrivals.dm
@@ -66,8 +66,6 @@
return 1
if(istype(A,/obj/item/phylactery))
return 1
- if(istype(A,/obj/effect/decal/wizard_mark))
- return 1
for(var/i=1, i<=A.contents.len, i++)
var/atom/B = A.contents[i]
diff --git a/code/controllers/subsystems/assets.dm b/code/controllers/subsystems/assets.dm
index 19f5f8d01f7..b09d9ec6f07 100644
--- a/code/controllers/subsystems/assets.dm
+++ b/code/controllers/subsystems/assets.dm
@@ -2,7 +2,7 @@
/datum/controller/subsystem/assets
name = "Assets"
- init_order = SS_INIT_MISC_FIRST
+ init_order = SS_INIT_ASSETS
flags = SS_BACKGROUND | SS_FIRE_IN_LOBBY
wait = 1
var/list/cache = list()
@@ -18,7 +18,7 @@
/datum/controller/subsystem/assets/Initialize(timeofday)
for(var/type in typesof(/datum/asset))
var/datum/asset/A = type
- if (type != initial(A._abstract) && !initial(A.delayed))
+ if (type != initial(A._abstract))
get_asset_datum(type)
CHECK_TICK
diff --git a/code/controllers/subsystems/initialization/atlas.dm b/code/controllers/subsystems/initialization/atlas.dm
index 951b619f8e8..cecc58f4d0a 100644
--- a/code/controllers/subsystems/initialization/atlas.dm
+++ b/code/controllers/subsystems/initialization/atlas.dm
@@ -19,6 +19,8 @@ var/datum/controller/subsystem/atlas/SSatlas
var/list/list/connected_z_cache = list()
var/z_levels = 0 // Each bit represents a connection between adjacent levels. So the first bit means levels 1 and 2 are connected.
+ var/datum/space_sector/current_sector
+ var/list/possible_sectors = list ()
/datum/controller/subsystem/atlas/stat_entry()
..("W:{X:[world.maxx] Y:[world.maxy] Z:[world.maxz]} ZL:[z_levels]")
@@ -76,6 +78,27 @@ var/datum/controller/subsystem/atlas/SSatlas
QDEL_NULL(maploader)
+ InitializeSectors()
+
+ var/chosen_sector
+ var/using_sector_config = FALSE
+
+ if(config.current_space_sector)
+ chosen_sector = config.current_space_sector
+ using_sector_config = TRUE
+ else
+ chosen_sector = current_map.default_sector
+
+ var/datum/space_sector/selected_sector = SSatlas.possible_sectors[chosen_sector]
+
+ if(!selected_sector)
+ if(using_sector_config)
+ log_debug("atlas: [chosen_sector] used in the config file is not a valid space sector")
+ current_sector = new /datum/space_sector/tau_ceti //if all fails, we go with tau ceti
+ log_debug("atlas: Unable to select [chosen_sector] as a valid space sector. Tau Ceti will be used instead.")
+ else
+ current_sector = selected_sector
+
..()
/datum/controller/subsystem/atlas/proc/load_map_directory(directory, overwrite_default_z = FALSE)
@@ -164,6 +187,15 @@ var/datum/controller/subsystem/atlas/SSatlas
var/datum/spawnpoint/S = new type
spawn_locations[S.display_name] = S
+/datum/controller/subsystem/atlas/proc/InitializeSectors()
+ for (var/type in subtypesof(/datum/space_sector))
+ var/datum/space_sector/space_sector = new type()
+
+ possible_sectors[space_sector.name] = space_sector
+
+ if (!possible_sectors.len)
+ crash_with("No space sectors located in SSatlas.")
+
// Called when there's a fatal, unrecoverable error in mapload. This reboots the server.
/world/proc/map_panic(reason)
to_chat(world, "Fatal error during map setup, unable to continue! Server will reboot in 60 seconds.")
@@ -185,10 +217,6 @@ var/datum/controller/subsystem/atlas/SSatlas
world.name = sname
world.log << "Set world.name to [sname]."
-/proc/system_name()
- ASSERT(current_map)
- return current_map.system_name
-
/proc/commstation_name()
ASSERT(current_map)
return current_map.dock_name
\ No newline at end of file
diff --git a/code/controllers/subsystems/initialization/map_finalization.dm b/code/controllers/subsystems/initialization/map_finalization.dm
index f30304dc96e..58140b3f20b 100644
--- a/code/controllers/subsystems/initialization/map_finalization.dm
+++ b/code/controllers/subsystems/initialization/map_finalization.dm
@@ -73,9 +73,9 @@
log_ss("map_finalization", "Error while creating away mission datum: [ec]")
continue
- if(length(am.valid_maps))
- if(!(current_map.name in am.valid_maps))
- log_ss("map_finalization", "[current_map.name] is not a valid map for [am.name]")
+ if(length(am.valid_sectors))
+ if(!(SSatlas.current_sector.name in am.valid_sectors))
+ log_ss("map_finalization", "[SSatlas.current_sector.name] is not a valid map for [am.name]")
continue
if(!am.validate_maps(folder))
diff --git a/code/controllers/subsystems/initialization/xenoarch.dm b/code/controllers/subsystems/initialization/xenoarch.dm
index ebbe07799bc..a62183ab5d7 100644
--- a/code/controllers/subsystems/initialization/xenoarch.dm
+++ b/code/controllers/subsystems/initialization/xenoarch.dm
@@ -21,8 +21,6 @@ var/datum/controller/subsystem/xenoarch/SSxenoarch
//create digsites
for(var/turf/simulated/mineral/M in turfs)
CHECK_TICK
- if(!M.geologic_data)
- M.geologic_data = new/datum/geosample(M)
if(!prob(XENOARCH_SPAWN_CHANCE))
continue
diff --git a/code/controllers/subsystems/job.dm b/code/controllers/subsystems/job.dm
index 970a3f99d59..6201eddf0fe 100644
--- a/code/controllers/subsystems/job.dm
+++ b/code/controllers/subsystems/job.dm
@@ -309,6 +309,11 @@
Debug("ER/([H]): Entry, joined_late=[joined_late],megavend=[megavend].")
+ if(SSatlas.current_sector.description)
+ var/sector_desc = "| # | SLIDE | SHOW | ||
|---|---|---|---|---|
| #[i] | " + if(I == current_slide) + table += "[I.name] | SHOWING | " + else + table += "[I.name] | SHOW | " + table += "