diff --git a/code/game/gamemodes/vampire/vampire_helpers.dm b/code/game/gamemodes/vampire/vampire_helpers.dm
index a0cac794841..8665bc475d3 100644
--- a/code/game/gamemodes/vampire/vampire_helpers.dm
+++ b/code/game/gamemodes/vampire/vampire_helpers.dm
@@ -76,7 +76,7 @@
if (!mind.vampire)
return 0
- if ((mind.vampire.status & VAMP_FULLPOWER) && !(T.mind.vampire && (T.mind.vampire.status & VAMP_FULLPOWER)))
+ if ((mind.vampire.status & VAMP_FULLPOWER) && !(T.mind && T.mind.vampire && (T.mind.vampire.status & VAMP_FULLPOWER)))
return 1
if (T.mind)
@@ -179,13 +179,9 @@
if (next_alert && message)
if (!vampire.last_frenzy_message || vampire.last_frenzy_message + next_alert < world.time)
- to_chat(usr, message)
+ to_chat(src, message)
vampire.last_frenzy_message = world.time
- // Remove one point per every life() tick.
- if (vampire.frenzy > 0)
- vampire.frenzy--
-
/mob/proc/vampire_start_frenzy(var/force_frenzy = 0)
var/datum/vampire/vampire = mind.vampire
@@ -243,6 +239,10 @@
if (mind.vampire.blood_usable < 10)
mind.vampire.frenzy += 2
+ else if (mind.vampire.frenzy > 0)
+ mind.vampire.frenzy = max(0, mind.vampire.frenzy -= Clamp(mind.vampire.blood_usable * 0.1, 1, 10))
+
+ mind.vampire.frenzy = min(mind.vampire.frenzy, 450)
vampire_check_frenzy()
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index 85744c8c9d9..ebe85b020f7 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -247,19 +247,19 @@
if(occupant.client)
occupant.client.eye = occupant.client.mob
occupant.client.perspective = MOB_PERSPECTIVE
- occupant.loc = loc
+ occupant.forceMove(loc)
occupant = null
- for(var/atom/movable/A in src) // In case an object was dropped inside or something
+ for(var/atom/movable/A in (contents - component_parts)) // In case an object was dropped inside or something
if(A == beaker)
continue
- A.loc = loc
+ A.forceMove(loc)
update_use_power(1)
update_icon()
toggle_filter()
/obj/machinery/sleeper/proc/remove_beaker()
if(beaker)
- beaker.loc = loc
+ beaker.forceMove(loc)
beaker = null
toggle_filter()
diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm
index 4077a7da9c7..046fff12588 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -53,6 +53,12 @@ var/const/HOLOPAD_MODE = RANGE_BASED
var/obj/machinery/hologram/holopad/targetpad
var/last_message
+/obj/machinery/hologram/holopad/check_eye(mob/user)
+ if (user && user == caller_id)
+ return 0
+
+ return -1
+
/obj/machinery/hologram/holopad/attack_hand(var/mob/living/carbon/human/user) //Carn: Hologram requests.
if(!istype(user))
return
@@ -109,8 +115,9 @@ var/const/HOLOPAD_MODE = RANGE_BASED
/obj/machinery/hologram/holopad/proc/take_call(mob/living/carbon/user)
incoming_connection = 0
+ caller_id.set_machine(src)
caller_id.reset_view(src)
- if(!masters[caller_id])//If there is no hologram, possibly make one.
+ if(!masters[caller_id]) //If there is no hologram, possibly make one.
activate_holocall(caller_id)
/obj/machinery/hologram/holopad/proc/end_call(mob/user)
@@ -119,19 +126,21 @@ var/const/HOLOPAD_MODE = RANGE_BASED
caller_id.reset_view() //Send the caller back to his body
clear_holo(null, caller_id) // destroy the hologram
caller_id = null
+
if(user)
user.unset_machine()
user.reset_view() //Send the caller back to his body
clear_holo(null, user) // destroy the hologram
user = null
+
/obj/machinery/hologram/holopad/proc/activate_holocall(mob/living/carbon/caller_id)
if(caller_id)
- create_holo(0,caller_id)//Create one.
- src.visible_message("A holographic image of [caller_id] flicks to life right before your eyes!")
+ create_holo(0, caller_id)//Create one.
+ visible_message("A holographic image of [caller_id] flicks to life right before your eyes!")
else
to_chat(caller_id, "ERROR: Unable to project hologram.")
return
-
+
/obj/machinery/hologram/holopad/attack_ai(mob/living/silicon/ai/user)
if (!istype(user))
return
@@ -223,16 +232,14 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(hacked == 0)
var/obj/effect/overlay/hologram = new(T)//Spawn a blank effect at the location.
if(caller_id)
- var/tempicon = 0
- for(var/datum/data/record/t in data_core.locked)
- if(t.fields["name"] == caller_id.name)
- tempicon = t.fields["image"]
+ var/tempicon = getFlatIcon(caller_id)
+
hologram.name = "[caller_id.name] (Hologram)"
hologram.loc = get_step(src,1)
masters[caller_id] = hologram
- add_overlay(getHologramIcon(icon(tempicon))) // Add the callers image as an overlay to keep coloration!
+ hologram.icon = getHologramIcon(icon(tempicon)) // Add the callers image as an overlay to keep coloration!
else
- add_overlay(A.holo_icon) // Add the AI's configured holo Icon
+ hologram.icon = A.holo_icon // Add the AI's configured holo Icon
hologram.name = "[A.name] (Hologram)"//If someone decides to right click.
A.holo = src
masters[A] = hologram
@@ -253,14 +260,14 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
A.holo = src
return 1
-/obj/machinery/hologram/holopad/proc/clear_holo(mob/living/silicon/ai/user, mob/living/carbon/caller_id)
+/obj/machinery/hologram/holopad/proc/clear_holo(mob/living/silicon/ai/user, mob/living/carbon/call_user)
if(user)
qdel(masters[user])//Get rid of user's hologram
user.holo = null
masters -= user //Discard AI from the list of those who use holopad
- if(caller_id)
- qdel(masters[caller_id])//Get rid of user's hologram
- masters -= caller_id //Discard the caller from the list of those who use holopad
+ if(call_user)
+ qdel(masters[call_user]) //Get rid of user's hologram
+ masters -= call_user //Discard the caller from the list of those who use holopad
if (!masters.len)//If no users left
set_light(0) //pad lighting (hologram lighting will be handled automatically since its owner was deleted)
icon_state = "holopad0"
@@ -289,7 +296,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
sourcepad.audible_message("The holopad connection timed out")
sourcepad = 0
if (caller_id && sourcepad)
- if(caller_id.loc!=sourcepad.loc)
+ if(caller_id.loc != sourcepad.loc)
sourcepad.visible_message("Severing connection to distant holopad.")
visible_message("The connection has been terminated by [caller_id].")
end_call()
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 21cae21a1a3..5c4bd313291 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -114,13 +114,15 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images
if(istype(target))
ManualFollow(target)
-/mob/dead/observer/proc/initialise_postkey()
+/mob/dead/observer/proc/initialise_postkey(set_timers = TRUE)
//This function should be run after a ghost has been created and had a ckey assigned
+ if (!set_timers)
+ return
//Death times are initialised if they were unset
//get/set death_time functions are in mob_helpers.dm
if (!get_death_time(ANIMAL))
- set_death_time(ANIMAL, world.time - RESPAWN_ANIMAL)//allow instant mouse spawning
+ set_death_time(ANIMAL, world.time - RESPAWN_ANIMAL) //allow instant mouse spawning
if (!get_death_time(MINISYNTH))
set_death_time(MINISYNTH, world.time - RESPAWN_MINISYNTH) //allow instant drone spawning
if (!get_death_time(CREW))
@@ -174,25 +176,15 @@ Works together with spawning an observer, noted above.
C.images += target.hud_list[SPECIALROLE_HUD]
return 1
-/mob/proc/ghostize(var/can_reenter_corpse = 1, var/should_set_timer = 1)
+/mob/proc/ghostize(var/can_reenter_corpse = TRUE, var/should_set_timer = TRUE)
if(ckey)
var/mob/dead/observer/ghost = new(src) //Transfer safety to observer spawning proc.
ghost.can_reenter_corpse = can_reenter_corpse
ghost.timeofdeath = src.stat == DEAD ? src.timeofdeath : world.time
- if(should_set_timer)
- //This is duplicated for robustness in cases where death might not be called.
- //It is also set in the mob/death proc
- if (isanimal(src))
- set_death_time(ANIMAL, world.time)
- else if (ispAI(src) || isDrone(src))
- set_death_time(MINISYNTH, world.time)
- else
- set_death_time(CREW, world.time)//Crew is the fallback
-
ghost.ckey = ckey
ghost.client = client
- ghost.initialise_postkey()
+ ghost.initialise_postkey(should_set_timer)
if(ghost.client)
if(!ghost.client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed.
ghost.verbs -= /mob/dead/observer/verb/toggle_antagHUD // Poor guys, don't know what they are missing!
diff --git a/code/modules/mob/living/bot/medbot.dm b/code/modules/mob/living/bot/medbot.dm
index bd30db99b54..300c7d7788e 100644
--- a/code/modules/mob/living/bot/medbot.dm
+++ b/code/modules/mob/living/bot/medbot.dm
@@ -353,7 +353,7 @@
var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN)
if(!t)
return
- if(!in_range(src, usr) && loc != usr)
+ if(!in_range(src, user) && loc != user)
return
created_name = t
else
diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm
index 89b02b03b85..aa3907d9997 100644
--- a/code/modules/mob/living/silicon/robot/inventory.dm
+++ b/code/modules/mob/living/silicon/robot/inventory.dm
@@ -253,11 +253,11 @@
G = module_state_1
if (!G.wrapped && G.grip_item(W, src, 1))
return 1
- if (istype(module_state_2, /obj/item/weapon/gripper))
+ else if (istype(module_state_2, /obj/item/weapon/gripper))
G = module_state_2
if (!G.wrapped && G.grip_item(W, src, 0))
return 1
- if (istype(module_state_2, /obj/item/weapon/gripper))
+ else if (istype(module_state_3, /obj/item/weapon/gripper))
G = module_state_3
if (!G.wrapped && G.grip_item(W, src, 0))
return 1
@@ -292,4 +292,4 @@
return 1
if (I.loc != src)
return 1//Allows objects inside grippers
- return 0//don't allow dropping our modules
\ No newline at end of file
+ return 0//don't allow dropping our modules
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 0766010e911..54dd0ce0e1b 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -482,7 +482,12 @@
announce_ghost_joinleave(client, 0)
+ // Run this here to null out death timers for the next go.
+
var/mob/new_player/M = new /mob/new_player()
+
+ M.reset_death_timers()
+
if(!client)
log_game("[usr.key] AM failed due to disconnect.",ckey=key_name(usr))
qdel(M)
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 7ad6b85acb3..532837e1db9 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -991,6 +991,26 @@ proc/is_blind(A)
P.time_of_death[which] = value
return 1
+/**
+ * Resets death timers for a mob. Should only be called during new player creation.
+ */
+/mob/proc/reset_death_timers()
+ var/datum/preferences/P
+ if (client)
+ P = client.prefs
+ else if (ckey)
+ // To avoid runtimes during adminghost.
+ if (copytext(ckey, 1, 2) == "@")
+ P = preferences_datums[copytext(ckey, 2)]
+ else
+ P = preferences_datums[ckey]
+ else
+ return
+
+ if (!P)
+ return
+
+ P.time_of_death.Cut()
//Below here is stuff related to devouring, but which is generally helpful and thus placed here
//See Devour.dm for more info in how these are used
@@ -1045,7 +1065,7 @@ proc/is_blind(A)
"donor" = WEAKREF(src),
"viruses" = null,
"species" = name,
- "blood_DNA" = md5("\ref[src]"),
+ "blood_DNA" = md5("\ref[src]"),
"blood_colour" = "#a10808",
"blood_type" = null,
"resistances" = null,
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
index 73a6ff4074e..beb9d75a06c 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
@@ -549,6 +549,8 @@
slime_temp_adj = 15
/datum/reagent/capsaicin/condensed/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
+#define EYES_PROTECTED 1
+#define EYES_MECH 2
var/eyes_covered = 0
var/mouth_covered = 0
var/no_pain = 0
@@ -563,13 +565,18 @@
protection = list(H.head, H.glasses, H.wear_mask)
if(H.species && (H.species.flags & NO_PAIN))
no_pain = 1 //TODO: living-level can_feel_pain() proc
+
+ // Robo-eyes are immune to pepperspray now. Wee.
+ var/obj/item/organ/eyes/E = H.get_eyes()
+ if (istype(E) && (E.status & (ORGAN_ROBOT|ORGAN_ADV_ROBOT)))
+ eyes_covered |= EYES_MECH
else
protection = list(M.wear_mask)
for(var/obj/item/I in protection)
if(I)
if(I.body_parts_covered & EYES)
- eyes_covered = 1
+ eyes_covered |= EYES_PROTECTED
eye_protection = I.name
if((I.body_parts_covered & FACE) && !(I.item_flags & FLEXIBLEMATERIAL))
mouth_covered = 1
@@ -577,8 +584,10 @@
var/message = null
if(eyes_covered)
- if(!mouth_covered)
+ if (!mouth_covered && (eyes_covered & EYES_PROTECTED))
message = "Your [eye_protection] protects your eyes from the pepperspray!"
+ else if (eyes_covered & EYES_MECH)
+ message = "Your mechanical eyes are invulnurable pepperspray!"
else
message = "The pepperspray gets in your eyes!"
if(mouth_covered)
@@ -597,6 +606,8 @@
M.custom_emote(2, "[pick("coughs!","coughs hysterically!","splutters!")]")
M.Stun(5)
M.Weaken(5)
+#undef EYES_PROTECTED
+#undef EYES_MECH
/datum/reagent/condensedcapsaicin/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
if(ishuman(M))
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index a67377e62ac..e577603fd55 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -73,7 +73,7 @@
/obj/item/weapon/reagent_containers/spray/proc/Spray_at(atom/A as mob|obj, mob/user as mob, proximity)
if (A.density && proximity)
- A.visible_message("[usr] sprays [A] with [src].")
+ A.visible_message("[user] sprays [A] with [src].")
reagents.splash(A, amount_per_transfer_from_this)
else
spawn(0)
@@ -157,12 +157,12 @@
/obj/item/weapon/reagent_containers/spray/pepper/attack_self(var/mob/user)
safety = !safety
- usr << "You switch the safety [safety ? "on" : "off"]."
+ user << "You switch the safety [safety ? "on" : "off"]."
playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
-/obj/item/weapon/reagent_containers/spray/pepper/Spray_at(atom/A as mob|obj)
+/obj/item/weapon/reagent_containers/spray/pepper/Spray_at(atom/A as mob|obj, mob/user)
if(safety)
- usr << "The safety is on!"
+ user << "The safety is on!"
return
..()
diff --git a/code/modules/spells/aoe_turf/conjure/druidic_spells.dm b/code/modules/spells/aoe_turf/conjure/druidic_spells.dm
index cec585c0cb6..dfc1c9f0e79 100644
--- a/code/modules/spells/aoe_turf/conjure/druidic_spells.dm
+++ b/code/modules/spells/aoe_turf/conjure/druidic_spells.dm
@@ -24,7 +24,7 @@
charge_max = 300
invocation = "Bla'yo daya!"
invocation_type = SpI_SHOUT
- level_max = list(Sp_TOTAL = 3, Sp_SPEED = 3, Sp_POWER = 3)
+ level_max = list(Sp_TOTAL = 3, Sp_SPEED = 4, Sp_POWER = 3)
range = 1
diff --git a/code/modules/virus2/dishincubator.dm b/code/modules/virus2/dishincubator.dm
index d6db4d4c2fc..b2e15414263 100644
--- a/code/modules/virus2/dishincubator.dm
+++ b/code/modules/virus2/dishincubator.dm
@@ -137,10 +137,10 @@
SSnanoui.update_uis(src)
- if (locate(/datum/reagent/toxin) in beaker.reagents.reagent_list && toxins < 100)
+ if ((locate(/datum/reagent/toxin) in beaker.reagents.reagent_list) && toxins < 100)
for(var/datum/reagent/toxin/T in beaker.reagents.reagent_list)
toxins += max(T.strength,1)
- beaker.reagents.remove_reagent(T.id,1)
+ beaker.reagents.remove_reagent(T.id, 1)
if(toxins > 100)
toxins = 100
break
diff --git a/html/changelogs/skull132_bonanza.yml b/html/changelogs/skull132_bonanza.yml
new file mode 100644
index 00000000000..e40dce79e12
--- /dev/null
+++ b/html/changelogs/skull132_bonanza.yml
@@ -0,0 +1,14 @@
+author: Skull132
+delete-after: True
+
+changes:
+ - bugfix: "Sleepers will no longer jettison their stored components when you exit them."
+ - bugfix: "Vampires approaching frenzy will now get their appropriate messages again."
+ - balance: "For vampires: capped the maximum time you can accumulate for frenzy. And having more blood will now reduce frenzy faster: the more humans you succ dry, the faster you become human again!"
+ - bugfix: "Fixed a runtime in robot/put_in_hands, which bugged out numerous gripper interactions. To include building robots as a science borg."
+ - bugfix: "Toxins can now be added to the pathogenic dish incubator again."
+ - balance: "Robotic eyes (not assisted ones!) are now partially immune to pepperspray effects. Because robots."
+ - bugfix: "Death timers no longer reset if you re-enter your corpse."
+ - bugfix: "Holocall fixes: icons are generated properly, caller view is moved properly, icons are cleaned up properly, AI interaction is now fine."
+ - imageadd: "Added a second lobby screen, courtesy of NursieKitty and Zelm."
+ - tweak: "Wizards can no longer upgrade spacebats into an instant-summon. The ability to spam mobs is bad ju-ju."
diff --git a/icons/misc/title.dmi b/icons/misc/title.dmi
index ef874221976..7fdcaf43ddb 100644
Binary files a/icons/misc/title.dmi and b/icons/misc/title.dmi differ