diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 30e5a3b946d..88116a4801c 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -37402,6 +37402,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 2
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/storage/primary)
"bxt" = (
@@ -41693,7 +41696,7 @@
/obj/structure/cable/white{
icon_state = "1-2"
},
-/obj/item/clothing/head/det_hat{
+/obj/item/clothing/head/fedora/det_hat{
icon_state = "curator"
},
/obj/item/clothing/suit/det_suit{
@@ -46248,6 +46251,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 2
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/storage/primary)
"bOh" = (
@@ -46259,6 +46265,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 2
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/storage/primary)
"bOi" = (
@@ -59878,6 +59887,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 4
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
/turf/open/floor/plating,
/area/maintenance/starboard)
"coE" = (
@@ -61484,12 +61496,7 @@
/turf/open/floor/plasteel/black,
/area/library)
"crP" = (
-/obj/structure/closet/crate,
-/obj/item/clothing/shoes/workboots/mining,
-/obj/item/clothing/under/rank/curator/treasure_hunter,
-/obj/item/clothing/suit/curator,
-/obj/item/clothing/head/curator,
-/obj/item/weapon/storage/backpack/satchel/explorer,
+/obj/structure/closet/wardrobe/curator,
/turf/open/floor/plasteel/black,
/area/library)
"crQ" = (
@@ -65483,6 +65490,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/library)
"czM" = (
@@ -67968,6 +67978,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
"cEI" = (
@@ -70199,6 +70212,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
"cIY" = (
@@ -79073,6 +79089,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/science/research)
"dbt" = (
@@ -79708,6 +79727,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/science/research)
"dcQ" = (
@@ -80455,6 +80477,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/science/research)
"deC" = (
@@ -82304,6 +82329,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 2
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/hallway/secondary/construction)
"diw" = (
@@ -82311,6 +82339,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 2
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/hallway/secondary/construction)
"dix" = (
@@ -82318,6 +82349,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 2
},
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
/turf/open/floor/plasteel,
/area/hallway/secondary/construction)
"diy" = (
@@ -139991,7 +140025,7 @@ akm
ajl
bKc
aip
-aol
+eph
bQf
bSn
bUr
@@ -140429,14 +140463,14 @@ aaf
aaf
aaf
aax
-ach
+epb
aax
aaf
aaa
aaa
aaf
aax
-ach
+epb
aax
aaf
aaf
@@ -140943,14 +140977,14 @@ aax
aaD
abT
aax
-acj
+epc
aax
acC
acT
ack
adq
aax
-ach
+epb
aax
abR
aaD
@@ -143268,9 +143302,9 @@ edp
edp
edp
een
-epf
+epc
aci
-epg
+epc
agl
agN
ahu
@@ -144291,7 +144325,7 @@ aaf
aaf
aaf
aax
-epd
+epc
aax
aaf
aaf
@@ -144805,7 +144839,7 @@ acV
adg
adr
aax
-epe
+epb
aax
abT
aaD
@@ -167002,10 +167036,10 @@ cqf
cqf
cqf
cqf
-cEE
+epj
cqf
cqf
-cIU
+epk
cqf
cqf
cqf
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 10944caebc8..dbb0d800bdb 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -50365,12 +50365,7 @@
/obj/machinery/computer/security/telescreen/entertainment{
pixel_x = 30
},
-/obj/structure/closet/crate,
-/obj/item/clothing/shoes/workboots/mining,
-/obj/item/clothing/under/rank/curator/treasure_hunter,
-/obj/item/clothing/suit/curator,
-/obj/item/clothing/head/curator,
-/obj/item/weapon/storage/backpack/satchel/explorer,
+/obj/structure/closet/wardrobe/curator,
/turf/open/floor/engine/cult,
/area/library)
"bPY" = (
diff --git a/_maps/map_files/TgStation/tgstation.2.1.3.dmm b/_maps/map_files/TgStation/tgstation.2.1.3.dmm
index 95b54cab7f6..f9643c4d42b 100644
--- a/_maps/map_files/TgStation/tgstation.2.1.3.dmm
+++ b/_maps/map_files/TgStation/tgstation.2.1.3.dmm
@@ -19077,12 +19077,7 @@
/turf/open/floor/wood,
/area/library)
"aQr" = (
-/obj/structure/closet/crate,
-/obj/item/clothing/shoes/workboots/mining,
-/obj/item/clothing/under/rank/curator/treasure_hunter,
-/obj/item/clothing/suit/curator,
-/obj/item/clothing/head/curator,
-/obj/item/weapon/storage/backpack/satchel/explorer,
+/obj/structure/closet/wardrobe/curator,
/obj/machinery/light/small,
/turf/open/floor/engine/cult,
/area/library)
diff --git a/code/__DEFINES/clockcult.dm b/code/__DEFINES/clockcult.dm
index 0bcf75c6ab7..c74bf9c61e9 100644
--- a/code/__DEFINES/clockcult.dm
+++ b/code/__DEFINES/clockcult.dm
@@ -19,10 +19,10 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
#define SCRIPTURE_PERIPHERAL "Peripheral"
#define SCRIPTURE_DRIVER "Driver"
#define SCRIPTURE_SCRIPT "Script"
-#define SCRIPT_SERVANT_REQ 5
+#define SCRIPT_SERVANT_REQ 6
#define SCRIPT_CACHE_REQ 1
#define SCRIPTURE_APPLICATION "Application"
-#define APPLICATION_SERVANT_REQ 8
+#define APPLICATION_SERVANT_REQ 9
#define APPLICATION_CACHE_REQ 3
#define APPLICATION_CV_REQ 100
#define SCRIPTURE_JUDGEMENT "Judgement"
@@ -94,3 +94,5 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
#define OCULAR_WARDEN_EXCLUSION_RANGE 3 //the range at which ocular wardens cannot be placed near other ocular wardens
#define RATVARIAN_SPEAR_DURATION 1800 //how long ratvarian spears last; defaults to 3 minutes
+
+#define PRISM_DELAY_DURATION 1200 //how long prolonging prisms delay the shuttle for; defaults to 2 minutes
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index e5d1f4c19e1..670a1778fb1 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -2,6 +2,11 @@
//Misc mob defines
+//Ready states at roundstart for mob/dead/new_player
+#define PLAYER_NOT_READY 0
+#define PLAYER_READY_TO_PLAY 1
+#define PLAYER_READY_TO_OBSERVE 2
+
//movement intent defines for the m_intent var
#define MOVE_INTENT_WALK "walk"
#define MOVE_INTENT_RUN "run"
@@ -128,4 +133,4 @@
#define INCORPOREAL_MOVE_BASIC 1
#define INCORPOREAL_MOVE_SHADOW 2 // leaves a trail of shadows
-#define INCORPOREAL_MOVE_JAUNT 3 // is blocked by holy water/salt
\ No newline at end of file
+#define INCORPOREAL_MOVE_JAUNT 3 // is blocked by holy water/salt
diff --git a/code/_globalvars/game_modes.dm b/code/_globalvars/game_modes.dm
index 38a415585fc..9c3af923f18 100644
--- a/code/_globalvars/game_modes.dm
+++ b/code/_globalvars/game_modes.dm
@@ -14,4 +14,5 @@ GLOBAL_VAR_INIT(cult_vote_called, FALSE)
GLOBAL_VAR_INIT(cult_mastered, FALSE)
GLOBAL_VAR_INIT(reckoning_complete, FALSE)
GLOBAL_VAR_INIT(sac_complete, FALSE)
-GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
\ No newline at end of file
+GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
+GLOBAL_LIST_EMPTY(summon_spots)
\ No newline at end of file
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 9a22b7c30a1..f257af11dec 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -306,7 +306,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
angle = 0
cut_overlays()
icon_state = "runed_sense1"
- desc = "The sacrifice is complete, bring the wrath of Nar-Sie upon the crew!"
+ desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(GLOB.summon_spots)]!"
add_overlay(narnar)
return
var/turf/P = get_turf(blood_target)
diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm
index 9a4f3bdb6fd..e819060afbc 100644
--- a/code/controllers/subsystem/atoms.dm
+++ b/code/controllers/subsystem/atoms.dm
@@ -98,7 +98,7 @@ SUBSYSTEM_DEF(atoms)
else if(!A.initialized)
BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT
- return qdeleted || QDELETED(A)
+ return qdeleted || QDELING(A)
/datum/controller/subsystem/atoms/proc/map_loader_begin()
old_initialized = initialized
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 05d8dbb5b7e..731166e0a9f 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -224,7 +224,7 @@ SUBSYSTEM_DEF(job)
//Get the players who are ready
for(var/mob/dead/new_player/player in GLOB.player_list)
- if(player.ready && player.mind && !player.mind.assigned_role)
+ if(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role)
unassigned += player
initial_players_to_assign = unassigned.len
@@ -456,7 +456,7 @@ SUBSYSTEM_DEF(job)
var/level5 = 0 //banned
var/level6 = 0 //account too young
for(var/mob/dead/new_player/player in GLOB.player_list)
- if(!(player.ready && player.mind && !player.mind.assigned_role))
+ if(!(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role))
continue //This player is not ready
if(jobban_isbanned(player, job.title))
level5++
@@ -489,7 +489,7 @@ SUBSYSTEM_DEF(job)
Debug("Popcap overflow Check observer located, Player: [player]")
to_chat(player, "You have failed to qualify for any job you desired.")
unassigned -= player
- player.ready = 0
+ player.ready = PLAYER_NOT_READY
/datum/controller/subsystem/job/Recover()
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 2d0bcf907cd..2a1f54e1712 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -83,6 +83,8 @@ SUBSYSTEM_DEF(ticker)
window_flash(C, ignorepref = TRUE) //let them know lobby has opened up.
to_chat(world, "Welcome to [station_name()]!")
current_state = GAME_STATE_PREGAME
+ //Everyone who wants to be an observer is now spawned
+ create_observers()
fire()
if(GAME_STATE_PREGAME)
//lobby stats for statpanels
@@ -92,7 +94,7 @@ SUBSYSTEM_DEF(ticker)
totalPlayersReady = 0
for(var/mob/dead/new_player/player in GLOB.player_list)
++totalPlayers
- if(player.ready)
+ if(player.ready == PLAYER_READY_TO_PLAY)
++totalPlayersReady
if(start_immediately)
@@ -131,6 +133,7 @@ SUBSYSTEM_DEF(ticker)
declare_completion(force_ending)
Master.SetRunLevel(RUNLEVEL_POSTGAME)
+
/datum/controller/subsystem/ticker/proc/setup()
to_chat(world, "Starting game...")
var/init_start = world.timeofday
@@ -233,6 +236,8 @@ SUBSYSTEM_DEF(ticker)
/datum/controller/subsystem/ticker/proc/PostSetup()
set waitfor = 0
mode.post_setup()
+ GLOB.start_state = new /datum/station_state()
+ GLOB.start_state.count(1)
//Cleanup some stuff
for(var/obj/effect/landmark/start/S in GLOB.landmarks_list)
//Deleting Startpoints but we need the ai point to AI-ize people later
@@ -400,7 +405,7 @@ SUBSYSTEM_DEF(ticker)
/datum/controller/subsystem/ticker/proc/create_characters()
for(var/mob/dead/new_player/player in GLOB.player_list)
- if(player.ready && player.mind)
+ if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
GLOB.joined_player_list += player.ckey
player.create_character(FALSE)
else
@@ -791,6 +796,13 @@ SUBSYSTEM_DEF(ticker)
else
timeLeft = newtime
+//Everyone who wanted to be an observer gets made one now
+/datum/controller/subsystem/ticker/proc/create_observers()
+ for(var/mob/dead/new_player/player in GLOB.player_list)
+ if(player.ready == PLAYER_READY_TO_OBSERVE && player.mind)
+ //Break chain since this has a sleep input in it
+ addtimer(CALLBACK(player, /mob/dead/new_player.proc/make_me_an_observer), 1)
+
/datum/controller/subsystem/ticker/proc/load_mode()
var/mode = trim(file2text("data/mode.txt"))
if(mode)
diff --git a/code/datums/antagonists/datum_cult.dm b/code/datums/antagonists/datum_cult.dm
index 813fc343ee0..7f1c3c5817c 100644
--- a/code/datums/antagonists/datum_cult.dm
+++ b/code/datums/antagonists/datum_cult.dm
@@ -1,3 +1,5 @@
+#define SUMMON_POSSIBILITIES 3
+
/datum/antagonist/cult
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
@@ -35,7 +37,14 @@
message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
GLOB.sac_complete = TRUE
SSticker.mode.cult_objectives += "sacrifice"
- SSticker.mode.cult_objectives += "eldergod"
+ if(GLOB.summon_spots.len)
+ SSticker.mode.cult_objectives += "eldergod"
+ else
+ while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
+ var/area/summon = pick(GLOB.sortedAreas)
+ if(summon && (summon.z == ZLEVEL_STATION) && summon.valid_territory)
+ GLOB.summon_spots |= summon
+ SSticker.mode.cult_objectives += "eldergod"
/datum/antagonist/cult/proc/cult_memorization(datum/mind/cult_mind)
var/mob/living/current = cult_mind.current
@@ -48,7 +57,7 @@
else
explanation = "The veil has already been weakened here, proceed to the final objective."
if("eldergod")
- explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie' with nine acolytes on it. You must do this after sacrificing your target."
+ explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'. The summoning can only be accomplished in [english_list(GLOB.summon_spots)] - where the veil is weak enough for the ritual to begin."
if(!silent)
to_chat(current, "Objective #[obj_count]: [explanation]")
cult_mind.memory += "Objective #[obj_count]: [explanation]
"
diff --git a/code/datums/antagonists/datum_traitor.dm b/code/datums/antagonists/datum_traitor.dm
index a57c2087e30..514d2619ead 100644
--- a/code/datums/antagonists/datum_traitor.dm
+++ b/code/datums/antagonists/datum_traitor.dm
@@ -243,11 +243,15 @@
/datum/antagonist/traitor/proc/finalize_traitor()
SSticker.mode.update_traitor_icons_added(owner)
return
+
/datum/antagonist/traitor/AI/finalize_traitor()
+ ..()
add_law_zero()
owner.current.playsound_local('sound/ambience/antag/Malf.ogg',100,0)
owner.current.grant_language(/datum/language/codespeak)
+
/datum/antagonist/traitor/human/finalize_traitor()
+ ..()
if(should_equip) equip(silent)
owner.current.playsound_local('sound/ambience/antag/TatorAlert.ogg',100,0)
diff --git a/code/datums/verbs.dm b/code/datums/verbs.dm
index 2c124d3114b..48f990d2acb 100644
--- a/code/datums/verbs.dm
+++ b/code/datums/verbs.dm
@@ -9,8 +9,10 @@
/datum/verbs/proc/GetList()
CRASH("Abstract verblist for [type]")
-//modify outlist for each entry in Generate_list
-/datum/verbs/proc/HandleVerb(list/outlist, atom/verb/verbpath, ...)
+//do things for each entry in Generate_list
+//return value sets Generate_list[verbpath]
+/datum/verbs/proc/HandleVerb(list/entry, atom/verb/verbpath, ...)
+ return entry
/datum/verbs/New()
var/mainlist = GetList()
@@ -91,8 +93,7 @@
else
entry["command"] = replacetext(verbpath.name, " ", "-")
- HandleVerb(arglist(list(entry, verbpath) + args))
- .[verbpath] = entry
+ .[verbpath] = HandleVerb(arglist(list(entry, verbpath) + args))
/world/proc/LoadVerbs(verb_type)
if(!ispath(verb_type, /datum/verbs) || verb_type == /datum/verbs)
diff --git a/code/game/gamemodes/clock_cult/clock_items/clock_components.dm b/code/game/gamemodes/clock_cult/clock_items/clock_components.dm
index 199e0ba9519..6dec7258f64 100644
--- a/code/game/gamemodes/clock_cult/clock_items/clock_components.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/clock_components.dm
@@ -69,7 +69,7 @@
/obj/item/clockwork/component/vanguard_cogwheel/onyx_prism
name = "onyx prism"
desc = "An onyx prism with a small aperture. It's very heavy."
- clockwork_desc = "A broken prism from a mending motor. Serviceable as a substitute for a vanguard cogwheel."
+ clockwork_desc = "A broken prism from a prolonging prism. Serviceable as a substitute for a vanguard cogwheel."
icon_state = "onyx_prism"
cultist_message = "The prism grows painfully hot in your hands."
servant_of_ratvar_messages = list("The prism isn't getting any lighter." = FALSE, "\"So... you haven't failed yet. Have hope, child.\"" = TRUE, \
diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
index c079cbb9257..f8bc5e4ce02 100644
--- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
+++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
@@ -214,6 +214,38 @@
quickbind_desc = "Creates an Interdiction Lens, which drains power into nearby Sigils of Transmission."
+//Prolonging Prism: Creates a prism that will delay the shuttle at a power cost
+/datum/clockwork_scripture/create_object/prolonging_prism
+ descname = "Powered Structure, Delay Emergency Shuttles"
+ name = "Prolonging Prism"
+ desc = "Creates a mechanized prism which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost."
+ invocations = list("May this prism...", "...grant us time to enact his will!")
+ channel_time = 80
+ consumed_components = list(VANGUARD_COGWHEEL = 5, GEIS_CAPACITOR = 2, REPLICANT_ALLOY = 2)
+ object_path = /obj/structure/destructible/clockwork/powered/prolonging_prism
+ creator_message = "You form a prolonging prism, which will delay the arrival of an emergency shuttle at a massive power cost."
+ observer_message = "An onyx prism forms in midair and sprouts tendrils to support itself!"
+ invokers_required = 2
+ multiple_invokers_used = TRUE
+ usage_tip = "The power cost to delay a shuttle increases based on CV and the number of times activated."
+ tier = SCRIPTURE_APPLICATION
+ one_per_tile = TRUE
+ primary_component = VANGUARD_COGWHEEL
+ sort_priority = 7
+ quickbind = TRUE
+ quickbind_desc = "Creates a Prolonging Prism, which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost."
+
+/datum/clockwork_scripture/create_object/prolonging_prism/check_special_requirements()
+ if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
+ to_chat(invoker, "\"It is too late to construct one of these, champion.\"")
+ return FALSE
+ var/turf/T = get_turf(invoker)
+ if(!T || T.z != ZLEVEL_STATION)
+ to_chat(invoker, "\"You must be on the station to construct one of these, champion.\"")
+ return FALSE
+ return ..()
+
+
//Mania Motor: Creates a malevolent transmitter that will broadcast the whispers of Sevtug into the minds of nearby nonservants, causing a variety of mental effects at a power cost.
/datum/clockwork_scripture/create_object/mania_motor
descname = "Powered Structure, Area Denial"
diff --git a/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm b/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm
new file mode 100644
index 00000000000..28cc82ff2ee
--- /dev/null
+++ b/code/game/gamemodes/clock_cult/clock_structures/prolonging_prism.dm
@@ -0,0 +1,140 @@
+//Prolonging Prism: A prism that consumes power to delay the shuttle
+/obj/structure/destructible/clockwork/powered/prolonging_prism
+ name = "prolonging prism"
+ desc = "A dark onyx prism, held in midair by spiraling tendrils of stone."
+ clockwork_desc = "A powerful prism that will delay the arrival of an emergency shuttle."
+ icon_state = "prolonging_prism_inactive"
+ active_icon = "prolonging_prism"
+ inactive_icon = "prolonging_prism_inactive"
+ unanchored_icon = "prolonging_prism_unwrenched"
+ construction_value = 20
+ max_integrity = 125
+ obj_integrity = 125
+ break_message = "The prism falls to the ground with a heavy thud!"
+ debris = list(/obj/item/clockwork/alloy_shards/small = 3, \
+ /obj/item/clockwork/alloy_shards/medium = 1, \
+ /obj/item/clockwork/alloy_shards/large = 1, \
+ /obj/item/clockwork/component/vanguard_cogwheel/onyx_prism = 1)
+ var/static/list/component_refund = list(VANGUARD_COGWHEEL = 2, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1)
+ var/static/delay_cost = 2500
+ var/static/delay_cost_increase = 750
+ var/static/delay_remaining = 0
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/examine(mob/user)
+ ..()
+ if(is_servant_of_ratvar(user) || isobserver(user))
+ if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
+ to_chat(user, "An emergency shuttle has arrived and this prism is no longer useful; attempt to activate it to gain a partial refund of components used.")
+ else
+ var/efficiency = get_efficiency_mod()
+ var/efficiency_time = get_efficiency_mod(TRUE)
+ to_chat(user, "It requires at least [get_delay_cost() * efficiency]W of power to attempt to delay the arrival of an emergency shuttle by \
+ [2 * efficiency_time] minutes.")
+ to_chat(user, "This cost increases by [delay_cost_increase * 0.1]W for every 10 CV and [delay_cost_increase]W for every previous \
+ activation.")
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/forced_disable(bad_effects)
+ if(active)
+ if(bad_effects)
+ try_use_power(MIN_CLOCKCULT_POWER*4)
+ visible_message("[src] emits an airy chuckling sound and falls dark!")
+ toggle()
+ return TRUE
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/attack_hand(mob/living/user)
+ if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY) && is_servant_of_ratvar(user))
+ if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
+ to_chat(user, "You break [src] apart, refunding some of the components used.")
+ for(var/i in component_refund)
+ generate_cache_component(i, src)
+ take_damage(max_integrity)
+ return 0
+ if(active)
+ return 0
+ var/turf/T = get_turf(src)
+ if(!T || T.z != ZLEVEL_STATION)
+ to_chat(user, "[src] must be on the station to function!")
+ return 0
+ if(SSshuttle.emergency.mode != SHUTTLE_CALL)
+ to_chat(user, "No emergency shuttles are attempting to arrive at the station!")
+ return 0
+ var/efficiency = get_efficiency_mod()
+ if(!try_use_power(get_delay_cost() * efficiency))
+ to_chat(user, "[src] needs more power to function!")
+ return 0
+ delay_cost += delay_cost_increase
+ delay_remaining += PRISM_DELAY_DURATION
+ toggle(0, user)
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/process()
+ var/turf/own_turf = get_turf(src)
+ if(SSshuttle.emergency.mode != SHUTTLE_CALL || delay_remaining <= 0 || !own_turf || own_turf.z != ZLEVEL_STATION)
+ forced_disable(FALSE)
+ return
+ . = ..()
+ var/delay_amount = 40
+ delay_remaining -= delay_amount
+ var/efficiency = get_efficiency_mod()
+ SSshuttle.emergency.setTimer(SSshuttle.emergency.timeLeft(1) + (delay_amount * efficiency))
+ var/highest_y
+ var/highest_x
+ var/lowest_y
+ var/lowest_x
+ var/list/prism_turfs = list()
+ for(var/t in SSshuttle.emergency.ripple_area(SSshuttle.getDock("emergency_home")))
+ prism_turfs[t] = TRUE
+ var/turf/T = t
+ if(!highest_y || T.y > highest_y)
+ highest_y = T.y
+ if(!highest_x || T.x > highest_x)
+ highest_x = T.x
+ if(!lowest_y || T.y < lowest_y)
+ lowest_y = T.y
+ if(!lowest_x || T.x < lowest_x)
+ lowest_x = T.x
+ var/mean_y = Lerp(lowest_y, highest_y)
+ var/mean_x = Lerp(lowest_x, highest_x)
+ if(prob(50))
+ mean_y = Ceiling(mean_y)
+ else
+ mean_y = Floor(mean_y)
+ if(prob(50))
+ mean_x = Ceiling(mean_x)
+ else
+ mean_x = Floor(mean_x)
+ var/turf/semi_random_center_turf = locate(mean_x, mean_y, ZLEVEL_STATION)
+ for(var/t in getline(src, semi_random_center_turf))
+ prism_turfs[t] = TRUE
+ var/placement_style = prob(50)
+ for(var/t in prism_turfs)
+ var/turf/T = t
+ if(placement_style)
+ if(IsOdd(T.x + T.y))
+ seven_random_hexes(T, efficiency)
+ else if(prob(50 * efficiency))
+ new /obj/effect/temp_visual/ratvar/prolonging_prism(T)
+ else
+ if(IsEven(T.x + T.y))
+ seven_random_hexes(T, efficiency)
+ else if(prob(50 * efficiency))
+ new /obj/effect/temp_visual/ratvar/prolonging_prism(T)
+ CHECK_TICK //we may be going over a hell of a lot of turfs
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/get_delay_cost()
+ return Floor((GLOB.clockwork_construction_value * delay_cost_increase * 0.01) + delay_cost, MIN_CLOCKCULT_POWER)
+
+/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/seven_random_hexes(turf/T, efficiency)
+ var/static/list/hex_states = list("prismhex1", "prismhex2", "prismhex3", "prismhex4", "prismhex5", "prismhex6", "prismhex7")
+ var/mutable_appearance/hex_combo
+ for(var/n in hex_states) //BUILD ME A HEXAGON
+ if(prob(50 * efficiency))
+ if(!hex_combo)
+ hex_combo = mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER)
+ else
+ hex_combo.overlays += mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER)
+ if(hex_combo) //YOU BUILT A HEXAGON
+ hex_combo.pixel_x = -16
+ hex_combo.pixel_y = -16
+ hex_combo.mouse_opacity = 0
+ hex_combo.plane = GAME_PLANE
+ new /obj/effect/temp_visual/ratvar/prolonging_prism(T, hex_combo)
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index e37afa2b4d6..93f6ee8172b 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -206,8 +206,8 @@ This file contains the arcane tome files.
if(!SSticker.mode.eldergod)
to_chat(user, "\"I am already here. There is no need to try to summon me now.\"")
return
- if((loc.z && loc.z != ZLEVEL_STATION) || !A.blob_allowed)
- to_chat(user, "The Geometer is not interested in lesser locations; the station is the prize!")
+ if(!(A in GLOB.summon_spots))
+ to_chat(user, "The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!")
return
var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie; it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
if(confirm_final == "No")
@@ -215,7 +215,8 @@ This file contains the arcane tome files.
return
Turf = get_turf(user)
A = get_area(src)
- if(!check_rune_turf(Turf, user) || (loc.z && loc.z != ZLEVEL_STATION)|| !A.blob_allowed)
+ if(!(A in GLOB.summon_spots)) // Check again to make sure they didn't move
+ to_chat(user, "The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!")
return
priority_announce("Figments from an eldritch god are being summoned by [user] into [A.map_name] from an unknown dimension. Disrupt the ritual at all costs!","Central Command Higher Dimensional Affairs", 'sound/AI/spanomalies.ogg')
for(var/B in spiral_range_turfs(1, user, 1))
@@ -248,8 +249,6 @@ This file contains the arcane tome files.
SSblackbox.add_details("cult_runes_scribed", R.cultist_name)
/obj/item/weapon/tome/proc/check_rune_turf(turf/T, mob/user)
- var/area/A = get_area(T)
-
if(isspaceturf(T))
to_chat(user, "You cannot scribe runes in space!")
return FALSE
@@ -262,8 +261,4 @@ This file contains the arcane tome files.
to_chat(user, "The veil is not weak enough here.")
return FALSE
- if(istype(A, /area/shuttle))
- to_chat(user, "Interference from hyperspace engines disrupts the Geometer's power on shuttles.")
- return FALSE
-
return TRUE
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 0f7bb791f27..b5f2b1cec12 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -54,7 +54,7 @@
/datum/game_mode/proc/can_start()
var/playerC = 0
for(var/mob/dead/new_player/player in GLOB.player_list)
- if((player.client)&&(player.ready))
+ if((player.client)&&(player.ready == PLAYER_READY_TO_PLAY))
playerC++
if(!GLOB.Debug2)
if(playerC < required_players || (maximum_players >= 0 && playerC > maximum_players))
@@ -94,8 +94,6 @@
if(report)
addtimer(CALLBACK(src, .proc/send_intercept, 0), rand(waittime_l, waittime_h))
generate_station_goals()
- GLOB.start_state = new /datum/station_state()
- GLOB.start_state.count(1)
return 1
@@ -310,7 +308,7 @@
// Ultimate randomizing code right here
for(var/mob/dead/new_player/player in GLOB.player_list)
- if(player.client && player.ready)
+ if(player.client && player.ready == PLAYER_READY_TO_PLAY)
players += player
// Shuffling, the players list is now ping-independent!!!
@@ -318,7 +316,7 @@
players = shuffle(players)
for(var/mob/dead/new_player/player in players)
- if(player.client && player.ready)
+ if(player.client && player.ready == PLAYER_READY_TO_PLAY)
if(role in player.client.prefs.be_special)
if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, role)) //Nodrak/Carn: Antag Job-bans
if(age_check(player.client)) //Must be older than the minimum age
@@ -332,7 +330,7 @@
if(candidates.len < recommended_enemies)
for(var/mob/dead/new_player/player in players)
- if(player.client && player.ready)
+ if(player.client && player.ready == PLAYER_READY_TO_PLAY)
if(!(role in player.client.prefs.be_special)) // We don't have enough people who want to be antagonist, make a seperate list of people who don't want to be one
if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, role)) //Nodrak/Carn: Antag Job-bans
drafted += player.mind
@@ -354,13 +352,7 @@
else // Not enough scrubs, ABORT ABORT ABORT
break
-/*
- if(candidates.len < recommended_enemies && override_jobbans) //If we still don't have enough people, we're going to start drafting banned people.
- for(var/mob/dead/new_player/player in players)
- if (player.client && player.ready)
- if(jobban_isbanned(player, "Syndicate") || jobban_isbanned(player, roletext)) //Nodrak/Carn: Antag Job-bans
- drafted += player.mind
-*/
+
if(restricted_jobs)
for(var/datum/mind/player in drafted) // Remove people who can't be an antagonist
for(var/job in restricted_jobs)
@@ -383,17 +375,12 @@
// recommended_enemies if the number of people with that role set to yes is less than recomended_enemies,
// Less if there are not enough valid players in the game entirely to make recommended_enemies.
-/*
-/datum/game_mode/proc/check_player_role_pref(var/role, var/mob/dead/new_player/player)
- if(player.preferences.be_special & role)
- return 1
- return 0
-*/
+
/datum/game_mode/proc/num_players()
. = 0
for(var/mob/dead/new_player/P in GLOB.player_list)
- if(P.client && P.ready)
+ if(P.client && P.ready == PLAYER_READY_TO_PLAY)
. ++
///////////////////////////////////
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 039b4cc3a45..21b1180b3d3 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -658,7 +658,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
var/n_p = 1 //autowin
if (SSticker.current_state == GAME_STATE_SETTING_UP)
for(var/mob/dead/new_player/P in GLOB.player_list)
- if(P.client && P.ready && P.mind!=owner)
+ if(P.client && P.ready == PLAYER_READY_TO_PLAY && P.mind!=owner)
n_p ++
else if (SSticker.IsRoundInProgress())
for(var/mob/living/carbon/human/P in GLOB.player_list)
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 5bf819a1558..d5ad78fc1fe 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -159,9 +159,10 @@
else if(istype(W, /obj/item/stack/sheet/mineral/plasma))
if(!isEmpProof())
+ var/obj/item/stack/sheet/mineral/plasma/P = W
upgradeEmpProof()
to_chat(user, "[msg]")
- qdel(W)
+ P.use(1)
else
to_chat(user, "[msg2]")
return
diff --git a/code/game/objects/effects/temporary_visuals/clockcult.dm b/code/game/objects/effects/temporary_visuals/clockcult.dm
index d68008260c6..ff788ef580e 100644
--- a/code/game/objects/effects/temporary_visuals/clockcult.dm
+++ b/code/game/objects/effects/temporary_visuals/clockcult.dm
@@ -140,6 +140,20 @@
pixel_y = rand(-10, 10)
animate(src, alpha = 0, time = 3, easing = EASE_OUT)
+/obj/effect/temp_visual/ratvar/prolonging_prism
+ icon = 'icons/effects/64x64.dmi'
+ icon_state = "prismhex1"
+ layer = RIPPLE_LAYER
+ pixel_y = -16
+ pixel_x = -16
+ duration = 30
+
+/obj/effect/temp_visual/ratvar/prolonging_prism/Initialize(mapload, set_appearance)
+ . = ..()
+ if(set_appearance)
+ appearance = set_appearance
+ animate(src, alpha = 0, time = duration, easing = BOUNCE_EASING)
+
/obj/effect/temp_visual/ratvar/spearbreak
icon = 'icons/effects/64x64.dmi'
icon_state = "ratvarspearbreak"
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 64af889af60..381b69b44f7 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -269,13 +269,15 @@
return
if(!in_range(src, user))
return
+ if(is_cyborg)
+ return
else
if(zero_amount())
return
//get amount from user
var/min = 0
var/max = src.get_amount()
- var/stackmaterial = round(input(user,"How many sheets do you wish to take out of this stack? (Maximum [max]") as num)
+ var/stackmaterial = round(input(user,"How many sheets do you wish to take out of this stack? (Maximum [max])") as num)
if(stackmaterial == null || stackmaterial <= min || stackmaterial >= src.get_amount())
return
else
diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm
index df23172b4fd..2821269da35 100644
--- a/code/game/objects/items/weapons/defib.dm
+++ b/code/game/objects/items/weapons/defib.dm
@@ -276,7 +276,6 @@
force = 0
throwforce = 6
w_class = WEIGHT_CLASS_BULKY
- flags = NODROP
var/revivecost = 1000
var/cooldown = 0
diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm
index fa6b0be45ec..5c1b27b5b4b 100644
--- a/code/game/objects/structures/crates_lockers/closets/job_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm
@@ -353,3 +353,16 @@
new /obj/item/clothing/under/rank/hydroponics(src)
for(var/i in 1 to 3)
new /obj/item/clothing/mask/bandana(src)
+
+
+/obj/structure/closet/wardrobe/curator
+ name = "treasure hunting wardrobe"
+ icon_door = "black"
+
+/obj/structure/closet/wardrobe/curator/PopulateContents()
+ new /obj/item/clothing/head/fedora/curator(src)
+ new /obj/item/clothing/suit/curator(src)
+ new /obj/item/clothing/under/rank/curator/treasure_hunter(src)
+ new /obj/item/clothing/shoes/workboots/mining(src)
+ new /obj/item/weapon/storage/backpack/satchel/explorer(src)
+
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index 6779700ddf0..c045b763f1a 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -168,7 +168,7 @@
..()
new /obj/item/clothing/under/rank/det(src)
new /obj/item/clothing/suit/det_suit(src)
- new /obj/item/clothing/head/det_hat(src)
+ new /obj/item/clothing/head/fedora/det_hat(src)
new /obj/item/clothing/gloves/color/black(src)
new /obj/item/clothing/under/rank/det/grey(src)
new /obj/item/clothing/accessory/waistcoat(src)
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index 3edb53a1ff4..e431d74d04c 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -3,6 +3,7 @@
* Morgue
* Morgue tray
* Crematorium
+ * Creamatorium
* Crematorium tray
* Crematorium button
*/
@@ -189,7 +190,7 @@ GLOBAL_LIST_EMPTY(crematoriums)
// Make sure we don't delete the actual morgue and its tray
var/list/conts = GetAllContents() - src - connected
- if(conts.len <= 1)
+ if(!conts.len)
audible_message("You hear a hollow crackle.")
return
@@ -223,6 +224,20 @@ GLOBAL_LIST_EMPTY(crematoriums)
update_icon()
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) //you horrible people
+/obj/structure/bodycontainer/crematorium/creamatorium
+ name = "creamatorium"
+ desc = "A human incinerator. Works well during ice cream socials."
+
+/obj/structure/bodycontainer/crematorium/creamatorium/cremate(mob/user)
+ var/list/icecreams = new()
+ for(var/mob/living/i_scream in GetAllContents())
+ var/obj/item/weapon/reagent_containers/food/snacks/icecream/IC = new()
+ IC.set_cone_type("waffle")
+ IC.add_mob_flavor(i_scream)
+ icecreams += IC
+ . = ..()
+ for(var/obj/IC in icecreams)
+ IC.forceMove(src)
/*
* Generic Tray
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index a6cac2d8a3c..d16fed30d75 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -183,7 +183,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
to_chat(C, "PM to-Admins: [name]")
//send it to irc if nobody is on and tell us how many were on
- var/admin_number_present = send2irc_adminless_only("#[id] [initiator_ckey]", name)
+ var/admin_number_present = send2irc_adminless_only(initiator_ckey, "Ticket #[id]: [name]")
log_admin_private("Ticket #[id]: [key_name(initiator)]: [name] - heard by [admin_number_present] non-AFK admins who have +BAN.")
if(admin_number_present <= 0)
to_chat(C, "No active admins are online, your adminhelp was sent to the admin irc.")
diff --git a/code/modules/admin/whitelist.dm b/code/modules/admin/whitelist.dm
index 095e3dceac0..082936e0e85 100644
--- a/code/modules/admin/whitelist.dm
+++ b/code/modules/admin/whitelist.dm
@@ -10,7 +10,7 @@ GLOBAL_PROTECT(whitelist)
continue
if(findtextEx(line,"#",1,2))
continue
- GLOB.whitelist += line
+ GLOB.whitelist += ckey(line)
if(!GLOB.whitelist.len)
GLOB.whitelist = null
diff --git a/code/modules/cargo/exports/sheets.dm b/code/modules/cargo/exports/sheets.dm
index 666d0f24fa3..fcd279f87e0 100644
--- a/code/modules/cargo/exports/sheets.dm
+++ b/code/modules/cargo/exports/sheets.dm
@@ -69,7 +69,7 @@
// Plasteel. Lightweight, strong and contains some plasma too.
/datum/export/stack/plasteel
- cost = 85
+ cost = 305 // 2000u of plasma + 2000u of metal.
message = "of plasteel"
export_types = list(/obj/item/stack/sheet/plasteel)
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index 6c09b824023..38bd719891f 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -286,7 +286,7 @@
/obj/item/device/camera,
/obj/item/device/taperecorder,
/obj/item/toy/crayon/white,
- /obj/item/clothing/head/det_hat)
+ /obj/item/clothing/head/fedora/det_hat)
crate_name = "forensics crate"
/datum/supply_pack/security/armory
@@ -1249,13 +1249,13 @@
/datum/supply_pack/materials/plasteel20
name = "20 Plasteel Sheets"
- cost = 3000
+ cost = 7500
contains = list(/obj/item/stack/sheet/plasteel/twenty)
crate_name = "plasteel sheets crate"
/datum/supply_pack/materials/plasteel50
name = "50 Plasteel Sheets"
- cost = 5000
+ cost = 16500
contains = list(/obj/item/stack/sheet/plasteel/fifty)
crate_name = "plasteel sheets crate"
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index fcbaace6fb9..a5b4b0ca313 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -278,6 +278,11 @@ BLIND // can't see anything
var/blockTracking = 0 //For AI tracking
var/can_toggle = null
+/obj/item/clothing/head/Initialize()
+ . = ..()
+ if(istype(loc, /mob/living/carbon/human) && dynamic_hair_suffix)
+ var/mob/living/carbon/human/H = loc
+ H.update_hair()
/obj/item/clothing/head/worn_overlays(isinhands = FALSE)
. = list()
@@ -293,6 +298,16 @@ BLIND // can't see anything
var/mob/M = loc
M.update_inv_head()
+/obj/item/clothing/head/equipped(mob/user, slot)
+ ..()
+ if(dynamic_hair_suffix)
+ user.update_hair()
+
+/obj/item/clothing/head/dropped(mob/user)
+ ..()
+ if(dynamic_hair_suffix)
+ user.update_hair()
+
//Neck
/obj/item/clothing/neck
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index 8402bdfdac3..6fc3a36ad6c 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -72,16 +72,15 @@
flags_cover = HEADCOVERSEYES
//Detective
-/obj/item/clothing/head/det_hat
+/obj/item/clothing/head/fedora/det_hat
name = "detective's fedora"
desc = "There's only one man who can sniff out the dirty stench of crime, and he's likely wearing this hat."
icon_state = "detective"
- armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50)
var/candy_cooldown = 0
pockets = /obj/item/weapon/storage/internal/pocket/small/detective
dog_fashion = /datum/dog_fashion/head/detective
-/obj/item/clothing/head/det_hat/AltClick()
+/obj/item/clothing/head/fedora/det_hat/AltClick()
..()
if(ismob(loc))
var/mob/M = loc
@@ -166,9 +165,7 @@
icon_state = "officerberet"
//Curator
-/obj/item/clothing/head/curator
+/obj/item/clothing/head/fedora/curator
name = "treasure hunter's fedora"
desc = "You got red text today kid, but it doesn't mean you have to like it."
- icon_state = "curator"
- armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50)
- pockets = /obj/item/weapon/storage/internal/pocket/small
\ No newline at end of file
+ icon_state = "curator"
\ No newline at end of file
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index f7e913df678..7428936eaa4 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -181,7 +181,9 @@
name = "fedora"
icon_state = "fedora"
item_state = "fedora"
+ armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50)
desc = "A really cool hat if you're a mobster. A really lame hat if you're not."
+ dynamic_hair_suffix = "+detective"
pockets = /obj/item/weapon/storage/internal/pocket/small
/obj/item/clothing/head/fedora/suicide_act(mob/user)
diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm
index ff60b5366eb..b405c16a7bc 100644
--- a/code/modules/clothing/outfits/standard.dm
+++ b/code/modules/clothing/outfits/standard.dm
@@ -30,7 +30,7 @@
uniform = /obj/item/clothing/under/rank/det
suit = /obj/item/clothing/suit/det_suit
glasses = /obj/item/clothing/glasses/thermal/monocle
- head = /obj/item/clothing/head/det_hat
+ head = /obj/item/clothing/head/fedora/det_hat
r_hand = /obj/item/weapon/gun/ballistic
l_hand = null
r_pocket = /obj/item/ammo_box/c10mm
diff --git a/code/modules/events/ghost_role.dm b/code/modules/events/ghost_role.dm
index 2468ddb5c6a..f5e9513b2ea 100644
--- a/code/modules/events/ghost_role.dm
+++ b/code/modules/events/ghost_role.dm
@@ -26,9 +26,7 @@
var/waittime = 300 * (2^retry)
message_admins("The event will not spawn a [role_name] until certain \
conditions are met. Waiting [waittime/10]s and then retrying.")
- spawn(waittime)
- // I hope this doesn't end up running out of stack space
- try_spawning(0,++retry)
+ addtimer(CALLBACK(src, .proc/try_spawning, 0, ++retry), waittime)
return
if(status == MAP_ERROR)
@@ -69,4 +67,4 @@
return candidates
-#undef MAX_SPAWN_ATTEMPT
\ No newline at end of file
+#undef MAX_SPAWN_ATTEMPT
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index fb625e14ea2..08fc5391201 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -287,7 +287,7 @@
name = "detective's flask"
desc = "The detective's only true friend."
icon_state = "detflask"
- list_reagents = list("whiskey" = 30)
+ list_reagents = list("hearty_punch" = 30)
/obj/item/weapon/reagent_containers/food/drinks/britcup
name = "cup"
diff --git a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
index 647c1bc5ba0..e6807f79cbf 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
@@ -147,15 +147,7 @@
if(product_types[dispense_cone] >= 1)
product_types[dispense_cone] -= 1
var/obj/item/weapon/reagent_containers/food/snacks/icecream/I = new(src.loc)
- I.cone_type = cone_name
- I.icon_state = "icecream_cone_[cone_name]"
- switch (I.cone_type)
- if ("waffle")
- I.reagents.add_reagent("nutriment", 1)
- if ("chocolate")
- I.reagents.add_reagent("cocoa", 1) // chocolate ain't as nutritious kids
-
- I.desc = "Delicious [cone_name] cone, but no ice cream."
+ I.set_cone_type(cone_name)
src.visible_message("[usr] dispenses a crunchy [cone_name] cone from [src].")
else
to_chat(usr, "There are no [cone_name] cones left!")
@@ -187,10 +179,23 @@
var/cone_type
bitesize = 3
-/obj/item/weapon/reagent_containers/food/snacks/icecream/New()
+/obj/item/weapon/reagent_containers/food/snacks/icecream/Initialize()
+ . = ..()
create_reagents(20)
reagents.add_reagent("nutriment", 4)
+/obj/item/weapon/reagent_containers/food/snacks/icecream/proc/set_cone_type(var/cone_name)
+ cone_type = cone_name
+ icon_state = "icecream_cone_[cone_name]"
+ switch (cone_type)
+ if ("waffle")
+ reagents.add_reagent("nutriment", 1)
+ if ("chocolate")
+ reagents.add_reagent("cocoa", 1) // chocolate ain't as nutritious kids
+
+ desc = "Delicious [cone_name] cone, but no ice cream."
+
+
/obj/item/weapon/reagent_containers/food/snacks/icecream/proc/add_ice_cream(var/flavour_name)
name = "[flavour_name] icecream"
src.add_overlay("icecream_[flavour_name]")
@@ -206,8 +211,15 @@
if ("blue")
desc = "A delicious [cone_type] cone filled with blue ice cream. Made with real... blue?"
reagents.add_reagent("singulo", 2)
+ if ("mob")
+ desc = "A suspicious [cone_type] cone filled with bright red ice cream. That's probably not strawberry..."
+ reagents.add_reagent("liquidgibs", 2)
ice_creamed = 1
+/obj/item/weapon/reagent_containers/food/snacks/icecream/proc/add_mob_flavor(var/mob/M)
+ add_ice_cream("mob")
+ name = "[M.name] icecream"
+
/obj/machinery/icecream_vat/deconstruct(disassembled = TRUE)
if(!(flags & NODECONSTRUCT))
new /obj/item/stack/sheet/metal(loc, 4)
diff --git a/code/modules/jobs/job_types/security.dm b/code/modules/jobs/job_types/security.dm
index 4e3864dbaf4..d5fc677208f 100644
--- a/code/modules/jobs/job_types/security.dm
+++ b/code/modules/jobs/job_types/security.dm
@@ -137,7 +137,7 @@ Detective
shoes = /obj/item/clothing/shoes/sneakers/brown
suit = /obj/item/clothing/suit/det_suit
gloves = /obj/item/clothing/gloves/color/black
- head = /obj/item/clothing/head/det_hat
+ head = /obj/item/clothing/head/fedora/det_hat
l_pocket = /obj/item/toy/crayon/white
r_pocket = /obj/item/weapon/lighter
backpack_contents = list(/obj/item/weapon/storage/box/evidence=1,\
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index c8bc7f4ff5b..c26c1089fc7 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -29,21 +29,25 @@
/mob/dead/new_player/prepare_huds()
return
-/mob/dead/new_player/proc/new_player_panel()
+/mob/dead/new_player/proc/linkify_ready(string, value)
+ return "Setup Character
< href='byond://?src=\ref[src];show_preferences=1'>Setup Character
" if(!SSticker || SSticker.current_state <= GAME_STATE_PREGAME) - if(ready) - output += "\[ Ready | Not Ready \]
" - else - output += "\[ Ready | Not Ready \]
" + switch(ready) + if(PLAYER_NOT_READY) + output += "\[ [linkify_ready("Ready", PLAYER_READY_TO_PLAY)] | Not Ready | [linkify_ready("Observe", PLAYER_READY_TO_OBSERVE)] \]
" + if(PLAYER_READY_TO_PLAY) + output += "\[ Ready | [linkify_ready("Not Ready", PLAYER_NOT_READY)] | [linkify_ready("Observe", PLAYER_READY_TO_OBSERVE)] \]
" + if(PLAYER_READY_TO_OBSERVE) + output += "\[ [linkify_ready("Ready", PLAYER_READY_TO_PLAY)]] | [linkify_ready("Not Ready", PLAYER_NOT_READY)] | Observe \]
" else output += "" output += "" - - output += "" + output += "[linkify_ready("Observe", 2)]
" if(!IsGuestKey(src.key)) if (SSdbcore.Connect()) @@ -108,42 +112,23 @@ return 1 if(href_list["ready"]) - if(!SSticker || SSticker.current_state <= GAME_STATE_PREGAME) // Make sure we don't ready up after the round has started - ready = text2num(href_list["ready"]) + if(SSticker) + var/tready = text2num(href_list["ready"]) + //Avoid updating ready if we're after PREGAME (they should use latejoin instead) + //This is likely not an actual issue but I don't have time to prove that this + //no longer is required + if(SSticker.current_state <= GAME_STATE_PREGAME) + ready = tready + //if it's post initialisation and they're trying to observe we do the needful + if(!SSticker.current_state < GAME_STATE_PREGAME && tready == PLAYER_READY_TO_OBSERVE) + ready = tready + make_me_an_observer() + return if(href_list["refresh"]) src << browse(null, "window=playersetup") //closes the player setup window new_player_panel() - if(href_list["observe"]) - - if(alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No") == "Yes") - if(!client) - return 1 - var/mob/dead/observer/observer = new() - - spawning = 1 - - observer.started_as_observer = 1 - close_spawn_windows() - var/obj/O = locate("landmark*Observer-Start") - to_chat(src, "Now teleporting.") - if (O) - observer.loc = O.loc - else - to_chat(src, "Teleporting failed. The map is probably still loading...") - observer.key = key - observer.client = client - observer.set_ghost_appearance() - if(observer.client && observer.client.prefs) - observer.real_name = observer.client.prefs.real_name - observer.name = observer.real_name - observer.update_icon() - observer.stop_sound_channel(CHANNEL_LOBBYMUSIC) - QDEL_NULL(mind) - qdel(src) - return 1 - if(href_list["late_join"]) if(!SSticker || !SSticker.IsRoundInProgress()) to_chat(usr, "The round is either not ready, or has already finished...") @@ -273,6 +258,42 @@ return to_chat(src, "Vote successful.") +//When you cop out of the round (NB: this HAS A SLEEP FOR PLAYER INPUT IN IT) +/mob/dead/new_player/proc/make_me_an_observer() + if(QDELETED(src) || !src.client) + ready = PLAYER_NOT_READY + return FALSE + + var/this_is_like_playing_right = alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No") + + if(QDELETED(src) || !src.client || this_is_like_playing_right != "Yes") + ready = PLAYER_NOT_READY + return FALSE + + var/mob/dead/observer/observer = new() + spawning = TRUE + + observer.started_as_observer = TRUE + close_spawn_windows() + var/obj/O = locate("landmark*Observer-Start") + to_chat(src, "Now teleporting.") + if (O) + observer.loc = O.loc + else + to_chat(src, "Teleporting failed. Ahelp an admin please") + stack_trace("There's no freaking observer landmark available on this map or you're making observers before the map is initialised") + observer.key = key + observer.client = client + observer.set_ghost_appearance() + if(observer.client && observer.client.prefs) + observer.real_name = observer.client.prefs.real_name + observer.name = observer.real_name + observer.update_icon() + observer.stop_sound_channel(CHANNEL_LOBBYMUSIC) + QDEL_NULL(mind) + qdel(src) + return TRUE + /mob/dead/new_player/proc/IsJobAvailable(rank) var/datum/job/job = SSjob.GetJob(rank) if(!job) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 694c9592c4f..6e453f68ef9 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -119,7 +119,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) GLOB.dead_mob_list += src - ..() + . = ..() grant_all_languages() diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm index 90d4ced85fc..71619ff9a41 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm @@ -45,9 +45,6 @@ if(!get_alien_type(/mob/living/carbon/alien/humanoid/royal/queen)) var/mob/living/carbon/alien/humanoid/royal/queen/new_xeno = new (user.loc) user.alien_evolve(new_xeno) - if(new_xeno.client.prefs.unlock_content) - var/datum/action/innate/maid/M = new() - M.Grant(new_xeno) return 1 else to_chat(user, "We already have an alive queen.") diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm index dc172b7730d..392e7ec67a9 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm @@ -153,36 +153,3 @@ /obj/item/queenpromote/attack_self(mob/user) to_chat(user, "You discard [src].") qdel(src) - -//:^) -/datum/action/innate/maid - name = "Maidify" - button_icon_state = "alien_queen_maidify" - check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS|AB_CHECK_LYING - background_icon_state = "bg_alien" - -/datum/action/innate/maid/Activate() - var/mob/living/carbon/alien/humanoid/royal/queen/A = owner - A.maidify() - active = TRUE - -/datum/action/innate/maid/Deactivate() - var/mob/living/carbon/alien/humanoid/royal/queen/A = owner - A.unmaidify() - active = FALSE - - - -/mob/living/carbon/alien/humanoid/royal/queen/proc/maidify() - name = "alien queen maid" - desc = "Lusty, Sexy" - icon_state = "alienqmaid" - caste = "qmaid" - update_icons() - -/mob/living/carbon/alien/humanoid/royal/queen/proc/unmaidify() - name = "alien queen" - desc = "" - icon_state = "alienq" - caste = "q" - update_icons() diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 82e53a73000..a5da6abdb8c 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -232,9 +232,6 @@ if(lying) M.visible_message("[M] shakes [src] trying to get [p_them()] up!", \ "You shake [src] trying to get [p_them()] up!") - else if(check_zone(M.zone_selected) == "head") - M.visible_message("[M] gives [src] a pat on the head to make [p_them()] feel better!", \ - "You give [src] a pat on the head to make [p_them()] feel better!") else M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \ "You hug [src] to make [p_them()] feel better!") @@ -303,8 +300,9 @@ Weaken(stun_pwr*effect_amount) if(istype(ears) && (deafen_pwr || damage_pwr)) - ears.ear_damage += damage_pwr * effect_amount - ears.deaf = max(ears.deaf, deafen_pwr * effect_amount) + var/ear_damage = damage_pwr * effect_amount + var/deaf = max(ears.deaf, deafen_pwr * effect_amount) + adjustEarDamage(ear_damage,deaf) if(ears.ear_damage >= 15) to_chat(src, "Your ears start to ring badly!") diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 9ca002fe102..214ba337514 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1082,18 +1082,7 @@ /datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) - var/aim_for_mouth = user.zone_selected == "mouth" - var/target_on_help_and_unarmed = target.a_intent == INTENT_HELP && !target.get_active_held_item() - var/target_aiming_for_mouth = target.zone_selected == "mouth" - var/target_restrained = target.restrained() - if(aim_for_mouth && ( target_on_help_and_unarmed || target_restrained || target_aiming_for_mouth)) - playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1) - user.visible_message("[user] slaps [target] in the face!", - "You slap [target] in the face! ",\ - "You hear a slap.") - target.endTailWag() - return FALSE - else if(target.check_block()) + if(target.check_block()) target.visible_message("[target] blocks [user]'s disarm attempt!") return 0 if(attacker_style && attacker_style.disarm_act(user,target)) diff --git a/code/modules/research/designs/smelting_designs.dm b/code/modules/research/designs/smelting_designs.dm index 9367b38da7a..5c9c0f68313 100644 --- a/code/modules/research/designs/smelting_designs.dm +++ b/code/modules/research/designs/smelting_designs.dm @@ -4,7 +4,7 @@ name = "Plasma + Iron alloy" id = "plasteel" build_type = SMELTER - materials = list(MAT_METAL = MINERAL_MATERIAL_AMOUNT / 2, MAT_PLASMA = MINERAL_MATERIAL_AMOUNT / 2) + materials = list(MAT_METAL = MINERAL_MATERIAL_AMOUNT, MAT_PLASMA = MINERAL_MATERIAL_AMOUNT) build_path = /obj/item/stack/sheet/plasteel category = list("initial") @@ -13,7 +13,7 @@ name = "Plasma + Titanium alloy" id = "plastitanium" build_type = SMELTER - materials = list(MAT_TITANIUM = MINERAL_MATERIAL_AMOUNT / 2, MAT_PLASMA = MINERAL_MATERIAL_AMOUNT / 2) + materials = list(MAT_TITANIUM = MINERAL_MATERIAL_AMOUNT, MAT_PLASMA = MINERAL_MATERIAL_AMOUNT) build_path = /obj/item/stack/sheet/mineral/plastitanium category = list("initial") diff --git a/code/modules/ruins/objects_and_mobs/ash_walker_den.dm b/code/modules/ruins/objects_and_mobs/ash_walker_den.dm index c59850198e3..0acfcc2a45b 100644 --- a/code/modules/ruins/objects_and_mobs/ash_walker_den.dm +++ b/code/modules/ruins/objects_and_mobs/ash_walker_den.dm @@ -12,6 +12,15 @@ loot = list(/obj/effect/gibspawner, /obj/item/device/assembly/signaler/anomaly) del_on_death = 1 var/meat_counter + var/obj/effect/light_emitter/tendril/emitted_light + +/mob/living/simple_animal/hostile/spawner/ash_walker/Initialize() + . = ..() + emitted_light = new(loc) + +/mob/living/simple_animal/hostile/spawner/ash_walker/Destroy() + QDEL_NULL(emitted_light) + . = ..() /mob/living/simple_animal/hostile/spawner/ash_walker/Life() ..() diff --git a/html/changelog.html b/html/changelog.html index 2d9e95ce776..451bf7fd683 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,45 @@ -->