diff --git a/_maps/festivestation.json b/_maps/festivestation.json
index 0803c1b566..b8884371a3 100644
--- a/_maps/festivestation.json
+++ b/_maps/festivestation.json
@@ -7,5 +7,8 @@
"ferry": "ferry_fancy",
"whiteship": "whiteship_box",
"emergency": "emergency_box"
- }
+ },
+ "traits": [
+ { "Weather_Icestorm":true }
+ ]
}
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index 791e6d1368..4078c690d4 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -29637,6 +29637,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
+/obj/item/cautery,
/turf/open/floor/plasteel/white,
/area/science/robotics/lab)
"btb" = (
diff --git a/_maps/spookystation.json b/_maps/spookystation.json
index ec2db6e950..c880aacff7 100644
--- a/_maps/spookystation.json
+++ b/_maps/spookystation.json
@@ -7,5 +7,8 @@
"whiteship": "whiteship_pubby",
"ferry": "ferry_fancy",
"cargo": "cargo_box"
- }
+ },
+ "traits": [
+ { "Weather_Longrain":true }
+ ]
}
diff --git a/code/__DEFINES/maps.dm b/code/__DEFINES/maps.dm
index 5e3f571cb7..70bb338b7b 100644
--- a/code/__DEFINES/maps.dm
+++ b/code/__DEFINES/maps.dm
@@ -43,6 +43,8 @@ require only minor tweaks.
#define ZTRAIT_ASHSTORM "Weather_Ashstorm"
#define ZTRAIT_ACIDRAIN "Weather_Acidrain"
#define ZTRAIT_VOIDSTORM "Weather_Voidstorm"
+#define ZTRAIT_ICESTORM "Weather_Icestorm"
+#define ZTRAIT_LONGRAIN "Weather_Longrain"
// number - bombcap is multiplied by this before being applied to bombs
#define ZTRAIT_BOMBCAP_MULTIPLIER "Bombcap Multiplier"
diff --git a/code/controllers/subsystem/research.dm b/code/controllers/subsystem/research.dm
index 410e21d419..46fb232d6d 100644
--- a/code/controllers/subsystem/research.dm
+++ b/code/controllers/subsystem/research.dm
@@ -343,10 +343,15 @@ SUBSYSTEM_DEF(research)
break //Just need one to work.
if (!isnull(last_income))
var/income_time_difference = world.time - last_income
- science_tech.last_bitcoins = bitcoins // Doesn't take tick drift into account
for(var/i in bitcoins)
bitcoins[i] *= income_time_difference / 10
science_tech.add_point_list(bitcoins)
+ if(!length(science_tech.last_bitcoins))
+ science_tech.last_bitcoins = science_tech.research_points
+ for(var/i in science_tech.last_bitcoins)
+ var/old_weighted = science_tech.last_bitcoins[i] * (1 MINUTES - income_time_difference)
+ var/new_weighted = science_tech.research_points[i] * income_time_difference
+ science_tech.last_bitcoins[i] = round((old_weighted + new_weighted) / (1 MINUTES))
last_income = world.time
/datum/controller/subsystem/research/proc/calculate_server_coefficient() //Diminishing returns.
diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm
index 03c23e11f6..eb49323464 100644
--- a/code/datums/chatmessage.dm
+++ b/code/datums/chatmessage.dm
@@ -178,7 +178,7 @@
var/mob/living/silicon/robot/R = target
if(iscyborg(R))
- if(R.module.dogborg == TRUE || R.dogborg == TRUE) //I hate whoever that thought that putting two types of dogborg that don't even sync up properly was good
+ if((R.module.dogborg == TRUE || R.dogborg == TRUE) && isturf(R.loc)) //I hate whoever that thought that putting two types of dogborg that don't even sync up properly was good
message.pixel_x = 16
/**
diff --git a/code/datums/weather/weather_types/ice_storm.dm b/code/datums/weather/weather_types/ice_storm.dm
index f7be622770..451b0bdad6 100644
--- a/code/datums/weather/weather_types/ice_storm.dm
+++ b/code/datums/weather/weather_types/ice_storm.dm
@@ -19,7 +19,7 @@
area_type = /area/edina
protected_areas = list(/area/edina/protected)
- target_trait = ZTRAIT_STATION
+ target_trait = ZTRAIT_ICESTORM
immunity_type = "rad"
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
index b62befc88c..0052306949 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
@@ -382,6 +382,70 @@
else
return ..()
+//////////////////////////////////////////////
+// //
+// Clock Cult (MID) //
+// //
+//////////////////////////////////////////////
+
+
+//changes two people midround into clockwork cultists
+/datum/dynamic_ruleset/midround/ratvar_awakening
+ name = "Ratvar Awakening"
+ antag_datum = /datum/antagonist/clockcult
+ antag_flag = "clock mid"
+ antag_flag_override = ROLE_SERVANT_OF_RATVAR
+ protected_roles = list("AI", "Cyborg", "Prisoner", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Chaplain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Chief Medical Officer", "Research Director")
+ restricted_roles = list("AI", "Cyborg", "Prisoner", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Chaplain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Chief Medical Officer", "Research Director")
+ enemy_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Chaplain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Chief Medical Officer", "Research Director")
+ required_enemies = list(1,1,1,1,1,1,0,0,0,0)
+ required_candidates = 2
+ weight = 3
+ cost = 20
+ requirements = list(101,101,101,101,50,40,30,20,10,10)
+ var/list/clock_cap = list(1,1,1,1,2,3,4,5,5,5)
+ flags = HIGH_IMPACT_RULESET
+
+/datum/dynamic_ruleset/midround/ratvar_awakening/acceptable(population=0, threat=0)
+ if (locate(/datum/dynamic_ruleset/roundstart/clockcult) in mode.executed_rules)
+ return FALSE // Unavailable if clockies exist at round start
+ indice_pop = min(clock_cap.len, round(living_players.len/5)+1)
+ required_candidates = clock_cap[indice_pop]
+ return ..()
+
+/datum/dynamic_ruleset/midround/ratvar_awakening/trim_candidates()
+ ..()
+ candidates = living_players
+ for(var/mob/living/player as anything in candidates)
+ var/turf/player_turf = get_turf(player)
+ if(!player_turf || !is_station_level(player_turf.z))
+ candidates -= player //no ghost roles
+ continue
+
+ if(!is_eligible_servant(player))
+ candidates -= player
+ continue
+
+ if(player.mind && (player.mind.special_role || length(player.mind.antag_datums) > 0))
+ candidates -= player //no double dipping
+
+/datum/dynamic_ruleset/midround/ratvar_awakening/execute()
+ if(!candidates || !candidates.len)
+ return FALSE
+ for(var/i = 0; i < required_candidates; i++)
+ if(!candidates.len)
+ break
+ var/mob/living/clock_antag = pick_n_take(candidates)
+ assigned += clock_antag.mind
+ for(var/datum/mind/M in assigned) //add them to the clockwork team
+ add_servant_of_ratvar(M.current)
+ SSticker.mode.equip_servant(M.current)
+ SSticker.mode.greet_servant(M.current)
+ message_admins("[ADMIN_LOOKUPFLW(M.current)] was selected by the [name] ruleset and has been made into a midround clock cultist.")
+ log_game("DYNAMIC: [key_name(M.current)] was selected by the [name] ruleset and has been made into a midround clock cultist.")
+ load_reebe()
+ return ..()
+
//////////////////////////////////////////////
// //
// BLOB (GHOST) //
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index ad9c8edf8f..fffcd6dada 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -271,18 +271,7 @@
if(resin_cooldown)
to_chat(user, "Resin launcher is still recharging...")
return
- resin_cooldown = TRUE
- R.remove_any(100)
- var/obj/effect/resin_container/A = new (get_turf(src))
- log_game("[key_name(user)] used Resin Launcher at [AREACOORD(user)].")
- playsound(src,'sound/items/syringeproj.ogg',40,1)
- for(var/a=0, a<5, a++)
- step_towards(A, target)
- sleep(2)
- A.Smoke()
- spawn(100)
- if(src)
- resin_cooldown = FALSE
+ launch_resin(target, user)
return
if(nozzle_mode == RESIN_FOAM)
if(!Adj|| !isturf(target))
@@ -301,6 +290,21 @@
to_chat(user, "Resin foam mix is still being synthesized...")
return
+/obj/item/extinguisher/mini/nozzle/proc/launch_resin(atom/target, mob/user)
+ set waitfor = FALSE
+ resin_cooldown = TRUE
+ reagents.remove_any(100)
+ var/obj/effect/resin_container/A = new (get_turf(src))
+ log_game("[key_name(user)] used Resin Launcher at [AREACOORD(user)].")
+ playsound(src,'sound/items/syringeproj.ogg',40,1)
+ for(var/a=0, a<5, a++)
+ step_towards(A, target)
+ sleep(2)
+ A.Smoke()
+ spawn(100)
+ if(src)
+ resin_cooldown = FALSE
+
/obj/effect/resin_container
name = "resin container"
desc = "A compacted ball of expansive resin, used to repair the atmosphere in a room, or seal off breaches."
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index 9bd1030685..521c32fe3d 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -387,8 +387,7 @@
log_combat(user, M, "used a cult spell on", source.name, "")
M.set_last_attacker(user)
-/obj/item/melee/blood_magic/afterattack(atom/target, mob/living/carbon/user, proximity)
- . = ..()
+/obj/item/melee/blood_magic/proc/post_cast(atom/target, mob/living/carbon/user, proximity)
if(invocation)
user.whisper(invocation, language = /datum/language/common)
if(health_cost)
@@ -467,6 +466,7 @@
to_chat(user, "In an brilliant flash of red, [L] [is_servant_of_ratvar(L) ? "writhes in pain!" : "falls to the ground!"]")
uses--
..()
+ post_cast(target, user, proximity)
//Teleportation
/obj/item/melee/blood_magic/teleport
@@ -480,40 +480,45 @@
to_chat(user, "You can only teleport adjacent cultists with this spell!")
return
if(iscultist(user))
- var/list/potential_runes = list()
- var/list/teleportnames = list()
- for(var/R in GLOB.teleport_runes)
- var/obj/effect/rune/teleport/T = R
- potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T
-
- if(!potential_runes.len)
- to_chat(user, "There are no valid runes to teleport to!")
- log_game("Teleport talisman failed - no other teleport runes")
- return
-
- var/turf/T = get_turf(src)
- if(is_away_level(T.z))
- to_chat(user, "You are not in the right dimension!")
- log_game("Teleport spell failed - user in away mission")
- return
-
- var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked
- var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
- if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune || !proximity)
- return
- var/turf/dest = get_turf(actual_selected_rune)
- if(is_blocked_turf(dest, TRUE))
- to_chat(user, "The target rune is blocked. Attempting to teleport to it would be massively unwise.")
- return
- uses--
- var/turf/origin = get_turf(user)
- var/mob/living/L = target
- if(do_teleport(L, dest, channel = TELEPORT_CHANNEL_CULT))
- origin.visible_message("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!", \
- "You speak the words of the talisman and find yourself somewhere else!", "You hear a sharp crack.")
- dest.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
+ try_teleport(target, user, proximity)
..()
+/obj/item/melee/blood_magic/teleport/proc/try_teleport(atom/target, mob/living/carbon/user, proximity)
+ set waitfor = FALSE
+ var/list/potential_runes = list()
+ var/list/teleportnames = list()
+ for(var/R in GLOB.teleport_runes)
+ var/obj/effect/rune/teleport/T = R
+ potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T
+
+ if(!potential_runes.len)
+ to_chat(user, "There are no valid runes to teleport to!")
+ log_game("Teleport talisman failed - no other teleport runes")
+ return
+
+ var/turf/T = get_turf(src)
+ if(is_away_level(T.z))
+ to_chat(user, "You are not in the right dimension!")
+ log_game("Teleport spell failed - user in away mission")
+ return
+
+ var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked
+ var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
+ if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune || !proximity)
+ return
+ var/turf/dest = get_turf(actual_selected_rune)
+ if(is_blocked_turf(dest, TRUE))
+ to_chat(user, "The target rune is blocked. Attempting to teleport to it would be massively unwise.")
+ return
+ uses--
+ var/turf/origin = get_turf(user)
+ var/mob/living/L = target
+ if(do_teleport(L, dest, channel = TELEPORT_CHANNEL_CULT))
+ origin.visible_message("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!", \
+ "You speak the words of the talisman and find yourself somewhere else!", "You hear a sharp crack.")
+ dest.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
+ post_cast(target, user, proximity)
+
//Shackles
/obj/item/melee/blood_magic/shackles
name = "Binding Aura"
@@ -530,6 +535,7 @@
user.visible_message("This victim doesn't have enough arms to complete the restraint!")
return
..()
+ post_cast(target, user, proximity)
/obj/item/melee/blood_magic/shackles/proc/CuffAttack(mob/living/carbon/C, mob/living/user)
if(!C.handcuffed)
@@ -583,6 +589,7 @@
to_chat(user, "A dark cloud emanates from your hand and swirls around the metal, twisting it into a construct shell!")
new /obj/structure/constructshell(T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ post_cast(target, proximity_flag, user)
else
to_chat(user, "You need 50 metal to produce a construct shell!")
else if(istype(target, /obj/item/stack/sheet/plasteel))
@@ -593,56 +600,73 @@
new /obj/item/stack/sheet/runed_metal(T,quantity)
to_chat(user, "A dark cloud emanates from you hand and swirls around the plasteel, transforming it into runed metal!")
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ post_cast(target, user, proximity_flag)
if(istype(target, /obj/item/clothing/suit/hooded/wintercoat) && target.type != /obj/item/clothing/suit/hooded/wintercoat/narsie)
- if (do_after(user,30,target=target))
- new /obj/item/clothing/suit/hooded/wintercoat/narsie(T)
- qdel(target)
- to_chat(user, "A dark cloud emanates from you hand and swirls around [target], transforming it into a narsian winter coat!")
- SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ convert_coat(target, user, proximity_flag, T)
else if(istype(target,/mob/living/silicon/robot))
- var/mob/living/silicon/robot/candidate = target
- if(!iscultist(user, TRUE))
- to_chat(user, "You are not strongly connected enough to Nar'sie to use make constructs...")
- else if(candidate.mmi)
- user.visible_message("A dark cloud emanates from [user]'s hand and swirls around [candidate]!")
- playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
- var/prev_color = candidate.color
- candidate.color = "black"
- if(do_after(user, 90, target = candidate))
- candidate.emp_act(80)
- var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
- user.visible_message("The dark cloud receedes from what was formerly [candidate], revealing a\n [construct_class]!")
- switch(construct_class)
- if("Juggernaut")
- makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, candidate, user, 0, T)
- if("Wraith")
- makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, candidate, user, 0, T)
- if("Artificer")
- makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, candidate, user, 0, T)
- SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
- uses--
- candidate.mmi = null
- qdel(candidate)
- else
- candidate.color = prev_color
- else
- uses--
- to_chat(user, "A dark cloud emanates from you hand and swirls around [candidate] - twisting it into a construct shell!")
- new /obj/structure/constructshell(T)
- SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ convert_borg(target, user, proximity_flag, T)
else if(istype(target,/obj/machinery/door/airlock))
- playsound(T, 'sound/machines/airlockforced.ogg', 50, 1)
- do_sparks(5, TRUE, target)
- if(do_after(user, 50, target = user))
- target.narsie_act()
- uses--
- user.visible_message("Black ribbons suddenly emanate from [user]'s hand and cling to the airlock - twisting and corrupting it!")
- SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ convert_door(target, user, proximity_flag, T)
else
to_chat(user, "The spell will not work on [target]!")
return
..()
+/obj/item/melee/blood_magic/construction/proc/convert_coat(atom/target, mob/user, proximity_flag, turf/T)
+ set waitfor = FALSE
+ if(do_after(user,30,target=target))
+ new /obj/item/clothing/suit/hooded/wintercoat/narsie(T)
+ qdel(target)
+ to_chat(user, "A dark cloud emanates from you hand and swirls around [target], transforming it into a narsian winter coat!")
+ SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ post_cast(target, user, proximity_flag)
+
+/obj/item/melee/blood_magic/construction/proc/convert_door(atom/target, mob/user, proximity_flag, turf/T)
+ set waitfor = FALSE
+ playsound(T, 'sound/machines/airlockforced.ogg', 50, 1)
+ do_sparks(5, TRUE, target)
+ if(do_after(user, 50, target = user))
+ target.narsie_act()
+ uses--
+ user.visible_message("Black ribbons suddenly emanate from [user]'s hand and cling to the airlock - twisting and corrupting it!")
+ SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ post_cast(target, user, proximity_flag)
+
+/obj/item/melee/blood_magic/construction/proc/convert_borg(atom/target, mob/user, proximity_flag, turf/T)
+ set waitfor = FALSE
+ var/mob/living/silicon/robot/candidate = target
+ if(!iscultist(user, TRUE))
+ to_chat(user, "You are not strongly connected enough to Nar'sie to use make constructs...")
+ return
+ else if(candidate.mmi)
+ user.visible_message("A dark cloud emanates from [user]'s hand and swirls around [candidate]!")
+ playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
+ var/prev_color = candidate.color
+ candidate.color = "black"
+ if(do_after(user, 90, target = candidate))
+ candidate.emp_act(80)
+ var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
+ user.visible_message("The dark cloud receedes from what was formerly [candidate], revealing a\n [construct_class]!")
+ switch(construct_class)
+ if("Juggernaut")
+ makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, candidate, user, 0, T)
+ if("Wraith")
+ makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, candidate, user, 0, T)
+ if("Artificer")
+ makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, candidate, user, 0, T)
+ SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ uses--
+ candidate.mmi = null
+ qdel(candidate)
+ else
+ candidate.color = prev_color
+ else
+ uses--
+ to_chat(user, "A dark cloud emanates from you hand and swirls around [candidate] - twisting it into a construct shell!")
+ new /obj/structure/constructshell(T)
+ SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
+ post_cast(target, user, proximity_flag)
+
//Armor: Gives the target a basic cultist combat loadout
/obj/item/melee/blood_magic/armor
name = "Bladed Aura"
@@ -665,6 +689,7 @@
C.put_in_hands(new /obj/item/melee/cultblade(user))
C.put_in_hands(new /obj/item/restraints/legcuffs/bola/cult(user))
..()
+ post_cast(target, user, proximity)
/obj/item/melee/blood_magic/manipulator
name = "Ritual Aura"
@@ -693,7 +718,9 @@
H.adjust_integration_blood(uses * 2)
to_chat(user,"You use the last of your blood rites to restore what blood you could!")
uses = 0
- return ..()
+ ..()
+ post_cast(target, user, proximity)
+ return
else
H.blood_volume = (BLOOD_VOLUME_SAFE*H.blood_ratio)
uses -= round(restore_blood/2)
@@ -758,6 +785,7 @@
if(istype(target, /obj/effect/decal/cleanable/blood))
blood_draw(target, user)
..()
+ post_cast()
/obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user)
var/temp = 0
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index 35151953a0..20e41828d4 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -660,40 +660,42 @@
return
if(istype(A, /obj/item))
-
- var/list/cultists = list()
- for(var/datum/mind/M in SSticker.mode.cult)
- if(M.current && M.current.stat != DEAD)
- cultists |= M.current
- var/mob/living/cultist_to_receive = input(user, "Who do you wish to call to [src]?", "Followers of the Geometer") as null|anything in (cultists - user)
- if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated())
- return
- if(!cultist_to_receive)
- to_chat(user, "You require a destination!")
- log_game("Void torch failed - no target")
- return
- if(cultist_to_receive.stat == DEAD)
- to_chat(user, "[cultist_to_receive] has died!")
- log_game("Void torch failed - target died")
- return
- if(!iscultist(cultist_to_receive))
- to_chat(user, "[cultist_to_receive] is not a follower of the Geometer!")
- log_game("Void torch failed - target was deconverted")
- return
- if(A in user.GetAllContents())
- to_chat(user, "[A] must be on a surface in order to teleport it!")
- return
- to_chat(user, "You ignite [A] with \the [src], turning it to ash, but through the torch's flames you see that [A] has reached [cultist_to_receive]!")
- cultist_to_receive.put_in_hands(A)
- charges--
- to_chat(user, "\The [src] now has [charges] charge\s.")
- if(charges == 0)
- qdel(src)
+ transmit_item(A, user, proximity)
else
..()
to_chat(user, "\The [src] can only transport items!")
+/obj/item/flashlight/flare/culttorch/proc/transmit_item(atom/movable/A, mob/user, proximity)
+ set waitfor = FALSE
+ var/list/cultists = list()
+ for(var/datum/mind/M in SSticker.mode.cult)
+ if(M.current && M.current.stat != DEAD)
+ cultists |= M.current
+ var/mob/living/cultist_to_receive = input(user, "Who do you wish to call to [src]?", "Followers of the Geometer") as null|anything in (cultists - user)
+ if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated())
+ return
+ if(!cultist_to_receive)
+ to_chat(user, "You require a destination!")
+ log_game("Void torch failed - no target")
+ return
+ if(cultist_to_receive.stat == DEAD)
+ to_chat(user, "[cultist_to_receive] has died!")
+ log_game("Void torch failed - target died")
+ return
+ if(!iscultist(cultist_to_receive))
+ to_chat(user, "[cultist_to_receive] is not a follower of the Geometer!")
+ log_game("Void torch failed - target was deconverted")
+ return
+ if(A in user.GetAllContents())
+ to_chat(user, "[A] must be on a surface in order to teleport it!")
+ return
+ to_chat(user, "You ignite [A] with \the [src], turning it to ash, but through the torch's flames you see that [A] has reached [cultist_to_receive]!")
+ cultist_to_receive.put_in_hands(A)
+ charges--
+ to_chat(user, "\The [src] now has [charges] charge\s.")
+ if(charges == 0)
+ qdel(src)
/obj/item/cult_spear
name = "blood halberd"
diff --git a/code/modules/mining/fulton.dm b/code/modules/mining/fulton.dm
index 5044a73c10..adee8b66ce 100644
--- a/code/modules/mining/fulton.dm
+++ b/code/modules/mining/fulton.dm
@@ -60,83 +60,86 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
return
if(A.anchored || (A.move_resist > max_force_fulton))
return
- to_chat(user, "You start attaching the pack to [A]...")
- if(do_after(user,50,target=A))
- to_chat(user, "You attach the pack to [A] and activate it.")
- if(loc == user && istype(user.back, /obj/item/storage/backpack))
- var/obj/item/storage/backpack/B = user.back
- SEND_SIGNAL(B, COMSIG_TRY_STORAGE_INSERT, src, user, FALSE, FALSE)
- uses_left--
- if(uses_left <= 0)
- user.transferItemToLoc(src, A, TRUE)
- var/mutable_appearance/balloon
- var/mutable_appearance/balloon2
- var/mutable_appearance/balloon3
- if(isliving(A))
- var/mob/living/M = A
- M.DefaultCombatKnockdown(320) // Keep them from moving during the duration of the extraction
- M.buckled = 0 // Unbuckle them to prevent anchoring problems
- else
- A.anchored = TRUE
- A.density = FALSE
- var/obj/effect/extraction_holder/holder_obj = new(A.loc)
- holder_obj.appearance = A.appearance
- A.forceMove(holder_obj)
- balloon2 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_expand")
- balloon2.pixel_y = 10
- balloon2.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
- holder_obj.add_overlay(balloon2)
- sleep(4)
- balloon = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_balloon")
- balloon.pixel_y = 10
- balloon.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
- holder_obj.cut_overlay(balloon2)
- holder_obj.add_overlay(balloon)
- playsound(holder_obj.loc, 'sound/items/fulext_deploy.wav', 50, 1, -3)
- animate(holder_obj, pixel_z = 10, time = 20)
- sleep(20)
- animate(holder_obj, pixel_z = 15, time = 10)
- sleep(10)
- animate(holder_obj, pixel_z = 10, time = 10)
- sleep(10)
- animate(holder_obj, pixel_z = 15, time = 10)
- sleep(10)
- animate(holder_obj, pixel_z = 10, time = 10)
- sleep(10)
- playsound(holder_obj.loc, 'sound/items/fultext_launch.wav', 50, 1, -3)
- animate(holder_obj, pixel_z = 1000, time = 30)
- if(ishuman(A))
- var/mob/living/carbon/human/L = A
- L.SetUnconscious(0)
- L.drowsyness = 0
- L.SetSleeping(0)
- sleep(30)
- var/list/flooring_near_beacon = list()
- for(var/turf/open/floor in orange(1, beacon))
- flooring_near_beacon += floor
- holder_obj.forceMove(pick(flooring_near_beacon))
- animate(holder_obj, pixel_z = 10, time = 50)
- sleep(50)
- animate(holder_obj, pixel_z = 15, time = 10)
- sleep(10)
- animate(holder_obj, pixel_z = 10, time = 10)
- sleep(10)
- balloon3 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_retract")
- balloon3.pixel_y = 10
- balloon3.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
- holder_obj.cut_overlay(balloon)
- holder_obj.add_overlay(balloon3)
- sleep(4)
- holder_obj.cut_overlay(balloon3)
- A.anchored = FALSE // An item has to be unanchored to be extracted in the first place.
- A.density = initial(A.density)
- animate(holder_obj, pixel_z = 0, time = 5)
- sleep(5)
- A.forceMove(holder_obj.loc)
- qdel(holder_obj)
- if(uses_left <= 0)
- qdel(src)
+ attach_fulton(A, user, flag, params)
+/obj/item/extraction_pack/proc/attach_fulton(atom/movable/A, mob/living/carbon/human/user, flag, params)
+ set waitfor = FALSE
+ to_chat(user, "You start attaching the pack to [A]...")
+ if(do_after(user,50,target=A))
+ to_chat(user, "You attach the pack to [A] and activate it.")
+ if(loc == user && istype(user.back, /obj/item/storage/backpack))
+ var/obj/item/storage/backpack/B = user.back
+ SEND_SIGNAL(B, COMSIG_TRY_STORAGE_INSERT, src, user, FALSE, FALSE)
+ uses_left--
+ if(uses_left <= 0)
+ user.transferItemToLoc(src, A, TRUE)
+ var/mutable_appearance/balloon
+ var/mutable_appearance/balloon2
+ var/mutable_appearance/balloon3
+ if(isliving(A))
+ var/mob/living/M = A
+ M.DefaultCombatKnockdown(320) // Keep them from moving during the duration of the extraction
+ M.buckled = 0 // Unbuckle them to prevent anchoring problems
+ else
+ A.anchored = TRUE
+ A.density = FALSE
+ var/obj/effect/extraction_holder/holder_obj = new(A.loc)
+ holder_obj.appearance = A.appearance
+ A.forceMove(holder_obj)
+ balloon2 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_expand")
+ balloon2.pixel_y = 10
+ balloon2.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
+ holder_obj.add_overlay(balloon2)
+ sleep(4)
+ balloon = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_balloon")
+ balloon.pixel_y = 10
+ balloon.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
+ holder_obj.cut_overlay(balloon2)
+ holder_obj.add_overlay(balloon)
+ playsound(holder_obj.loc, 'sound/items/fulext_deploy.wav', 50, 1, -3)
+ animate(holder_obj, pixel_z = 10, time = 20)
+ sleep(20)
+ animate(holder_obj, pixel_z = 15, time = 10)
+ sleep(10)
+ animate(holder_obj, pixel_z = 10, time = 10)
+ sleep(10)
+ animate(holder_obj, pixel_z = 15, time = 10)
+ sleep(10)
+ animate(holder_obj, pixel_z = 10, time = 10)
+ sleep(10)
+ playsound(holder_obj.loc, 'sound/items/fultext_launch.wav', 50, 1, -3)
+ animate(holder_obj, pixel_z = 1000, time = 30)
+ if(ishuman(A))
+ var/mob/living/carbon/human/L = A
+ L.SetUnconscious(0)
+ L.drowsyness = 0
+ L.SetSleeping(0)
+ sleep(30)
+ var/list/flooring_near_beacon = list()
+ for(var/turf/open/floor in orange(1, beacon))
+ flooring_near_beacon += floor
+ holder_obj.forceMove(pick(flooring_near_beacon))
+ animate(holder_obj, pixel_z = 10, time = 50)
+ sleep(50)
+ animate(holder_obj, pixel_z = 15, time = 10)
+ sleep(10)
+ animate(holder_obj, pixel_z = 10, time = 10)
+ sleep(10)
+ balloon3 = mutable_appearance('icons/obj/fulton_balloon.dmi', "fulton_retract")
+ balloon3.pixel_y = 10
+ balloon3.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
+ holder_obj.cut_overlay(balloon)
+ holder_obj.add_overlay(balloon3)
+ sleep(4)
+ holder_obj.cut_overlay(balloon3)
+ A.anchored = FALSE // An item has to be unanchored to be extracted in the first place.
+ A.density = initial(A.density)
+ animate(holder_obj, pixel_z = 0, time = 5)
+ sleep(5)
+ A.forceMove(holder_obj.loc)
+ qdel(holder_obj)
+ if(uses_left <= 0)
+ qdel(src)
/obj/item/fulton_core
name = "extraction beacon signaller"
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 9a6cd477ad..7aa085f41b 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -2217,9 +2217,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.throw_alert("tempfeel", /atom/movable/screen/alert/cold, 2)
if(-35 to -20)
H.throw_alert("tempfeel", /atom/movable/screen/alert/cold, 1)
- if(-20 to 0) //This is the sweet spot where air is considered normal
+ if(-20 to 1) //This is the sweet spot where air is considered normal
H.clear_alert("tempfeel")
- if(0 to 15) //When the air around you matches your body's temperature, you'll start to feel warm.
+ if(1 to 15) //When the air around you matches your body's temperature, you'll start to feel warm.
H.throw_alert("tempfeel", /atom/movable/screen/alert/hot, 1)
if(15 to 30)
H.throw_alert("tempfeel", /atom/movable/screen/alert/hot, 2)
diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm
index ddeef393ac..71bc1020e2 100644
--- a/code/modules/movespeed/modifiers/mobs.dm
+++ b/code/modules/movespeed/modifiers/mobs.dm
@@ -15,6 +15,7 @@
/datum/movespeed_modifier/hunger
variable = TRUE
+ blacklisted_movetypes = FLOATING|FLYING
/datum/movespeed_modifier/slaughter
multiplicative_slowdown = -1
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index b4f1acbed4..41e22de9e6 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -148,6 +148,10 @@
/obj/item/pen/afterattack(obj/O, mob/living/user, proximity)
. = ..()
//Changing name/description of items. Only works if they have the UNIQUE_RENAME object flag set
+ try_modify_object(O, user, proximity)
+
+/obj/item/pen/proc/try_modify_object(obj/O, mob/living/user, proximity)
+ set waitfor = FALSE
if(isobj(O) && proximity && (O.obj_flags & UNIQUE_RENAME))
var/penchoice = input(user, "What would you like to edit?", "Rename, change description or reset both?") as null|anything in list("Rename","Change description","Reset")
if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE))
diff --git a/code/modules/pool/pool_controller.dm b/code/modules/pool/pool_controller.dm
index 142690566b..ff52fb9fef 100644
--- a/code/modules/pool/pool_controller.dm
+++ b/code/modules/pool/pool_controller.dm
@@ -235,10 +235,10 @@
if(POOL_SCALDING) //Scalding
M.adjust_bodytemperature(50,0,500)
if(POOL_WARM) //Warm
- M.adjust_bodytemperature(20,0,360) //Heats up mobs till the thermometer shows up
+ M.adjust_bodytemperature(20,0,323.15) //Heats up mobs till the thermometer shows up
//Normal temp does nothing, because it's just room temperature water.
if(POOL_COOL)
- M.adjust_bodytemperature(-20,250) //Cools mobs till the thermometer shows up
+ M.adjust_bodytemperature(-20,274.15) //Cools mobs till the thermometer shows up
if(POOL_FRIGID) //Freezing
M.adjust_bodytemperature(-60) //cool mob at -35k per cycle, less would not affect the mob enough.
if(M.bodytemperature <= 50 && !M.stat)
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 70cd28718c..9bf794a0a2 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -735,7 +735,10 @@
if(jb)
to_chat(user, "Your mind goes blank as you attempt to use the potion.")
return
+ try_transfer_mind(SM, user)
+/obj/item/slimepotion/transference/proc/try_transfer_mind(mob/living/simple_animal/SM, mob/user)
+ set waitfor = FALSE
prompted = 1
if(alert("This will permanently transfer your consciousness to [SM]. Are you sure you want to do this?",,"Yes","No")=="No")
prompted = 0
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index 553cc2d043..2b212bd224 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -223,7 +223,6 @@
var/alert_type = null
if(ispath(breathing_class))
breathing_class = breathing_classes[breathing_class]
- var/list/gases = breathing_class.gases
alert_category = breathing_class.high_alert_category
alert_type = breathing_class.high_alert_datum
danger_reagent = breathing_class.danger_reagent
diff --git a/html/changelog.html b/html/changelog.html
index f1834a647e..b1f30d9e83 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -50,6 +50,40 @@
-->
+
11 December 2021
+
SandPoot updated:
+
+ - Borg speech is now centralized even inside lockers or something like that.
+
+
bunny232 updated:
+
+ - Cold blooded critters won't worry too much about the air around them being too hot even though their body temperature is the same as it.
+ - The warm pool is no longer nearly boiling and the cool pool no longer goes below 0C.
+
+
+
09 December 2021
+
DeltaFire15 updated:
+
+ - Linters should no longer scream.
+
+
Linzolle updated:
+
+ - it now only snows on festivestation instead of every map
+ - rain now triggers properly on spookystation
+
+
TripleShades updated:
+
+ - (Pubby) Gives Robotic's Lab Surgery a cautery
+
+
keronshb updated:
+
+ - Lets dynamic pick clock cultists midround
+
+
timothyteakettle updated:
+
+ - being fat no longer makes you slower when floating
+
+
05 December 2021
Arturlang updated:
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 7be04803a8..fd720bcc02 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -30372,3 +30372,23 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
DeltaFire15:
- bugfix: Fireman carry no longer drops the carried person if passing over a prone
individual.
+2021-12-09:
+ DeltaFire15:
+ - bugfix: Linters should no longer scream.
+ Linzolle:
+ - bugfix: it now only snows on festivestation instead of every map
+ - bugfix: rain now triggers properly on spookystation
+ TripleShades:
+ - rscadd: (Pubby) Gives Robotic's Lab Surgery a cautery
+ keronshb:
+ - rscadd: Lets dynamic pick clock cultists midround
+ timothyteakettle:
+ - bugfix: being fat no longer makes you slower when floating
+2021-12-11:
+ SandPoot:
+ - bugfix: Borg speech is now centralized even inside lockers or something like that.
+ bunny232:
+ - bugfix: Cold blooded critters won't worry too much about the air around them being
+ too hot even though their body temperature is the same as it.
+ - balance: The warm pool is no longer nearly boiling and the cool pool no longer
+ goes below 0C.
diff --git a/html/changelogs/AutoChangeLog-pr-15417.yml b/html/changelogs/AutoChangeLog-pr-15417.yml
deleted file mode 100644
index 2008aeafa8..0000000000
--- a/html/changelogs/AutoChangeLog-pr-15417.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "DeltaFire15"
-delete-after: True
-changes:
- - bugfix: "Linters should no longer scream."
diff --git a/html/changelogs/AutoChangeLog-pr-15421.yml b/html/changelogs/AutoChangeLog-pr-15421.yml
new file mode 100644
index 0000000000..ffc347c20e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-15421.yml
@@ -0,0 +1,4 @@
+author: "DeltaFire15"
+delete-after: True
+changes:
+ - bugfix: "Linters should no longer complain about afterattack sleeps."
diff --git a/modular_citadel/code/modules/eventmaps/Spookystation/JTGSZwork.dm b/modular_citadel/code/modules/eventmaps/Spookystation/JTGSZwork.dm
index 98ca2005dc..8143380262 100644
--- a/modular_citadel/code/modules/eventmaps/Spookystation/JTGSZwork.dm
+++ b/modular_citadel/code/modules/eventmaps/Spookystation/JTGSZwork.dm
@@ -483,7 +483,8 @@
end_message = "The downpour gradually slows until it stops."
area_type = /area/eventmap/outside
- target_trait = ZTRAIT_STATION
+ target_trait = ZTRAIT_LONGRAIN
+ probability = 90
barometer_predictable = TRUE