diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm
index d283656ccae6..e650ebacb8e3 100644
--- a/code/__DEFINES/shuttles.dm
+++ b/code/__DEFINES/shuttles.dm
@@ -115,6 +115,7 @@
#define ALMAYER_DROPSHIP_LZ1 "almayer-hangar-lz1"
#define ALMAYER_DROPSHIP_LZ2 "almayer-hangar-lz2"
+#define DROPSHIP_FLYBY_ID "special_flight"
#define DROPSHIP_LZ1 "dropship-lz1"
#define DROPSHIP_LZ2 "dropship-lz2"
diff --git a/code/datums/emergency_calls/cmb.dm b/code/datums/emergency_calls/cmb.dm
index 777ad322befc..a49c0a4ce273 100644
--- a/code/datums/emergency_calls/cmb.dm
+++ b/code/datums/emergency_calls/cmb.dm
@@ -100,6 +100,19 @@
to_chat(M, SPAN_BOLD("Corporate Officers chase after paychecks and promotions, but you are motivated to do your sworn duty and care for the population, no matter how far or isolated a colony may be."))
to_chat(M, SPAN_BOLD("Despite being stretched thin, the stalwart oath of the Marshals has continued to keep communities safe, with the CMB well respected by many. You are a representation of that oath, serve with distinction."))
+
+// A Nearby Colonial Marshal patrol team responding to Marshals in Distress.
+/datum/emergency_call/cmb/alt
+ name = "CMB - Patrol Team - Marshals in Distress (Friendly)"
+ mob_max = 5
+ mob_min = 1
+ probability = 0
+
+/datum/emergency_call/cmb/alt/New()
+ ..()
+ arrival_message = "CMB Team, this is Anchorpoint Station. We have confirmed you are in distress. Routing nearby units to assist!"
+ objectives = "Patrol Unit 5807, we have nearby Marshals in Distress! Locate and assist them immediately."
+
// Anchorpoint Station Colonial Marines, use this primarily for reinforcing or evacuating the CMB, as the CMB themselves are not equipped to handle heavy engagements.
/datum/emergency_call/cmb/anchorpoint
name = "CMB - Anchorpoint Station Colonial Marine QRF (Friendly)"
diff --git a/code/datums/emergency_calls/inspection.dm b/code/datums/emergency_calls/inspection.dm
index 4c33d7d9bfa3..ad0200339952 100644
--- a/code/datums/emergency_calls/inspection.dm
+++ b/code/datums/emergency_calls/inspection.dm
@@ -183,7 +183,7 @@
/datum/emergency_call/inspection_cmb/New()
..()
- arrival_message = "[MAIN_SHIP_NAME], This is Anchorpoint Station with the Colonial Marshal Bureau. Be advised, a CMB transport vessel is preparing to board you, submitting Federal docking clearances now. Standby."
+ arrival_message = "[MAIN_SHIP_NAME], this is Anchorpoint Station with the Colonial Marshal Bureau. Be advised, a CMB transport vessel is preparing to board you, submitting Federal docking clearances now. Standby."
objectives = "Get your instructions from the CMB Office at Anchorpoint Station, and carry out your orders. Ensure that Colonial assets are safe and in your custody. Do not enforce or override Marine Law on a Marine Ship unless requested, as it's outside of your juristiction."
will_spawn_icc_liaison = prob(90)
@@ -265,7 +265,7 @@
to_chat(M, SPAN_BOLD("Despite being stretched thin, the stalwart oath of the Marshals has continued to keep communities safe, with the CMB well respected by many. You are a representation of that oath, serve with distinction."))
/datum/emergency_call/inspection_cmb/black_market
- name = "Inspection - Colonial Marshal Ledger Investigation Team"
+ name = "Inspection - Colonial Marshals Ledger Investigation Team"
mob_max = 3 //Marshal, Deputy, ICC CL
mob_min = 2
shuttle_id = "Distress_PMC"
diff --git a/code/defines/procs/announcement.dm b/code/defines/procs/announcement.dm
index 5223d63b8e59..60bf117a6b92 100644
--- a/code/defines/procs/announcement.dm
+++ b/code/defines/procs/announcement.dm
@@ -125,7 +125,7 @@
//AI shipside announcement, that uses announcement mechanic instead of talking into comms
//to ensure that all humans on ship hear it regardless of comms and power
-/proc/shipwide_ai_announcement(message, title = MAIN_AI_SYSTEM, sound_to_play = sound('sound/misc/interference.ogg'), signature)
+/proc/shipwide_ai_announcement(message, title = MAIN_AI_SYSTEM, sound_to_play = sound('sound/misc/interference.ogg'), signature, ares_logging = ARES_LOG_MAIN)
var/list/targets = GLOB.human_mob_list + GLOB.dead_mob_list
for(var/mob/T in targets)
if(isobserver(T))
@@ -136,8 +136,12 @@
if(!isnull(signature))
message += "
Signed by,
[signature]"
var/datum/ares_link/link = GLOB.ares_link
- if(link.interface && !(link.interface.inoperable()))
- link.log_ares_announcement(title, message)
+ if(ares_can_log())
+ switch(ares_logging)
+ if(ARES_LOG_MAIN)
+ link.log_ares_announcement(title, message)
+ if(ARES_LOG_SECURITY)
+ link.log_ares_security(title, message)
announcement_helper(message, title, targets, sound_to_play)
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 826b2dc0585f..c81da5556e24 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -90,7 +90,7 @@
initialize_power()
/area/Initialize(mapload, ...)
- icon_state = "" //Used to reset the icon overlay, I assume.
+ icon = null
layer = AREAS_LAYER
uid = ++global_uid
. = ..()
diff --git a/code/game/objects/items/handheld_distress_beacon.dm b/code/game/objects/items/handheld_distress_beacon.dm
index d3f99134cd23..699c45c256b2 100644
--- a/code/game/objects/items/handheld_distress_beacon.dm
+++ b/code/game/objects/items/handheld_distress_beacon.dm
@@ -38,3 +38,44 @@
active = TRUE
update_icon()
+
+/// CMB distress beacon held by CMB Marshal for signalling distress to Anchorpoint Station
+/obj/item/handheld_distress_beacon_CMB
+ name = "\improper CMB handheld distress beacon"
+ desc = "An emergency beacon. This one is branded with a Colonial Marshal Bureau star and 'ANCHORPOINT STATION' is etched in stencil on the side. This device is issued to CMB Marshals and features an extended relay antenna."
+ icon = 'icons/obj/items/handheld_distress_beacon.dmi'
+ icon_state = "beacon_inactive"
+ w_class = SIZE_SMALL
+
+/// whether or not the beacon is turned on, when activated sends message to admins requesting Anchorpoint ERT and changes sprite
+ var/active = FALSE
+
+/obj/item/handheld_distress_beacon_CMB/get_examine_text(mob/user)
+ . = ..()
+
+ if(active)
+ . += "The beacon has been activated!"
+
+/obj/item/handheld_distress_beacon_CMB/update_icon()
+ . = ..()
+
+ if(active)
+ icon_state = "beacon_active"
+ else
+ icon_state = initial(icon_state)
+
+/obj/item/handheld_distress_beacon_CMB/attack_self(mob/user)
+ . = ..()
+
+ if(active)
+ to_chat(user, "[src] is already active!")
+ return
+
+ for(var/client/client in GLOB.admins)
+ if((R_ADMIN|R_MOD) & client.admin_holder.rights)
+ playsound_client(client,'sound/effects/sos-morse-code.ogg',10)
+ message_admins("[key_name(user)] has signalled CMB in distress, and requests reinforcements! [CC_MARK(user)] (SEND MARINE QRF) (SEND CMB TEAM) (DENY) [ADMIN_JMP_USER(user)] [CC_REPLY(user)]")
+ to_chat(user, SPAN_NOTICE("The CMB distress beacon flashes red, indicating that the device has been activated and is transmitting."))
+
+ active = TRUE
+ update_icon()
diff --git a/code/game/objects/structures/props.dm b/code/game/objects/structures/props.dm
index 9eea571961f7..bd5610487ea0 100644
--- a/code/game/objects/structures/props.dm
+++ b/code/game/objects/structures/props.dm
@@ -810,8 +810,10 @@
var/obj/item/stack/sheet/wood/fuel = attacking_item
if(remaining_fuel >= initial(remaining_fuel))
to_chat(user, SPAN_NOTICE("You cannot fuel [src] further."))
+ return
if(!fuel.use(1))
to_chat(SPAN_NOTICE("You do not have enough [attacking_item] to fuel [src]."))
+ return
visible_message(SPAN_NOTICE("[user] fuels [src] with [fuel]."))
remaining_fuel++
diff --git a/code/game/turfs/light.dm b/code/game/turfs/light.dm
index 219e79e93ef2..e8b7038bcb51 100644
--- a/code/game/turfs/light.dm
+++ b/code/game/turfs/light.dm
@@ -1,9 +1,21 @@
+#define LIGHT_FLOOR_COLOR_BLUE 0
+#define LIGHT_FLOOR_COLOR_RED 1
+#define LIGHT_FLOOR_COLOR_GREEN 2
+#define LIGHT_FLOOR_COLOR_YELLOW 3
+#define LIGHT_FLOOR_COLOR_PURPLE 4
+#define LIGHT_FLOOR_COLOR_WHITE 5
+
/turf/open/floor/light
name = "light floor"
desc = "Beware of breakdancing on these tiles, glass shards embedded in the head is not a fun time."
+ icon_state = "light_on"
tile_type = /obj/item/stack/tile/light
var/on = TRUE
- var/state = 0
+ var/state = LIGHT_FLOOR_COLOR_BLUE
+
+/turf/open/floor/light/get_examine_text(mob/user)
+ . = ..()
+ . += "[src] is [broken ? "broken, and requires a replacement lightbulb":"[on ? "on" : "off"]"]."
/turf/open/floor/light/is_light_floor()
return TRUE
@@ -12,22 +24,22 @@
. = ..()
if(on && !broken) //manages color, I feel like this switch is a sin.
switch(state)
- if(0)
+ if(LIGHT_FLOOR_COLOR_BLUE)
icon_state = "light_on"
set_light(5)
- if(1)
+ if(LIGHT_FLOOR_COLOR_RED)
icon_state = "light_on-r"
set_light(5)
- if(2)
+ if(LIGHT_FLOOR_COLOR_GREEN)
icon_state = "light_on-g"
set_light(5)
- if(3)
+ if(LIGHT_FLOOR_COLOR_YELLOW)
icon_state = "light_on-y"
set_light(5)
- if(4)
+ if(LIGHT_FLOOR_COLOR_PURPLE)
icon_state = "light_on-p"
set_light(5)
- if(5,-1)
+ if(LIGHT_FLOOR_COLOR_WHITE,-1) //change this later
icon_state = "light_on-w"
set_light(5)
state = -1
@@ -84,3 +96,68 @@
broken = TRUE
update_icon()
return XENO_ATTACK_ACTION
+
+/turf/open/floor/light/red
+ icon_state = "light_on-r"
+ state = LIGHT_FLOOR_COLOR_RED
+
+/turf/open/floor/light/green
+ icon_state = "light_on-g"
+ state = LIGHT_FLOOR_COLOR_GREEN
+
+/turf/open/floor/light/yellow
+ icon_state = "light_on-y"
+ state = LIGHT_FLOOR_COLOR_YELLOW
+
+/turf/open/floor/light/purple
+ icon_state = "light_on-p"
+ state = LIGHT_FLOOR_COLOR_PURPLE
+
+/turf/open/floor/light/white
+ icon_state = "light_on-w"
+ state = LIGHT_FLOOR_COLOR_WHITE
+
+/turf/open/floor/light/off
+ icon_state = "light_off"
+ on = FALSE
+
+/turf/open/floor/light/off/red
+ state = LIGHT_FLOOR_COLOR_RED
+
+/turf/open/floor/light/off/green
+ state = LIGHT_FLOOR_COLOR_GREEN
+
+/turf/open/floor/light/off/yellow
+ state = LIGHT_FLOOR_COLOR_YELLOW
+
+/turf/open/floor/light/off/purple
+ state = LIGHT_FLOOR_COLOR_PURPLE
+
+/turf/open/floor/light/off/white
+ state = LIGHT_FLOOR_COLOR_WHITE
+
+/turf/open/floor/light/broken
+ icon_state = "light_broken"
+ broken = TRUE
+
+/turf/open/floor/light/broken/red
+ state = LIGHT_FLOOR_COLOR_RED
+
+/turf/open/floor/light/broken/green
+ state = LIGHT_FLOOR_COLOR_GREEN
+
+/turf/open/floor/light/broken/yellow
+ state = LIGHT_FLOOR_COLOR_YELLOW
+
+/turf/open/floor/light/broken/purple
+ state = LIGHT_FLOOR_COLOR_PURPLE
+
+/turf/open/floor/light/broken/white
+ state = LIGHT_FLOOR_COLOR_WHITE
+
+#undef LIGHT_FLOOR_COLOR_BLUE
+#undef LIGHT_FLOOR_COLOR_RED
+#undef LIGHT_FLOOR_COLOR_GREEN
+#undef LIGHT_FLOOR_COLOR_YELLOW
+#undef LIGHT_FLOOR_COLOR_PURPLE
+#undef LIGHT_FLOOR_COLOR_WHITE
diff --git a/code/modules/admin/topic/topic.dm b/code/modules/admin/topic/topic.dm
index bb7755aa41b0..31f99870fe43 100644
--- a/code/modules/admin/topic/topic.dm
+++ b/code/modules/admin/topic/topic.dm
@@ -1243,7 +1243,7 @@
for(var/client/X in GLOB.admins)
if((R_ADMIN|R_MOD) & X.admin_holder.rights)
to_chat(X, SPAN_STAFF_IC("ADMINS/MODS: \red [src.owner] replied to [key_name(H)]'s USCM message with: \blue \")[input]\""))
- to_chat(H, SPAN_DANGER("You hear something crackle in your headset before a voice speaks, please stand by for a message from USCM:\" \blue \"[input]\""))
+ to_chat(H, SPAN_DANGER("You hear something crackle in your headset before a voice speaks, please stand by for a message:\" \blue \"[input]\""))
else if(href_list["SyndicateReply"])
var/mob/living/carbon/human/H = locate(href_list["SyndicateReply"])
@@ -1904,6 +1904,22 @@
addtimer(CALLBACK(src, PROC_REF(accept_ert), usr, locate(href_list["distress"])), 10 SECONDS)
//unanswered_distress -= ref_person
+ if(href_list["distress_cmb"]) //CMB distress signal, activates Anchorpoint Marine QRF to assist/rescue Colonial Marshals in distress
+ distress_cancel = FALSE
+ message_admins("[key_name_admin(usr)] has opted to SEND the Anchorpoint Station Colonial Marine QRF to assist the CMB! Launching in 10 seconds... (CANCEL)")
+ addtimer(CALLBACK(src, PROC_REF(accept_cmb_ert), usr, locate(href_list["distress"])), 10 SECONDS)
+
+ if(href_list["distress_cmb_alt"]) //CMB distress signal, activates a nearby CMB Patrol Team to assist/rescue Colonial Marshals in distress
+ distress_cancel = FALSE
+ message_admins("[key_name_admin(usr)] has opted to SEND a nearby CMB Patrol Team to assist the CMB! Launching in 10 seconds... (CANCEL)")
+ addtimer(CALLBACK(src, PROC_REF(accept_cmb_alt_ert), usr, locate(href_list["distress"])), 10 SECONDS)
+
+ if(href_list["deny_cmb"]) // Anchorpoint-deny. The distress call is denied, citing unavailable forces
+ var/mob/ref_person = locate(href_list["deny_cmb"])
+ to_chat(ref_person, "A voice barely crackles through the static: CMB Team, this is Anchorpoint Station. No can do, QRF currently dispatched elsewhere, relaying distress. Sorry. Good luck, out.")
+ log_game("[key_name_admin(usr)] has denied a distress beacon, requested by [key_name_admin(ref_person)]")
+ message_admins("[key_name_admin(usr)] has denied a distress beacon, requested by [key_name_admin(ref_person)]", 1)
+
if(href_list["distress_pmc"]) //Wey-Yu specific PMC distress signal for chem retrieval ERT
distress_cancel = FALSE
message_admins("[key_name_admin(usr)] has opted to SEND the distress beacon! Launching in 10 seconds... (CANCEL)")
@@ -2092,6 +2108,24 @@
log_game("[key_name_admin(approver)] has sent a randomized distress beacon, requested by [key_name_admin(ref_person)]")
message_admins("[key_name_admin(approver)] has sent a randomized distress beacon, requested by [key_name_admin(ref_person)]")
+/// tells admins which admin has sent the Anchorpoint ERT in response to CMB distress
+/datum/admins/proc/accept_cmb_ert(mob/approver, mob/ref_person)
+ if(distress_cancel)
+ return
+ distress_cancel = TRUE
+ SSticker.mode.get_specific_call("CMB - Anchorpoint Station Colonial Marine QRF (Friendly)", FALSE, FALSE)
+ log_game("[key_name_admin(approver)] has sent an Anchorpoint Station Colonial Marine QRF response, requested by [key_name_admin(ref_person)]")
+ message_admins("[key_name_admin(approver)] has sent an Anchorpoint Station Colonial Marine QRF response, requested by [key_name_admin(ref_person)]")
+
+/// tells admins which admin has sent the CMB ERT in response to CMB distress
+/datum/admins/proc/accept_cmb_alt_ert(mob/approver, mob/ref_person)
+ if(distress_cancel)
+ return
+ distress_cancel = TRUE
+ SSticker.mode.get_specific_call("CMB - Patrol Team - Marshals in Distress (Friendly)", FALSE, FALSE)
+ log_game("[key_name_admin(approver)] has sent a CMB Patrol Team distress response, requested by [key_name_admin(ref_person)]")
+ message_admins("[key_name_admin(approver)] has sent a CMB Patrol Team distress response, requested by [key_name_admin(ref_person)]")
+
/datum/admins/proc/accept_pmc_ert(mob/approver, mob/ref_person)
if(distress_cancel)
return
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 84a35163339b..554ba28e417f 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1696,6 +1696,9 @@ var/const/MAX_SAVE_SLOTS = 10
if("origin")
var/choice = tgui_input_list(user, "Please choose your character's origin.", "Origin Selection", GLOB.player_origins)
+ var/datum/origin/picked_choice = GLOB.origins[choice]
+ if(tgui_alert(user, "You've selected [picked_choice.name]. [picked_choice.desc]", "Selected Origin", list("Confirm", "Cancel")) == "Cancel")
+ return
if(choice)
origin = choice
diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm
index 779d8212f398..a6462b7a9214 100644
--- a/code/modules/clothing/glasses/glasses.dm
+++ b/code/modules/clothing/glasses/glasses.dm
@@ -142,7 +142,7 @@
/obj/item/clothing/glasses/science/prescription
name = "prescription reagent scanner HUD goggles"
- desc = "These goggles are probably of use to someone who isn't holding a rifle and actively seeking to lower their combat life expectancy. Contains prescription lenses."
+ desc = "These goggles are probably of use to someone who isn't holding a rifle and actively seeking to lower their combat life expectancy. Contains prescription lenses."
prescription = TRUE
/obj/item/clothing/glasses/science/get_examine_text(mob/user)
@@ -414,7 +414,7 @@
/obj/item/clothing/glasses/mgoggles/v2
name = "M1A1 marine ballistic goggles"
desc = "Newer issue USCM goggles. While commonly found mounted atop M10 pattern helmets, they are also capable of preventing insects, dust, and other things from getting into one's eyes. This version has larger lenses."
- icon_state = "mgoggles2_down"
+ icon_state = "mgoggles2"
active_icon_state = "mgoggles2_down"
inactive_icon_state = "mgoggles2"
diff --git a/code/modules/gear_presets/cmb.dm b/code/modules/gear_presets/cmb.dm
index 867669463569..3ce7a6ec281d 100644
--- a/code/modules/gear_presets/cmb.dm
+++ b/code/modules/gear_presets/cmb.dm
@@ -185,7 +185,7 @@
new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel/sec, WEAR_BACK)
new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/holdout, WEAR_IN_BACK)
new_human.equip_to_slot_or_del(new /obj/item/explosive/grenade/high_explosive/m15/rubber, WEAR_IN_BACK)
- new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/revolver/cmb, WEAR_IN_BACK)
+ new_human.equip_to_slot_or_del(new /obj/item/handheld_distress_beacon_CMB, WEAR_IN_BACK)
new_human.equip_to_slot_or_del(new /obj/item/device/radio, WEAR_IN_BACK)
new_human.equip_to_slot_or_del(new /obj/item/device/flashlight, WEAR_IN_BACK)
new_human.equip_to_slot_or_del(new /obj/item/device/camera, WEAR_IN_BACK)
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index 521045a56717..eafbb3c12c8a 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -23,8 +23,7 @@
/obj/item/paper_bin/MouseDrop(atom/over_object)
if(over_object == usr && ishuman(usr) && !usr.is_mob_restrained() && !usr.stat && (loc == usr || in_range(src, usr)))
if(!usr.get_active_hand()) //if active hand is empty
- attack_hand(usr, 1, 1)
-
+ usr.put_in_hands(src)
return
/obj/item/paper_bin/attack_hand(mob/user)
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index e004715f326a..dbd490792e8f 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -175,81 +175,110 @@
res.Scale(size*32, size*32)
// Initialize the photograph to black.
res.Blend("#000", ICON_OVERLAY)
+ CHECK_TICK
- var/atoms[] = list()
- for(var/turf/the_turf in turfs)
- // Add outselves to the list of stuff to draw
+ var/pixel_size = world.icon_size
+ var/radius = (size - 1) * 0.5
+ var/center_offset = radius * pixel_size + 1
+ var/x_min = center.x - radius
+ var/x_max = center.x + radius
+ var/y_min = center.y - radius
+ var/y_max = center.y + radius
+
+ var/list/atoms = list()
+ for(var/turf/the_turf as anything in turfs)
+ // Add ourselves to the list of stuff to draw
atoms.Add(the_turf);
+
// As well as anything that isn't invisible.
- for(var/atom/A in the_turf)
- if(A.invisibility) continue
- atoms.Add(A)
+ for(var/atom/cur_atom as anything in the_turf)
+ if(!cur_atom || cur_atom.invisibility)
+ continue
+ atoms.Add(cur_atom)
// Sort the atoms into their layers
var/list/sorted = sort_atoms_by_layer(atoms)
- var/center_offset = (size-1)/2 * 32 + 1
- for(var/i; i <= sorted.len; i++)
- var/atom/A = sorted[i]
- if(A)
- var/icon/IM = getFlatIcon(A)//build_composite_icon(A)
-
- // If what we got back is actually a picture, draw it.
- if(istype(IM, /icon))
- // Check if we're looking at a mob that's lying down
- if(istype(A, /mob/living))
- var/mob/living/L = A
- if(!istype(L, /mob/living/carbon/xenomorph)) //xenos don't use icon rotatin for lying.
- if(L.lying)
- // If they are, apply that effect to their picture.
- IM.BecomeLying()
- // Calculate where we are relative to the center of the photo
- var/xoff = (A.x - center.x) * 32 + center_offset
- var/yoff = (A.y - center.y) * 32 + center_offset
- if (istype(A,/atom/movable))
- xoff+=A:step_x
- yoff+=A:step_y
- res.Blend(IM, blendMode2iconMode(A.blend_mode), A.pixel_x + xoff, A.pixel_y + yoff)
+ for(var/atom/cur_atom as anything in sorted)
+ if(QDELETED(cur_atom))
+ continue
+
+ if(cur_atom.x < x_min || cur_atom.x > x_max || cur_atom.y < y_min || cur_atom.y > y_max)
+ // they managed to move out of frame with all this CHECK_TICK...
+ continue
+
+ var/icon/cur_icon = getFlatIcon(cur_atom)//build_composite_icon(cur_atom)
+
+ // If what we got back is actually a picture, draw it.
+ if(istype(cur_icon, /icon))
+ // Check if we're looking at a mob that's lying down
+ if(istype(cur_atom, /mob/living))
+ var/mob/living/cur_mob = cur_atom
+ if(!isxeno(cur_mob) && cur_mob.lying) //xenos don't use icon rotatin for lying.
+ cur_icon.BecomeLying()
+
+ // Calculate where we are relative to the center of the photo
+ var/xoff = (cur_atom.x - center.x) * pixel_size + center_offset
+ var/yoff = (cur_atom.y - center.y) * pixel_size + center_offset
+ if(istype(cur_atom, /atom/movable))
+ xoff += cur_atom:step_x
+ yoff += cur_atom:step_y
+ res.Blend(cur_icon, blendMode2iconMode(cur_atom.blend_mode), cur_atom.pixel_x + xoff, cur_atom.pixel_y + yoff)
+
+ CHECK_TICK
// Lastly, render any contained effects on top.
for(var/turf/the_turf as anything in turfs)
// Calculate where we are relative to the center of the photo
- var/xoff = (the_turf.x - center.x) * 32 + center_offset
- var/yoff = (the_turf.y - center.y) * 32 + center_offset
- var/image/IM = getFlatIcon(the_turf.loc)
- if(IM)
- res.Blend(IM, blendMode2iconMode(the_turf.blend_mode),xoff,yoff)
+ var/xoff = (the_turf.x - center.x) * pixel_size + center_offset
+ var/yoff = (the_turf.y - center.y) * pixel_size + center_offset
+ var/image/cur_icon = getFlatIcon(the_turf.loc)
+ CHECK_TICK
+
+ if(cur_icon)
+ res.Blend(cur_icon, blendMode2iconMode(the_turf.blend_mode), xoff, yoff)
+ CHECK_TICK
return res
+/obj/item/device/camera/proc/get_mob_descriptions(turf/the_turf, existing_descripion)
+ var/mob_detail = existing_descripion
+ for(var/mob/living/carbon/cur_carbon in the_turf)
+ if(cur_carbon.invisibility)
+ continue
-/obj/item/device/camera/proc/get_mobs(turf/the_turf as turf)
- var/mob_detail
- for(var/mob/living/carbon/A in the_turf)
- if(A.invisibility) continue
var/holding = null
- if(A.l_hand || A.r_hand)
- if(A.l_hand) holding = "They are holding \a [A.l_hand]"
- if(A.r_hand)
+ if(cur_carbon.l_hand || cur_carbon.r_hand)
+ if(cur_carbon.l_hand)
+ holding = "They are holding \a [cur_carbon.l_hand]"
+ if(cur_carbon.r_hand)
if(holding)
- holding += " and \a [A.r_hand]"
+ holding += " and \a [cur_carbon.r_hand]"
else
- holding = "They are holding \a [A.r_hand]"
+ holding = "They are holding \a [cur_carbon.r_hand]"
+
+ var/hurt = ""
+ if(cur_carbon.health < 75)
+ hurt = prob(25) ? " - they look hurt" : " - [cur_carbon] looks hurt"
if(!mob_detail)
- mob_detail = "You can see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]. "
+ mob_detail = "You can see [cur_carbon] in the photo[hurt].[holding ? " [holding]" : "."]."
else
- mob_detail += "You can also see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]."
+ mob_detail += " You [prob(50) ? "can" : "also"] see [cur_carbon] in the photo[hurt].[holding ? " [holding]" : "."]."
return mob_detail
/obj/item/device/camera/afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag)
- if(!on || !pictures_left || ismob(target.loc) || isstorage(target.loc)) return
- if(user.contains(target) || istype(target, /atom/movable/screen)) return
- captureimage(target, user, flag)
+ if(!on || !pictures_left || ismob(target.loc) || isstorage(target.loc))
+ return
+ if(user.contains(target) || istype(target, /atom/movable/screen))
+ return
playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 15, 1)
pictures_left--
desc = "A polaroid camera. It has [pictures_left] photos left."
to_chat(user, SPAN_NOTICE("[pictures_left] photos left."))
+
+ captureimage(target, user, flag)
+
icon_state = icon_off
on = 0
spawn(64)
@@ -257,37 +286,46 @@
on = 1
/obj/item/device/camera/proc/captureimage(atom/target, mob/user, flag)
- var/mobs = ""
+ var/mob_descriptions = ""
var/radius = (size-1)*0.5
var/list/turf/turfs = RANGE_TURFS(radius, target) & view(world_view_size + radius, user.client)
- for(var/turf/T as anything in turfs)
- mobs += get_mobs(T)
- var/datum/picture/P = createpicture(target, user, turfs, mobs, flag)
- printpicture(user, P)
+ for(var/turf/the_turf as anything in turfs)
+ mob_descriptions = get_mob_descriptions(the_turf, mob_descriptions)
+ var/datum/picture/the_picture = createpicture(target, user, turfs, mob_descriptions, flag)
-/obj/item/device/camera/proc/createpicture(atom/target, mob/user, list/turfs, mobs, flag)
+ if(QDELETED(user))
+ return
+
+ printpicture(user, the_picture)
+
+/obj/item/device/camera/proc/createpicture(atom/target, mob/user, list/turfs, description, flag)
var/icon/photoimage = get_icon(turfs, target)
+ if(!description)
+ description = "A very scenic photo"
+
var/icon/small_img = icon(photoimage)
var/icon/tiny_img = icon(photoimage)
- var/icon/ic = icon('icons/obj/items/items.dmi',"photo")
- var/icon/pc = icon('icons/obj/items/paper.dmi', "photo")
+ var/icon/item_icon = icon('icons/obj/items/items.dmi',"photo")
+ var/icon/paper_icon = icon('icons/obj/items/paper.dmi', "photo")
small_img.Scale(8, 8)
tiny_img.Scale(4, 4)
- ic.Blend(small_img,ICON_OVERLAY, 10, 13)
- pc.Blend(tiny_img,ICON_OVERLAY, 12, 19)
-
- var/datum/picture/P = new()
- P.fields["author"] = user
- P.fields["icon"] = ic
- P.fields["tiny"] = pc
- P.fields["img"] = photoimage
- P.fields["desc"] = mobs
- P.fields["pixel_x"] = rand(-10, 10)
- P.fields["pixel_y"] = rand(-10, 10)
- P.fields["size"] = size
-
- return P
+ item_icon.Blend(small_img, ICON_OVERLAY, 10, 13)
+ CHECK_TICK
+ paper_icon.Blend(tiny_img, ICON_OVERLAY, 12, 19)
+ CHECK_TICK
+
+ var/datum/picture/the_picture = new()
+ the_picture.fields["author"] = user
+ the_picture.fields["icon"] = item_icon
+ the_picture.fields["tiny"] = paper_icon
+ the_picture.fields["img"] = photoimage
+ the_picture.fields["desc"] = description
+ the_picture.fields["pixel_x"] = rand(-10, 10)
+ the_picture.fields["pixel_y"] = rand(-10, 10)
+ the_picture.fields["size"] = size
+
+ return the_picture
/obj/item/device/camera/proc/printpicture(mob/user, datum/picture/P)
var/obj/item/photo/Photo = new/obj/item/photo()
diff --git a/code/modules/projectiles/guns/shotguns.dm b/code/modules/projectiles/guns/shotguns.dm
index edecce85ccb4..c3b4906c1b29 100644
--- a/code/modules/projectiles/guns/shotguns.dm
+++ b/code/modules/projectiles/guns/shotguns.dm
@@ -1278,7 +1278,7 @@ can cause issues with ammo types getting mixed up during the burst.
/obj/item/weapon/gun/shotgun/pump/dual_tube/cmb/m3717
name = "\improper M37-17 pump shotgun"
- desc = "A military version of the iconic HG 37-12, this design can fit one extra shell in each of its dual-tube internal magazines, and fires shells with increased velocity, resulting in more damage. Issued to select USCM vessels out on the rim. You can switch the active internal magazine by toggling the shotgun tube."
+ desc = "A military version of the iconic HG 37-12, this design can fit one extra shell in each of its dual-tube internal magazines, and fires shells with increased velocity, resulting in more damage. Issued to select USCM vessels and stations in the outer veil. A button on the side toggles the internal tubes."
icon = 'icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi'
icon_state = "m3717"
item_state = "m3717"
diff --git a/code/modules/shuttle/computers/dropship_computer.dm b/code/modules/shuttle/computers/dropship_computer.dm
index c7a79b9c44ca..15b6a6ca6e87 100644
--- a/code/modules/shuttle/computers/dropship_computer.dm
+++ b/code/modules/shuttle/computers/dropship_computer.dm
@@ -179,6 +179,9 @@
return
to_chat(xeno, SPAN_NOTICE("You command the metal bird to come down. Clever girl."))
xeno_announcement(SPAN_XENOANNOUNCE("Your Queen has commanded the metal bird to the hive at [linked_lz]."), xeno.hivenumber, XENO_GENERAL_ANNOUNCE)
+ var/datum/ares_link/link = GLOB.ares_link
+ link.log_ares_flight("Unknown", "Remote launch signal for [shuttle.name] received. Authentication garbled.")
+ link.log_ares_security("Security Alert", "Remote launch signal for [shuttle.name] received. Authentication garbled.")
return
if(shuttle.destination.id != linked_lz)
to_chat(xeno, "The shuttle not ready. The screen reads T-[shuttle.timeLeft(10)]. Have patience.")
@@ -317,13 +320,22 @@
.["primary_lz"] = SSticker.mode.active_lz?.linked_lz
if(shuttle.destination)
.["target_destination"] = shuttle.in_flyby? "Flyby" : shuttle.destination.name
- .["destinations"] = list()
.["door_status"] = is_remote ? list() : shuttle.get_door_data()
-
.["flight_configuration"] = is_set_flyby ? "flyby" : "ferry"
.["has_flyby_skill"] = skillcheck(user, SKILL_PILOT, SKILL_PILOT_EXPERT)
+ .["destinations"] = list()
+ // add flight
+ .["destinations"] += list(
+ list(
+ "id" = DROPSHIP_FLYBY_ID,
+ "name" = "Flyby",
+ "available" = TRUE,
+ "error" = FALSE
+ )
+ )
+
for(var/obj/docking_port/stationary/dock in compatible_landing_zones)
var/dock_reserved = FALSE
for(var/obj/docking_port/mobile/other_shuttle in SSshuttle.mobile)
@@ -359,15 +371,16 @@
to_chat(usr, SPAN_WARNING("You can't move to a new destination right now."))
return TRUE
- if(is_set_flyby && !skillcheck(user, SKILL_PILOT, SKILL_PILOT_EXPERT))
- to_chat(user, SPAN_WARNING("You don't have the skill to perform a flyby."))
- return FALSE
var/is_optimised = FALSE
// automatically apply optimisation if user is a pilot
if(skillcheck(user, SKILL_PILOT, SKILL_PILOT_EXPERT))
is_optimised = TRUE
update_equipment(is_optimised)
- if(is_set_flyby)
+ var/dock_id = params["target"]
+ if(dock_id == DROPSHIP_FLYBY_ID)
+ if(!skillcheck(user, SKILL_PILOT, SKILL_PILOT_EXPERT))
+ to_chat(user, SPAN_WARNING("You don't have the skill to perform a flyby."))
+ return FALSE
to_chat(user, SPAN_NOTICE("You begin the launch sequence for a flyby."))
link.log_ares_flight(user.name, "Launched Dropship [shuttle.name] on a flyby.")
var/log = "[key_name(user)] launched the dropship [src.shuttleId] on flyby."
@@ -375,19 +388,19 @@
log_interact(user, msg = "[log]")
shuttle.send_for_flyby()
return TRUE
- var/dockId = params["target"]
+
var/list/local_data = ui_data(user)
var/found = FALSE
playsound(loc, get_sfx("terminal_button"), KEYBOARD_SOUND_VOLUME, 1)
for(var/destination in local_data["destinations"])
- if(destination["id"] == dockId)
+ if(destination["id"] == dock_id)
found = TRUE
break
if(!found)
- log_admin("[key_name(user)] may be attempting a href dock exploit on [src] with target location \"[dockId]\"")
- to_chat(user, SPAN_WARNING("The [dockId] dock is not available at this time."))
+ log_admin("[key_name(user)] may be attempting a href dock exploit on [src] with target location \"[dock_id]\"")
+ to_chat(user, SPAN_WARNING("The [dock_id] dock is not available at this time."))
return
- var/obj/docking_port/stationary/dock = SSshuttle.getDock(dockId)
+ var/obj/docking_port/stationary/dock = SSshuttle.getDock(dock_id)
var/dock_reserved = FALSE
for(var/obj/docking_port/mobile/other_shuttle in SSshuttle.mobile)
if(dock == other_shuttle.destination)
diff --git a/code/modules/shuttle/shuttles/dropship.dm b/code/modules/shuttle/shuttles/dropship.dm
index d81484b0343d..e1c2bb9a1f9a 100644
--- a/code/modules/shuttle/shuttles/dropship.dm
+++ b/code/modules/shuttle/shuttles/dropship.dm
@@ -100,7 +100,7 @@
var/name = "Unidentified Lifesigns"
var/input = "Unidentified lifesigns detected onboard. Recommendation: lockdown of exterior access ports, including ducting and ventilation."
- shipwide_ai_announcement(input, name, 'sound/AI/unidentified_lifesigns.ogg')
+ shipwide_ai_announcement(input, name, 'sound/AI/unidentified_lifesigns.ogg', ares_logging = ARES_LOG_SECURITY)
set_security_level(SEC_LEVEL_RED)
return
diff --git a/code/modules/shuttles/marine_ferry.dm b/code/modules/shuttles/marine_ferry.dm
index 426d90c1457a..7ec4b2eb7333 100644
--- a/code/modules/shuttles/marine_ferry.dm
+++ b/code/modules/shuttles/marine_ferry.dm
@@ -230,7 +230,7 @@
if(X && X.stat != DEAD)
var/name = "Unidentified Lifesigns"
var/input = "Unidentified lifesigns detected onboard. Recommendation: lockdown of exterior access ports, including ducting and ventilation."
- shipwide_ai_announcement(input, name, 'sound/AI/unidentified_lifesigns.ogg')
+ shipwide_ai_announcement(input, name, 'sound/AI/unidentified_lifesigns.ogg', ares_logging = ARES_LOG_SECURITY)
set_security_level(SEC_LEVEL_RED)
break
diff --git a/html/changelogs/AutoChangeLog-pr-4598.yml b/html/changelogs/AutoChangeLog-pr-4598.yml
deleted file mode 100644
index 4d7973cbf282..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4598.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "CapCamIII"
-delete-after: True
-changes:
- - rscdel: "XO can no longer take a sword as their personal weapon in their vendor."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4601.yml b/html/changelogs/AutoChangeLog-pr-4601.yml
deleted file mode 100644
index 4f4c63c8d6ed..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4601.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "BeagleGaming1"
-delete-after: True
-changes:
- - code_imp: "prop guns will copy attachments"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4636.yml b/html/changelogs/AutoChangeLog-pr-4636.yml
new file mode 100644
index 000000000000..2f26402bc864
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4636.yml
@@ -0,0 +1,4 @@
+author: "Drathek"
+delete-after: True
+changes:
+ - refactor: "Refactored camera code to be less blocking, use typechecks less often, and provide somewhat more fluid descriptions to photos."
\ No newline at end of file
diff --git a/html/changelogs/archive/2023-10.yml b/html/changelogs/archive/2023-10.yml
index 5e0d2a5e5068..a511276351e7 100644
--- a/html/changelogs/archive/2023-10.yml
+++ b/html/changelogs/archive/2023-10.yml
@@ -118,3 +118,38 @@
- rscadd: tactical shotguns now come standard with their stock. Yes you can remove
it if you dont want it
- rscadd: new tactical shotgun stock sprite done by esselnek
+2023-10-10:
+ BeagleGaming1:
+ - code_imp: prop guns will copy attachments
+ CapCamIII:
+ - rscdel: XO can no longer take a sword as their personal weapon in their vendor.
+ realforest2001:
+ - rscadd: Added missing flight record for Queen dropship summon.
+ - code_imp: Added security record option for shipwide_ai_announcement.
+ - rscadd: Added security records for unidentified lifeforms announcement.
+2023-10-11:
+ BeagleGaming1:
+ - rscadd: Light floor can be examined to tell if it is on, off, or broken.
+ - code_imp: Light floor subtypes for easier mapping
+ Birdtalon:
+ - bugfix: You can now pick up paper bins
+ - bugfix: Campfires stop consuming wood when full
+ Zonespace27:
+ - rscdel: Predators can no longer see their or others cross-round honor count.
+ irRegularGuy646:
+ - bugfix: fixed new goggle's on helmet sprite
+2023-10-12:
+ QuickLode:
+ - rscadd: Adds a handheld distress beacon for the Colonial Marshal. They can use
+ this to signal distress which in turn allows reinforcements in the form of Anchorpoint
+ Marine QRF or nearby CMB teams. Admins do the final check.
+ - rscadd: Adds a CMB Patrol Team which responds to "Marshals in Distress" call.
+ - admin: headset admin response no longer specifies USCM origin(as this is used
+ for USCM, WY, and now CMB)
+ - spellcheck: fixes a CMB typo in response message. Also a miniscule change to HG
+ 37-12 desc.
+ - spellcheck: fixes 2 misc typos in CMB Inspections
+ harryob:
+ - rscadd: origin descriptions are now displayed when selecting an origin
+ mullenpaul:
+ - ui: tweaked flyby controls to make them in line with other destinations
diff --git a/icons/mob/humans/onmob/eyes.dmi b/icons/mob/humans/onmob/eyes.dmi
index bda5bec0f0d7..c4d743f61e38 100644
Binary files a/icons/mob/humans/onmob/eyes.dmi and b/icons/mob/humans/onmob/eyes.dmi differ
diff --git a/icons/mob/humans/onmob/helmet_garb.dmi b/icons/mob/humans/onmob/helmet_garb.dmi
index 9e4cbf462982..cc91c47fe2fc 100644
Binary files a/icons/mob/humans/onmob/helmet_garb.dmi and b/icons/mob/humans/onmob/helmet_garb.dmi differ
diff --git a/icons/mob/humans/onmob/mask.dmi b/icons/mob/humans/onmob/mask.dmi
index 6f7e99813986..896da0201bd2 100644
Binary files a/icons/mob/humans/onmob/mask.dmi and b/icons/mob/humans/onmob/mask.dmi differ
diff --git a/nano/templates/clan_menu.tmpl b/nano/templates/clan_menu.tmpl
index 98ac3057a10a..cd987e9079f6 100644
--- a/nano/templates/clan_menu.tmpl
+++ b/nano/templates/clan_menu.tmpl
@@ -46,7 +46,7 @@
}
#clan_list {
- border-collapse: collapse;
+ border-collapse: collapse;
width: 100%;
}
@@ -76,9 +76,6 @@
{{:data.clan_description}}- {{if data.clan_honor != null}} -
Name | Rank | -Honor | {{if data.player_modify_ranks}}{{/if}} @@ -128,7 +124,6 @@ | {{:keys.name}} | {{:keys.rank}} | -{{:keys.honor}} | {{if data.player_rank_pos > keys.rank_pos}} {{if data.player_modify_ranks}}{{:helper.link('Set Rank', '', { 'clan_target_href' : keys.player_id, 'clan_action': 'modifyrank' })}} |
@@ -142,4 +137,4 @@
{{/if}}
---|