From 5232728ee747832bd31c71f98e871868ce481525 Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Mon, 7 Oct 2019 05:25:47 +0200
Subject: [PATCH 001/144] Ports "Adds three new .38 ammo types", also lazily
adding .357 AP
---
code/game/machinery/computer/teleporter.dm | 4 +-
.../objects/items/implants/implant_track.dm | 16 +++++-
code/game/objects/items/teleportation.dm | 2 +-
.../ammunition/ballistic/revolver.dm | 26 +++++++++-
.../projectiles/boxes_magazines/ammo_boxes.dm | 21 ++++++++
.../projectile/bullets/revolver.dm | 49 +++++++++++++++++--
.../research/designs/weapon_designs.dm | 30 ++++++++++++
code/modules/research/techweb/all_nodes.dm | 12 ++---
code/modules/uplink/uplink_items.dm | 8 ++-
9 files changed, 151 insertions(+), 17 deletions(-)
diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm
index b9b95eecd0..9e0bea08ab 100644
--- a/code/game/machinery/computer/teleporter.dm
+++ b/code/game/machinery/computer/teleporter.dm
@@ -124,12 +124,12 @@
L[avoid_assoc_duplicate_keys(A.name, areaindex)] = R
for(var/obj/item/implant/tracking/I in GLOB.tracked_implants)
- if(!I.imp_in || !isliving(I.loc))
+ if(!I.imp_in || !isliving(I.loc) || !I.allow_teleport)
continue
else
var/mob/living/M = I.loc
if(M.stat == DEAD)
- if(M.timeofdeath + 6000 < world.time)
+ if(M.timeofdeath + I.lifespan_postmortem < world.time)
continue
if(is_eligible(I))
L[avoid_assoc_duplicate_keys(M.real_name, areaindex)] = I
diff --git a/code/game/objects/items/implants/implant_track.dm b/code/game/objects/items/implants/implant_track.dm
index 913c577f2c..fc7539af9e 100644
--- a/code/game/objects/items/implants/implant_track.dm
+++ b/code/game/objects/items/implants/implant_track.dm
@@ -1,7 +1,19 @@
/obj/item/implant/tracking
name = "tracking implant"
desc = "Track with this."
- activated = 0
+ activated = FALSE
+ var/lifespan_postmortem = 6000 //for how many deciseconds after user death will the implant work?
+ var/allow_teleport = TRUE //will people implanted with this act as teleporter beacons?
+
+/obj/item/implant/tracking/c38
+ name = "TRAC implant"
+ desc = "A smaller tracking implant that supplies power for only a few minutes."
+ var/lifespan = 3000 //how many deciseconds does the implant last?
+ allow_teleport = FALSE
+
+/obj/item/implant/tracking/c38/Initialize()
+ . = ..()
+ QDEL_IN(src, lifespan)
/obj/item/implant/tracking/New()
..()
@@ -21,7 +33,7 @@
var/dat = {"Implant Specifications:
Name: Tracking Beacon
Life: 10 minutes after death of host
- Important Notes: None
+ Important Notes: Implant also works as a teleporter beacon.
Implant Details:
Function: Continuously transmits low power signal. Useful for tracking.
diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm
index 1ccc88d892..da806908df 100644
--- a/code/game/objects/items/teleportation.dm
+++ b/code/game/objects/items/teleportation.dm
@@ -80,7 +80,7 @@
else
var/mob/living/M = W.loc
if (M.stat == DEAD)
- if (M.timeofdeath + 6000 < world.time)
+ if (M.timeofdeath + W.lifespan_postmortem < world.time)
continue
var/turf/tr = get_turf(W)
diff --git a/code/modules/projectiles/ammunition/ballistic/revolver.dm b/code/modules/projectiles/ammunition/ballistic/revolver.dm
index b45d01d7d8..6232ca4d69 100644
--- a/code/modules/projectiles/ammunition/ballistic/revolver.dm
+++ b/code/modules/projectiles/ammunition/ballistic/revolver.dm
@@ -6,6 +6,11 @@
caliber = "357"
projectile_type = /obj/item/projectile/bullet/a357
+/obj/item/ammo_casing/a357/ap
+ name = ".357 armor-piercing bullet casing"
+ desc = "A .357 armor-piercing bullet casing."
+ projectile_type = /obj/item/projectile/bullet/a357/ap
+
// 7.62x38mmR (Nagant Revolver)
/obj/item/ammo_casing/n762
@@ -20,9 +25,26 @@
name = ".38 rubber bullet casing"
desc = "A .38 rubber bullet casing."
caliber = "38"
- projectile_type = /obj/item/projectile/bullet/c38
+ projectile_type = /obj/item/projectile/bullet/c38/rubber
/obj/item/ammo_casing/c38/lethal
name = ".38 bullet casing"
desc = "A .38 bullet casing"
- projectile_type = /obj/item/projectile/bullet/c38lethal
+ projectile_type = /obj/item/projectile/bullet/c38
+
+/obj/item/ammo_casing/c38/trac
+ name = ".38 TRAC bullet casing"
+ desc = "A .38 \"TRAC\" bullet casing."
+ projectile_type = /obj/item/projectile/bullet/c38/trac
+
+/obj/item/ammo_casing/c38/hotshot
+ name = ".38 Hot Shot bullet casing"
+ desc = "A .38 Hot Shot bullet casing."
+ caliber = "38"
+ projectile_type = /obj/item/projectile/bullet/c38/hotshot
+
+/obj/item/ammo_casing/c38/iceblox
+ name = ".38 Iceblox bullet casing"
+ desc = "A .38 Iceblox bullet casing."
+ caliber = "38"
+ projectile_type = /obj/item/projectile/bullet/c38/iceblox
\ No newline at end of file
diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
index 7cd27e8592..ba6a8e2454 100644
--- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
+++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
@@ -3,13 +3,19 @@
desc = "Designed to quickly reload revolvers."
icon_state = "357"
ammo_type = /obj/item/ammo_casing/a357
+ caliber = "357"
max_ammo = 7
multiple_sprites = 1
+/obj/item/ammo_box/a357/ap
+ name = "speed loader (.357 AP)"
+ ammo_type = /obj/item/ammo_casing/a357/ap
+
/obj/item/ammo_box/c38
name = "speed loader (.38 rubber)"
desc = "Designed to quickly reload revolvers."
icon_state = "38"
+ caliber = "38"
ammo_type = /obj/item/ammo_casing/c38
max_ammo = 6
multiple_sprites = 1
@@ -19,6 +25,21 @@
name = "speed loader (.38)"
ammo_type = /obj/item/ammo_casing/c38/lethal
+/obj/item/ammo_box/c38/trac
+ name = "speed loader (.38 TRAC)"
+ desc = "Designed to quickly reload revolvers. TRAC bullets embed a tracking implant within the target's body."
+ ammo_type = /obj/item/ammo_casing/c38/trac
+
+/obj/item/ammo_box/c38/hotshot
+ name = "speed loader (.38 Hot Shot)"
+ desc = "Designed to quickly reload revolvers. Hot Shot bullets contain an incendiary payload."
+ ammo_type = /obj/item/ammo_casing/c38/hotshot
+
+/obj/item/ammo_box/c38/iceblox
+ name = "speed loader (.38 Iceblox)"
+ desc = "Designed to quickly reload revolvers. Iceblox bullets contain a cryogenic payload."
+ ammo_type = /obj/item/ammo_casing/c38/iceblox
+
/obj/item/ammo_box/c9mm
name = "ammo box (9mm)"
icon_state = "9mmbox"
diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm
index d3af474d76..3bbfe437fe 100644
--- a/code/modules/projectiles/projectile/bullets/revolver.dm
+++ b/code/modules/projectiles/projectile/bullets/revolver.dm
@@ -13,16 +13,59 @@
// .38 (Detective's Gun)
/obj/item/projectile/bullet/c38
+ name = ".38 bullet"
+ damage = 25
+
+/obj/item/projectile/bullet/c38/rubber
name = ".38 rubber bullet"
damage = 15
stamina = 48
-/obj/item/projectile/bullet/c38lethal
- name = ".38 bullet"
- damage = 25
+/obj/item/projectile/bullet/c38/trac
+ name = ".38 TRAC bullet"
+ damage = 10
+
+/obj/item/projectile/bullet/c38/trac/on_hit(atom/target, blocked = FALSE)
+ . = ..()
+ var/mob/living/carbon/M = target
+ var/obj/item/implant/tracking/c38/imp
+ for(var/obj/item/implant/tracking/c38/TI in M.implants) //checks if the target already contains a tracking implant
+ imp = TI
+ return
+ if(!imp)
+ imp = new /obj/item/implant/tracking/c38(M)
+ imp.implant(M)
+
+/obj/item/projectile/bullet/c38/hotshot //similar to incendiary bullets, but do not leave a flaming trail
+ name = ".38 Hot Shot bullet"
+ damage = 20
+
+/obj/item/projectile/bullet/c38/hotshot/on_hit(atom/target, blocked = FALSE)
+ . = ..()
+ if(iscarbon(target))
+ var/mob/living/carbon/M = target
+ M.adjust_fire_stacks(6)
+ M.IgniteMob()
+
+/obj/item/projectile/bullet/c38/iceblox //see /obj/item/projectile/temp for the original code
+ name = ".38 Iceblox bullet"
+ damage = 20
+ var/temperature = 100
+
+/obj/item/projectile/bullet/c38/iceblox/on_hit(atom/target, blocked = FALSE)
+ . = ..()
+ if(isliving(target))
+ var/mob/living/M = target
+ M.adjust_bodytemperature(((100-blocked)/100)*(temperature - M.bodytemperature))
+
// .357 (Syndie Revolver)
/obj/item/projectile/bullet/a357
name = ".357 bullet"
damage = 60
+
+/obj/item/projectile/bullet/a357/ap
+ name = ".357 armor-piercing bullet"
+ damage = 45
+ armour_penetration = 45
\ No newline at end of file
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index 214ef36afe..7dd85ea18c 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -17,6 +17,36 @@
id = "sec_38lethal"
build_path = /obj/item/ammo_box/c38/lethal
+/datum/design/c38_trac
+ name = "Speed Loader (.38 TRAC)"
+ desc = "Designed to quickly reload revolvers. TRAC bullets embed a tracking implant within the target's body."
+ id = "c38_trac"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 20000, MAT_SILVER = 5000, MAT_GOLD = 1000)
+ build_path = /obj/item/ammo_box/c38/trac
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/c38_hotshot
+ name = "Speed Loader (.38 Hot Shot)"
+ desc = "Designed to quickly reload revolvers. Hot Shot bullets contain an incendiary payload."
+ id = "c38_hotshot"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 20000, MAT_PLASMA = 5000)
+ build_path = /obj/item/ammo_box/c38/hotshot
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/c38_iceblox
+ name = "Speed Loader (.38 Iceblox)"
+ desc = "Designed to quickly reload revolvers. Iceblox bullets contain a cryogenic payload."
+ id = "c38_iceblox"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 20000, MAT_PLASMA = 5000)
+ build_path = /obj/item/ammo_box/c38/iceblox
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
//////////////
//WT550 Mags//
//////////////
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 038a41b3cd..5a2493184f 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -508,7 +508,7 @@
display_name = "Subdermal Implants"
description = "Electronic implants buried beneath the skin."
prereq_ids = list("biotech", "datatheory")
- design_ids = list("implanter", "implantcase", "implant_chem", "implant_tracking", "locator")
+ design_ids = list("implanter", "implantcase", "implant_chem", "implant_tracking", "locator", "c38_trac")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -676,12 +676,12 @@
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2750)
export_price = 5000
-/datum/techweb_node/tech_shell
- id = "tech_shell"
- display_name = "Technological Shells"
- description = "They're more technological than regular shot."
+/datum/techweb_node/exotic_ammo
+ id = "exotic_ammo"
+ display_name = "Exotic Ammunition"
+ description = "They won't know what hit em."
prereq_ids = list("weaponry", "ballistic_weapons")
- design_ids = list("techshotshell")
+ design_ids = list("techshotshell", "c38_hotshot", "c38_iceblox")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500)
export_price = 5000
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 09e955d2f9..3b51b7c9a0 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -767,9 +767,15 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
desc = "A speed loader that contains seven additional .357 Magnum rounds; usable with the Syndicate revolver. \
For when you really need a lot of things dead."
item = /obj/item/ammo_box/a357
- cost = 4
+ cost = 3
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
+/datum/uplink_item/ammo/revolver/ap
+ name = ".357 Armor Piercing Speed Loader"
+ desc = "A speed loader that contains seven additional .357 AP Magnum rounds; usable with the Syndicate revolver. \
+ Cuts through like a hot knife through butter."
+ item = /obj/item/ammo_box/a357/ap
+
/datum/uplink_item/ammo/a40mm
name = "40mm Grenade"
desc = "A 40mm HE grenade for use with the M-90gl's under-barrel grenade launcher. \
From b95f910a4e8d8a076bceca5de3573cd3a5512e3d Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Mon, 7 Oct 2019 17:32:16 +0200
Subject: [PATCH 002/144] macros
---
code/game/objects/items/implants/implant_track.dm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/code/game/objects/items/implants/implant_track.dm b/code/game/objects/items/implants/implant_track.dm
index fc7539af9e..4398688cee 100644
--- a/code/game/objects/items/implants/implant_track.dm
+++ b/code/game/objects/items/implants/implant_track.dm
@@ -2,13 +2,13 @@
name = "tracking implant"
desc = "Track with this."
activated = FALSE
- var/lifespan_postmortem = 6000 //for how many deciseconds after user death will the implant work?
+ var/lifespan_postmortem = 10 MINUTES //for how many deciseconds after user death will the implant work?
var/allow_teleport = TRUE //will people implanted with this act as teleporter beacons?
/obj/item/implant/tracking/c38
name = "TRAC implant"
desc = "A smaller tracking implant that supplies power for only a few minutes."
- var/lifespan = 3000 //how many deciseconds does the implant last?
+ var/lifespan = 5 MINUTES //how many deciseconds does the implant last?
allow_teleport = FALSE
/obj/item/implant/tracking/c38/Initialize()
From b4e975ef75d231e892bb6053c750c41063831d38 Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Wed, 9 Oct 2019 06:51:07 +0200
Subject: [PATCH 003/144] mitigates the ghost roles/mid-round antag lock out
for suicide/cryo. And related fixes.
---
code/__DEFINES/misc.dm | 3 +++
code/__HELPERS/game.dm | 2 +-
code/controllers/subsystem/pai.dm | 5 +++++
code/game/machinery/cryopod.dm | 3 ++-
.../clockcult/clock_items/construct_chassis.dm | 5 ++++-
code/modules/awaymissions/corpse.dm | 4 ++--
code/modules/mob/dead/observer/observer.dm | 14 +++++++-------
code/modules/mob/living/brain/posibrain.dm | 10 +++++++---
.../friendly/drone/drones_as_items.dm | 5 ++++-
.../living/simple_animal/hostile/giant_spider.dm | 5 +++++
.../simple_animal/hostile/megafauna/colossus.dm | 3 +++
11 files changed, 43 insertions(+), 16 deletions(-)
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index ba5e105041..2823761444 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -221,6 +221,9 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
//Same as above except gets the area instead
#define get_area(A) (isarea(A) ? A : get_step(A, 0)?.loc)
+//Used to prevent cryo/suicidees from coming back into the round as ghost roles or mid round antags before a given duration has passed.
+#define SUICIDE_REENTER_ROUND_TIMER 40 MINUTES
+
//Ghost orbit types:
#define GHOST_ORBIT_CIRCLE "circle"
#define GHOST_ORBIT_TRIANGLE "triangle"
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index cc0bd3e0b4..00decafabd 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -446,7 +446,7 @@
var/list/candidates = list()
for(var/mob/dead/observer/G in GLOB.player_list)
- if(G.can_reenter_round)
+ if(G.reenter_round_timeout < world.realtime)
candidates += G
return pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category, flashwindow, candidates)
diff --git a/code/controllers/subsystem/pai.dm b/code/controllers/subsystem/pai.dm
index 2e2f7edd99..09087c8626 100644
--- a/code/controllers/subsystem/pai.dm
+++ b/code/controllers/subsystem/pai.dm
@@ -69,6 +69,11 @@ SUBSYSTEM_DEF(pai)
candidate.comments = copytext(sanitize(candidate.comments),1,MAX_MESSAGE_LEN)
if("submit")
+ if(isobserver(usr))
+ var/mob/dead/observer/O = usr
+ if(O.reenter_round_timeout > world.realtime)
+ to_chat(O, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((O.reenter_round_timeout - world.realtime)/600)] minutes.")
+ return
if(candidate)
candidate.ready = 1
for(var/obj/item/paicard/p in pai_card_list)
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index e358f10346..84cc27953a 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -411,7 +411,8 @@
// Ghost and delete the mob.
if(!mob_occupant.get_ghost(1))
- mob_occupant.ghostize(0) // Players who cryo out may not re-enter the round
+ mob_occupant.suiciding = TRUE //to penalize them from making a ghost role / midround antag comeback right away.
+ mob_occupant.ghostize(0)
QDEL_NULL(occupant)
open_machine()
diff --git a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm
index 12af249bee..fa15509c59 100644
--- a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm
+++ b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm
@@ -39,7 +39,10 @@
. = ..()
//ATTACK GHOST IGNORING PARENT RETURN VALUE
-/obj/item/clockwork/construct_chassis/attack_ghost(mob/user)
+/obj/item/clockwork/construct_chassis/attack_ghost(mob/dead/observer/user)
+ if(user.reenter_round_timeout > world.realtime)
+ to_chat(user, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((user.reenter_round_timeout - world.realtime)/600)] minutes.")
+ return
if(!SSticker.mode)
to_chat(user, "You cannot use that before the game has started.")
return
diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm
index 74f81ec9a0..9d5c46fdf5 100644
--- a/code/modules/awaymissions/corpse.dm
+++ b/code/modules/awaymissions/corpse.dm
@@ -43,8 +43,8 @@
return
if(isobserver(user))
var/mob/dead/observer/O = user
- if(!O.can_reenter_round)
- to_chat(user, "You are unable to reenter the round.")
+ if(O.reenter_round_timeout > world.realtime)
+ to_chat(user, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((O.reenter_round_timeout - world.realtime)/600)] minutes.")
return
var/ghost_role = alert(latejoinercalling ? "Latejoin as [mob_name]? (This is a ghost role, and as such, it's very likely to be off-station.)" : "Become [mob_name]? (Warning, You can no longer be cloned!)",,"Yes","No")
if(ghost_role == "No" || !loc)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index fefa032e4f..16fd99e9be 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -18,7 +18,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
invisibility = INVISIBILITY_OBSERVER
hud_type = /datum/hud/ghost
var/can_reenter_corpse
- var/can_reenter_round = TRUE
+ var/reenter_round_timeout = 0 // used to prevent people from coming back through ghost roles/midround antags as they suicide/cryo for a duration set by SUICIDE_REENTER_ROUND_TIMER.
var/datum/hud/living/carbon/hud = null // hud
var/bootime = 0
var/started_as_observer //This variable is set to 1 when you enter the game as an observer.
@@ -267,7 +267,7 @@ Works together with spawning an observer, noted above.
var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc.
SStgui.on_transfer(src, ghost) // Transfer NanoUIs.
ghost.can_reenter_corpse = can_reenter_corpse
- ghost.can_reenter_round = (can_reenter_corpse && !suiciding)
+ ghost.reenter_round_timeout = suiciding ? world.realtime + SUICIDE_REENTER_ROUND_TIMER : 0
ghost.key = key
return ghost
@@ -282,7 +282,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
// CITADEL EDIT
if(istype(loc, /obj/machinery/cryopod))
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
+ var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [SUICIDE_REENTER_ROUND_TIMER/600] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")//darn copypaste
return
var/obj/machinery/cryopod/C = loc
@@ -295,7 +295,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(stat == DEAD)
ghostize(1)
else
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
+ var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [SUICIDE_REENTER_ROUND_TIMER/600] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return //didn't want to ghost after-all
ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
@@ -306,7 +306,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Ghost"
set desc = "Relinquish your life and enter the land of the dead."
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
+ var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [SUICIDE_REENTER_ROUND_TIMER/600] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return
ghostize(0)
@@ -617,8 +617,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(src, "This isn't really a creature, now is it!")
return 0
- if(!can_reenter_round)
- to_chat(src, "You are unable to re-enter the round.")
+ if(reenter_round_timeout > world.realtime)
+ to_chat(src, "You are unable to re-enter the round yet. Your ghost role blacklist will expire in [round((reenter_round_timeout - world.realtime)/600)] minutes.")
return FALSE
if(can_reenter_corpse && mind && mind.current)
diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm
index 9e0bb0428b..e52d53dca2 100644
--- a/code/modules/mob/living/brain/posibrain.dm
+++ b/code/modules/mob/living/brain/posibrain.dm
@@ -83,11 +83,15 @@ GLOBAL_VAR(posibrain_notify_cooldown)
//Two ways to activate a positronic brain. A clickable link in the ghost notif, or simply clicking the object itself.
/obj/item/mmi/posibrain/proc/activate(mob/user)
- if(QDELETED(brainmob))
- return
- if(is_occupied() || jobban_isbanned(user,"posibrain") || QDELETED(brainmob) || QDELETED(src) || QDELETED(user))
+ if(QDELETED(brainmob) || is_occupied() || jobban_isbanned(user,"posibrain") || QDELETED(src) || QDELETED(user))
return
+ if(isobserver(user))
+ var/mob/dead/observer/O = user
+ if(O.reenter_round_timeout > world.realtime)
+ to_chat(user, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((O.reenter_round_timeout - world.realtime)/600)] minutes.")
+ return
+
var/posi_ask = alert("Become a [name]? (Warning, You can no longer be cloned, and all past lives will be forgotten!)","Are you positive?","Yes","No")
if(posi_ask == "No" || QDELETED(src))
return
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
index a655bdf231..dd0b948299 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
@@ -40,7 +40,7 @@
. = ..()
//ATTACK GHOST IGNORING PARENT RETURN VALUE
-/obj/item/drone_shell/attack_ghost(mob/user)
+/obj/item/drone_shell/attack_ghost(mob/dead/observer/user)
if(jobban_isbanned(user,"drone") || QDELETED(src) || QDELETED(user))
return
if(CONFIG_GET(flag/use_age_restriction_for_jobs))
@@ -49,6 +49,9 @@
if(user.client.player_age < DRONE_MINIMUM_AGE)
to_chat(user, "You're too new to play as a drone! Please try again in [DRONE_MINIMUM_AGE - user.client.player_age] days.")
return
+ if(user.reenter_round_timeout > world.realtime)
+ to_chat(user, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((user.reenter_round_timeout - world.realtime)/600)] minutes.")
+ return
if(!SSticker.mode)
to_chat(user, "Can't become a drone before the game has started.")
return
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index cfdf302d6b..c851e50be7 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -84,6 +84,11 @@
/mob/living/simple_animal/hostile/poison/giant_spider/proc/humanize_spider(mob/user)
if(key || !playable_spider || stat)//Someone is in it, it's dead, or the fun police are shutting it down
return 0
+ if(isobserver(user))
+ var/mob/dead/observer/O = user
+ if(O.reenter_round_timeout > world.realtime)
+ to_chat(O, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((O.reenter_round_timeout - world.realtime)/600)] minutes.")
+ return
var/spider_ask = alert("Become a spider?", "Are you australian?", "Yes", "No")
if(spider_ask == "No" || !src || QDELETED(src))
return 1
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index b529d826c9..a9a49e3982 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -582,6 +582,9 @@ Difficulty: Very Hard
if(.)
return
if(ready_to_deploy)
+ if(user.reenter_round_timeout > world.realtime)
+ to_chat(user, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((user.reenter_round_timeout - world.realtime)/600)] minutes.")
+ return
var/be_helper = alert("Become a Lightgeist? (Warning, You can no longer be cloned!)",,"Yes","No")
if(be_helper == "Yes" && !QDELETED(src) && isobserver(user))
var/mob/living/simple_animal/hostile/lightgeist/W = new /mob/living/simple_animal/hostile/lightgeist(get_turf(loc))
From ac0b3629f1485e8463f5ad4dc04248fbf9905fae Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Wed, 9 Oct 2019 07:53:59 +0200
Subject: [PATCH 004/144] roundstart quitters
---
code/__DEFINES/misc.dm | 3 ++-
code/modules/mob/dead/observer/observer.dm | 18 ++++++++++++++----
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 2823761444..9751030e8d 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -222,7 +222,8 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
#define get_area(A) (isarea(A) ? A : get_step(A, 0)?.loc)
//Used to prevent cryo/suicidees from coming back into the round as ghost roles or mid round antags before a given duration has passed.
-#define SUICIDE_REENTER_ROUND_TIMER 40 MINUTES
+#define SUICIDE_REENTER_ROUND_TIMER 30 MINUTES
+#define ROUNDSTART_QUITTER_TIME_LIMIT 30 MINUTES //a game time threshold under which will be applied a proportional added penalty.
//Ghost orbit types:
#define GHOST_ORBIT_CIRCLE "circle"
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 16fd99e9be..f75d7016d3 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -267,7 +267,11 @@ Works together with spawning an observer, noted above.
var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc.
SStgui.on_transfer(src, ghost) // Transfer NanoUIs.
ghost.can_reenter_corpse = can_reenter_corpse
- ghost.reenter_round_timeout = suiciding ? world.realtime + SUICIDE_REENTER_ROUND_TIMER : 0
+ if(suiciding)
+ var/penalty = SUICIDE_REENTER_ROUND_TIMER
+ if(world.time < ROUNDSTART_QUITTER_TIME_LIMIT) //add up the time difference to their antag rolling penalty if they quit before half a (ingame) hour even passed.
+ penalty += ROUNDSTART_QUITTER_TIME_LIMIT - world.time
+ ghost.reenter_round_timeout = world.realtime + penalty
ghost.key = key
return ghost
@@ -280,9 +284,12 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Ghost"
set desc = "Relinquish your life and enter the land of the dead."
+ var/penalty = SUICIDE_REENTER_ROUND_TIMER
+ if(world.time < ROUNDSTART_QUITTER_TIME_LIMIT)
+ penalty += ROUNDSTART_QUITTER_TIME_LIMIT - world.time
// CITADEL EDIT
if(istype(loc, /obj/machinery/cryopod))
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [SUICIDE_REENTER_ROUND_TIMER/600] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
+ var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [round(penalty/600, 600)] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")//darn copypaste
return
var/obj/machinery/cryopod/C = loc
@@ -295,7 +302,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(stat == DEAD)
ghostize(1)
else
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [SUICIDE_REENTER_ROUND_TIMER/600] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
+ var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [round(penalty/600, 600)] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return //didn't want to ghost after-all
ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
@@ -306,7 +313,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Ghost"
set desc = "Relinquish your life and enter the land of the dead."
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [SUICIDE_REENTER_ROUND_TIMER/600] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
+ var/penalty = SUICIDE_REENTER_ROUND_TIMER
+ if(world.time < ROUNDSTART_QUITTER_TIME_LIMIT)
+ penalty += ROUNDSTART_QUITTER_TIME_LIMIT - world.time
+ var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [round(penalty/600, 600)] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return
ghostize(0)
From f73516a17f086888d34ab445453d5d4a269e2292 Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Thu, 17 Oct 2019 04:44:30 +0200
Subject: [PATCH 005/144] made it into config.
---
code/__DEFINES/misc.dm | 4 --
.../configuration/entries/game_options.dm | 8 +++
code/game/machinery/cryopod.dm | 3 +-
code/modules/client/verbs/suicide.dm | 2 +-
code/modules/mob/dead/observer/observer.dm | 55 +++++++++----------
config/game_options.txt | 12 ++++
6 files changed, 49 insertions(+), 35 deletions(-)
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index afa9071aae..bccf1f28dd 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -221,10 +221,6 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
//Same as above except gets the area instead
#define get_area(A) (isarea(A) ? A : get_step(A, 0)?.loc)
-//Used to prevent cryo/suicidees from coming back into the round as ghost roles or mid round antags before a given duration has passed.
-#define SUICIDE_REENTER_ROUND_TIMER 30 MINUTES
-#define ROUNDSTART_QUITTER_TIME_LIMIT 30 MINUTES //a game time threshold under which will be applied a proportional added penalty.
-
//Ghost orbit types:
#define GHOST_ORBIT_CIRCLE "circle"
#define GHOST_ORBIT_TRIANGLE "triangle"
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index cfd57b4850..95935a7066 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -132,6 +132,14 @@
min_val = 0
max_val = 1
+/datum/config_entry/number/suicide_reenter_round_timer
+ config_entry_value = 30
+ min_val = 0
+
+/datum/config_entry/number/roundstart_suicide_time_limit
+ config_entry_value = 30
+ min_val = 0
+
/datum/config_entry/number/shuttle_refuel_delay
config_entry_value = 12000
min_val = 0
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 84cc27953a..b856ee4c94 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -411,8 +411,7 @@
// Ghost and delete the mob.
if(!mob_occupant.get_ghost(1))
- mob_occupant.suiciding = TRUE //to penalize them from making a ghost role / midround antag comeback right away.
- mob_occupant.ghostize(0)
+ mob_occupant.ghostize(FALSE, penalize = TRUE)
QDEL_NULL(occupant)
open_machine()
diff --git a/code/modules/client/verbs/suicide.dm b/code/modules/client/verbs/suicide.dm
index 2e643cc05d..90c692c60e 100644
--- a/code/modules/client/verbs/suicide.dm
+++ b/code/modules/client/verbs/suicide.dm
@@ -49,7 +49,7 @@
if(!(damagetype & (BRUTELOSS | FIRELOSS | TOXLOSS | OXYLOSS) ))
adjustOxyLoss(max(200 - getToxLoss() - getFireLoss() - getBruteLoss() - getOxyLoss(), 0))
- death(FALSE)
+ death(FALSE, penalize = TRUE)
return
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 835dcab9e2..eb5c968bd2 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -18,7 +18,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
invisibility = INVISIBILITY_OBSERVER
hud_type = /datum/hud/ghost
var/can_reenter_corpse
- var/reenter_round_timeout = 0 // used to prevent people from coming back through ghost roles/midround antags as they suicide/cryo for a duration set by SUICIDE_REENTER_ROUND_TIMER.
+ var/reenter_round_timeout = 0 // used to prevent people from coming back through ghost roles/midround antags as they suicide/cryo for a duration set by CONFIG_GET(number/suicide_reenter_round_timer) and CONFIG_GET(number/roundstart_suicide_time_limit)
var/datum/hud/living/carbon/hud = null // hud
var/bootime = 0
var/started_as_observer //This variable is set to 1 when you enter the game as an observer.
@@ -260,18 +260,20 @@ Transfer_mind is there to check if mob is being deleted/not going to have a body
Works together with spawning an observer, noted above.
*/
-/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE)
- if(!key || cmptext(copytext(key,1,2),"@") || (!special && SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special) & COMPONENT_BLOCK_GHOSTING))
+/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE, penalize = FALSE)
+ if(!key || cmptext(copytext(key,1,2),"@") || (!special && SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse) & COMPONENT_BLOCK_GHOSTING))
return //mob has no key, is an aghost or some component hijacked.
stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now
var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc.
SStgui.on_transfer(src, ghost) // Transfer NanoUIs.
ghost.can_reenter_corpse = can_reenter_corpse
- if(suiciding)
- var/penalty = SUICIDE_REENTER_ROUND_TIMER
- if(world.time < ROUNDSTART_QUITTER_TIME_LIMIT) //add up the time difference to their antag rolling penalty if they quit before half a (ingame) hour even passed.
- penalty += ROUNDSTART_QUITTER_TIME_LIMIT - world.time
- ghost.reenter_round_timeout = world.realtime + penalty
+ if(penalize) //penalizing them from making a ghost role / midround antag comeback right away.
+ var/penalty = CONFIG_GET(number/suicide_reenter_round_timer)
+ var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit)
+ if(world.time < roundstart_quit_limit) //add up the time difference to their antag rolling penalty if they quit before half a (ingame) hour even passed.
+ penalty += roundstart_quit_limit - world.time
+ if(penalty)
+ ghost.reenter_round_timeout = world.realtime + penalty
transfer_ckey(ghost, FALSE)
return ghost
@@ -287,29 +289,25 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING)
return
- var/penalty = SUICIDE_REENTER_ROUND_TIMER
- if(world.time < ROUNDSTART_QUITTER_TIME_LIMIT)
- penalty += ROUNDSTART_QUITTER_TIME_LIMIT - world.time
-// CITADEL EDIT
- if(istype(loc, /obj/machinery/cryopod))
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [round(penalty/600, 600)] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
- if(response != "Ghost")//darn copypaste
- return
- var/obj/machinery/cryopod/C = loc
- C.despawn_occupant()
- return
-// END EDIT
+ var/penalty = CONFIG_GET(number/suicide_reenter_round_timer)
+ var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit)
+ if(world.time < roundstart_quit_limit)
+ penalty += roundstart_quit_limit - world.time
if(stat != DEAD)
succumb()
if(stat == DEAD)
ghostize(1)
else
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [round(penalty/600, 600)] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
+ var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles for the next [round(penalty/600)] minutes" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return //didn't want to ghost after-all
- ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
- suicide_log(TRUE)
+ if(istype(loc, /obj/machinery/cryopod))
+ var/obj/machinery/cryopod/C = loc
+ C.despawn_occupant()
+ else
+ ghostize(0, penalize = TRUE) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
+ suicide_log(TRUE)
/mob/camera/verb/ghost()
set category = "OOC"
@@ -319,14 +317,15 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING)
return
- var/penalty = SUICIDE_REENTER_ROUND_TIMER
- if(world.time < ROUNDSTART_QUITTER_TIME_LIMIT)
- penalty += ROUNDSTART_QUITTER_TIME_LIMIT - world.time
+ var/penalty = CONFIG_GET(number/suicide_reenter_round_timer)
+ var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit)
+ if(world.time < roundstart_quit_limit)
+ penalty += roundstart_quit_limit - world.time
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round for the next [round(penalty/600, 600)] minutes! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
+ var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles for the next [round(penalty/600)] minutes" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return
- ghostize(0)
+ ghostize(0, penalize = TRUE)
/mob/dead/observer/Move(NewLoc, direct)
if(updatedir)
diff --git a/config/game_options.txt b/config/game_options.txt
index 2e346ce0ac..ca07d4e744 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -471,6 +471,18 @@ MIDROUND_ANTAG_TIME_CHECK 60
## A ratio of living to total crew members, the lower this is, the more people will have to die in order for midround antag to be skipped
MIDROUND_ANTAG_LIFE_CHECK 0.7
+## A time, in real-time deciseconds, applied upon suicide, cryosleep or ghosting whilst alive
+## during which the player shouldn't be able to come back through
+## midround playable roles or mob spawners.
+## Set to 0 to completely disable it.
+SUICIDE_REENTER_ROUND_TIMER 18000
+
+## A time, in real-time deciseconds, below which the player receives
+## a timed penalty, for purposes similar to the aforementioned one (can also stack)
+## and equal to this config difference with world.time.
+## Both configs are indipendent from each other, disabling one won't affect the other.
+ROUNDSTART_SUICIDE_TIME_LIMIT 18000
+
##Limit Spell Choices##
## Uncomment to disallow wizards from using certain spells that may be too chaotic/fun for your playerbase
From ec22088534dc3c005922e11b8695aa09d0948843 Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Sun, 20 Oct 2019 09:15:35 +0200
Subject: [PATCH 006/144] Complying with suggestions. Also stops dnr observers
from getting ghost role notifications
---
code/controllers/subsystem/pai.dm | 7 ++--
code/game/objects/effects/spiders.dm | 2 +-
.../objects/structures/ghost_role_spawners.dm | 6 +--
.../clock_items/construct_chassis.dm | 7 ++--
code/modules/antagonists/cult/runes.dm | 4 +-
code/modules/antagonists/swarmer/swarmer.dm | 2 +-
code/modules/awaymissions/corpse.dm | 5 +--
code/modules/events/pirates.dm | 2 +-
code/modules/mob/dead/observer/observer.dm | 37 ++++++++++++++-----
code/modules/mob/living/brain/posibrain.dm | 7 ++--
.../friendly/drone/drones_as_items.dm | 7 ++--
.../simple_animal/hostile/giant_spider.dm | 13 +++----
.../hostile/megafauna/colossus.dm | 7 ++--
code/modules/mob/mob_helpers.dm | 4 +-
.../mob/living/simple_animal/banana_spider.dm | 9 ++++-
15 files changed, 69 insertions(+), 50 deletions(-)
diff --git a/code/controllers/subsystem/pai.dm b/code/controllers/subsystem/pai.dm
index 09087c8626..18667053d4 100644
--- a/code/controllers/subsystem/pai.dm
+++ b/code/controllers/subsystem/pai.dm
@@ -71,9 +71,8 @@ SUBSYSTEM_DEF(pai)
if("submit")
if(isobserver(usr))
var/mob/dead/observer/O = usr
- if(O.reenter_round_timeout > world.realtime)
- to_chat(O, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((O.reenter_round_timeout - world.realtime)/600)] minutes.")
- return
+ if(!O.can_reenter_round())
+ return FALSE
if(candidate)
candidate.ready = 1
for(var/obj/item/paicard/p in pai_card_list)
@@ -153,6 +152,8 @@ SUBSYSTEM_DEF(pai)
continue
if(!(ROLE_PAI in G.client.prefs.be_special))
continue
+ if(!G.can_reenter_round()) // this should use notify_ghosts() instead one day.
+ return FALSE
to_chat(G, "[user] is requesting a pAI personality! Use the pAI button to submit yourself as one.")
addtimer(CALLBACK(src, .proc/spam_again), spam_delay)
var/list/available = list()
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index c92721082c..08a3501be6 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -201,7 +201,7 @@
S.directive = directive
if(player_spiders)
S.playable_spider = TRUE
- notify_ghosts("Spider [S.name] can be controlled", null, enter_link="(Click to play)", source=S, action=NOTIFY_ATTACK, ignore_key = POLL_IGNORE_SPIDER)
+ notify_ghosts("Spider [S.name] can be controlled", null, enter_link="(Click to play)", source=S, action=NOTIFY_ATTACK, ignore_key = POLL_IGNORE_SPIDER, ignore_dnr_observers = TRUE)
qdel(src)
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index b820e93c7b..10f1f30e13 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -66,7 +66,7 @@
. = ..()
var/area/A = get_area(src)
if(A)
- notify_ghosts("An ash walker egg is ready to hatch in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_ASHWALKER)
+ notify_ghosts("An ash walker egg is ready to hatch in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_ASHWALKER, ignore_dnr_observers = TRUE)
/datum/outfit/ashwalker
name ="Ashwalker"
@@ -133,7 +133,7 @@
. = ..()
var/area/A = get_area(src)
if(!mapload && A)
- notify_ghosts("\A [initial(species.prefix)] golem shell has been completed in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_GOLEM)
+ notify_ghosts("\A [initial(species.prefix)] golem shell has been completed in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_GOLEM, ignore_dnr_observers = TRUE)
if(has_owner && creator)
flavour_text = "You are a Golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. \
Serve [creator], and assist [creator.p_them()] in completing [creator.p_their()] goals at any cost."
@@ -372,7 +372,7 @@
flavour_text = "You have been given a reprieve from your eternity of torment, to be [owner.name]'s friend for [owner.p_their()] short mortal coil. Be aware that if you do not live up to [owner.name]'s expectations, they can send you back to hell with a single thought. [owner.name]'s death will also return you to hell."
var/area/A = get_area(src)
if(!mapload && A)
- notify_ghosts("\A friendship shell has been completed in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE)
+ notify_ghosts("\A friendship shell has been completed in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE)
objectives = "Be [owner.name]'s friend, and keep [owner.name] alive, so you don't get sent back to hell."
spell = summoning_spell
diff --git a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm
index 4519a2d6a2..f53796f02a 100644
--- a/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm
+++ b/code/modules/antagonists/clockcult/clock_items/construct_chassis.dm
@@ -15,7 +15,7 @@
. = ..()
var/area/A = get_area(src)
if(A && construct_type)
- notify_ghosts("A [construct_name] chassis has been created in [A.name]!", 'sound/magic/clockwork/fellowship_armory.ogg', source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_CONSTRUCT)
+ notify_ghosts("A [construct_name] chassis has been created in [A.name]!", 'sound/magic/clockwork/fellowship_armory.ogg', source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_CONSTRUCT, ignore_dnr_observers = TRUE)
GLOB.poi_list += src
LAZYADD(GLOB.mob_spawners[name], src)
@@ -40,9 +40,8 @@
//ATTACK GHOST IGNORING PARENT RETURN VALUE
/obj/item/clockwork/construct_chassis/attack_ghost(mob/dead/observer/user)
- if(user.reenter_round_timeout > world.realtime)
- to_chat(user, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((user.reenter_round_timeout - world.realtime)/600)] minutes.")
- return
+ if(!user.can_reenter_round())
+ return FALSE
if(!SSticker.mode)
to_chat(user, "You cannot use that before the game has started.")
return
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 2e233d26e4..1eac059d36 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -848,10 +848,10 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
log_game("Manifest rune failed - too many summoned ghosts")
return list()
- notify_ghosts("Manifest rune invoked in [get_area(src)].", 'sound/effects/ghost2.ogg', source = src)
+ notify_ghosts("Manifest rune invoked in [get_area(src)].", 'sound/effects/ghost2.ogg', source = src, ignore_dnr_observers = TRUE)
var/list/ghosts_on_rune = list()
for(var/mob/dead/observer/O in T)
- if(O.client && !jobban_isbanned(O, ROLE_CULTIST) && !QDELETED(src) && !QDELETED(O))
+ if(!QDELETED(O) && O.client && !jobban_isbanned(O, ROLE_CULTIST) && !QDELETED(src) && O.can_reenter_round())
ghosts_on_rune += O
if(!ghosts_on_rune.len)
to_chat(user, "There are no spirits near [src]!")
diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm
index 87cee7586d..ce455d9e67 100644
--- a/code/modules/antagonists/swarmer/swarmer.dm
+++ b/code/modules/antagonists/swarmer/swarmer.dm
@@ -33,7 +33,7 @@
. = ..()
var/area/A = get_area(src)
if(A)
- notify_ghosts("A swarmer shell has been created in [A.name].", 'sound/effects/bin_close.ogg', source = src, action = NOTIFY_ATTACK, flashwindow = FALSE)
+ notify_ghosts("A swarmer shell has been created in [A.name].", 'sound/effects/bin_close.ogg', source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE)
/obj/effect/mob_spawn/swarmer/attack_hand(mob/living/user)
. = ..()
diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm
index 9d5c46fdf5..304d050630 100644
--- a/code/modules/awaymissions/corpse.dm
+++ b/code/modules/awaymissions/corpse.dm
@@ -43,9 +43,8 @@
return
if(isobserver(user))
var/mob/dead/observer/O = user
- if(O.reenter_round_timeout > world.realtime)
- to_chat(user, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((O.reenter_round_timeout - world.realtime)/600)] minutes.")
- return
+ if(!O.can_reenter_round())
+ return FALSE
var/ghost_role = alert(latejoinercalling ? "Latejoin as [mob_name]? (This is a ghost role, and as such, it's very likely to be off-station.)" : "Become [mob_name]? (Warning, You can no longer be cloned!)",,"Yes","No")
if(ghost_role == "No" || !loc)
return
diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm
index 7256ddb6ea..1a8501f179 100644
--- a/code/modules/events/pirates.dm
+++ b/code/modules/events/pirates.dm
@@ -75,7 +75,7 @@
spawner.create(M.ckey)
candidates -= M
else
- notify_ghosts("Space pirates are waking up!", source = spawner, action=NOTIFY_ATTACK, flashwindow = FALSE)
+ notify_ghosts("Space pirates are waking up!", source = spawner, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE)
priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/ai/commandreport.ogg') //CITADEL EDIT also metabreak here too
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index eb5c968bd2..f2a24cd763 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -3,6 +3,8 @@ GLOBAL_LIST_EMPTY(ghost_images_simple) //this is a list of all ghost images as t
GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
+#define CANT_REENTER_ROUND -1
+
/mob/dead/observer
name = "ghost"
desc = "It's a g-g-g-g-ghooooost!" //jinkies!
@@ -274,6 +276,8 @@ Works together with spawning an observer, noted above.
penalty += roundstart_quit_limit - world.time
if(penalty)
ghost.reenter_round_timeout = world.realtime + penalty
+ if(ghost.reenter_round_timeout - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
+ ghost.reenter_round_timeout = CANT_REENTER_ROUND
transfer_ckey(ghost, FALSE)
return ghost
@@ -289,17 +293,19 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING)
return
- var/penalty = CONFIG_GET(number/suicide_reenter_round_timer)
- var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit)
+ var/penalty = CONFIG_GET(number/suicide_reenter_round_timer) MINUTES
+ var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
if(world.time < roundstart_quit_limit)
penalty += roundstart_quit_limit - world.time
+ if(penalty + world.realtime - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
+ penalty = CANT_REENTER_ROUND
if(stat != DEAD)
succumb()
if(stat == DEAD)
ghostize(1)
else
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles for the next [round(penalty/600)] minutes" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
+ var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty != CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return //didn't want to ghost after-all
if(istype(loc, /obj/machinery/cryopod))
@@ -317,16 +323,25 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING)
return
- var/penalty = CONFIG_GET(number/suicide_reenter_round_timer)
- var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit)
+ var/penalty = CONFIG_GET(number/suicide_reenter_round_timer) MINUTES
+ var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
if(world.time < roundstart_quit_limit)
penalty += roundstart_quit_limit - world.time
+ if(penalty + world.realtime - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
+ penalty = CANT_REENTER_ROUND
- var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles for the next [round(penalty/600)] minutes" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
+ var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty != CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return
ghostize(0, penalize = TRUE)
+/mob/dead/observer/proc/can_reenter_round(silent = FALSE)
+ if(reenter_round_timeout != CANT_REENTER_ROUND && reenter_round_timeout <= world.realtime)
+ return TRUE
+ if(!silent)
+ to_chat(src, "You are unable to reenter the round[reenter_round_timeout != CANT_REENTER_ROUND ? " yet. Your ghost role blacklist will expire in [DisplayTimeText(reenter_round_timeout - world.realtime)]" : ""].")
+ return FALSE
+
/mob/dead/observer/Move(NewLoc, direct)
if(updatedir)
setDir(direct)//only update dir if we actually need it, so overlays won't spin on base sprites that don't have directions of their own
@@ -613,6 +628,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Possess!"
set desc= "Take over the body of a mindless creature!"
+ if(reenter_round_timeout > world.realtime)
+ to_chat(src, "You are unable to re-enter the round yet. Your ghost role blacklist will expire in [DisplayTimeText(reenter_round_timeout - world.realtime)].")
+ return FALSE
+
var/list/possessible = list()
for(var/mob/living/L in GLOB.alive_mob_list)
if(istype(L,/mob/living/carbon/human/dummy) || !get_turf(L)) //Haha no.
@@ -633,10 +652,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(src, "This isn't really a creature, now is it!")
return 0
- if(reenter_round_timeout > world.realtime)
- to_chat(src, "You are unable to re-enter the round yet. Your ghost role blacklist will expire in [round((reenter_round_timeout - world.realtime)/600)] minutes.")
- return FALSE
-
if(can_reenter_corpse && mind && mind.current)
if(alert(src, "Your soul is still tied to your former life as [mind.current.name], if you go forward there is no going back to that life. Are you sure you wish to continue?", "Move On", "Yes", "No") == "No")
return 0
@@ -881,3 +896,5 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
spawners_menu = new(src)
spawners_menu.ui_interact(src)
+
+#undef CANT_REENTER_ROUND
\ No newline at end of file
diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm
index e52d53dca2..77af8d07d8 100644
--- a/code/modules/mob/living/brain/posibrain.dm
+++ b/code/modules/mob/living/brain/posibrain.dm
@@ -36,7 +36,7 @@ GLOBAL_VAR(posibrain_notify_cooldown)
/obj/item/mmi/posibrain/proc/ping_ghosts(msg, newlymade)
if(newlymade || GLOB.posibrain_notify_cooldown <= world.time)
- notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/misc/server-ready.ogg':null, enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_POSIBRAIN)
+ notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/misc/server-ready.ogg':null, enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_POSIBRAIN, ignore_dnr_observers = TRUE)
if(!newlymade)
GLOB.posibrain_notify_cooldown = world.time + askDelay
@@ -88,9 +88,8 @@ GLOBAL_VAR(posibrain_notify_cooldown)
if(isobserver(user))
var/mob/dead/observer/O = user
- if(O.reenter_round_timeout > world.realtime)
- to_chat(user, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((O.reenter_round_timeout - world.realtime)/600)] minutes.")
- return
+ if(!O.can_reenter_round())
+ return FALSE
var/posi_ask = alert("Become a [name]? (Warning, You can no longer be cloned, and all past lives will be forgotten!)","Are you positive?","Yes","No")
if(posi_ask == "No" || QDELETED(src))
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
index 7ac718ee6f..948be53abc 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
@@ -21,7 +21,7 @@
. = ..()
var/area/A = get_area(src)
if(A)
- notify_ghosts("A drone shell has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_DRONE)
+ notify_ghosts("A drone shell has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_DRONE, ignore_dnr_observers = TRUE)
GLOB.poi_list |= src
if(isnull(possible_seasonal_hats))
build_seasonal_hats()
@@ -49,9 +49,8 @@
if(user.client.player_age < DRONE_MINIMUM_AGE)
to_chat(user, "You're too new to play as a drone! Please try again in [DRONE_MINIMUM_AGE - user.client.player_age] days.")
return
- if(user.reenter_round_timeout > world.realtime)
- to_chat(user, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((user.reenter_round_timeout - world.realtime)/600)] minutes.")
- return
+ if(!user.can_reenter_round())
+ return FALSE
if(!SSticker.mode)
to_chat(user, "Can't become a drone before the game has started.")
return
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index afe49e82dc..c780dd1e96 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -83,20 +83,19 @@
/mob/living/simple_animal/hostile/poison/giant_spider/proc/humanize_spider(mob/user)
if(key || !playable_spider || stat)//Someone is in it, it's dead, or the fun police are shutting it down
- return 0
+ return FALSE
if(isobserver(user))
var/mob/dead/observer/O = user
- if(O.reenter_round_timeout > world.realtime)
- to_chat(O, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((O.reenter_round_timeout - world.realtime)/600)] minutes.")
- return
+ if(!O.can_reenter_round())
+ return FALSE
var/spider_ask = alert("Become a spider?", "Are you australian?", "Yes", "No")
if(spider_ask == "No" || !src || QDELETED(src))
- return 1
+ return TRUE
if(key)
to_chat(user, "Someone else already took this spider.")
- return 1
+ return TRUE
user.transfer_ckey(src, FALSE)
- return 1
+ return TRUE
//nursemaids - these create webs and eggs
/mob/living/simple_animal/hostile/poison/giant_spider/nurse
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index da8033205a..f45048632f 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -575,16 +575,15 @@ Difficulty: Very Hard
if(..() && !ready_to_deploy)
GLOB.poi_list |= src
ready_to_deploy = TRUE
- notify_ghosts("An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.", enter_link = "(Click to enter)", ghost_sound = 'sound/effects/ghost2.ogg', source = src, action = NOTIFY_ATTACK)
+ notify_ghosts("An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.", enter_link = "(Click to enter)", ghost_sound = 'sound/effects/ghost2.ogg', source = src, action = NOTIFY_ATTACK, ignore_dnr_observers = TRUE)
/obj/machinery/anomalous_crystal/helpers/attack_ghost(mob/dead/observer/user)
. = ..()
if(.)
return
if(ready_to_deploy)
- if(user.reenter_round_timeout > world.realtime)
- to_chat(user, "You are unable to reenter the round yet. Your ghost role blacklist will expire in [round((user.reenter_round_timeout - world.realtime)/600)] minutes.")
- return
+ if(!user.can_reenter_round())
+ return FALSE
var/be_helper = alert("Become a Lightgeist? (Warning, You can no longer be cloned!)",,"Yes","No")
if(be_helper == "Yes" && !QDELETED(src) && isobserver(user))
var/mob/living/simple_animal/hostile/lightgeist/W = new /mob/living/simple_animal/hostile/lightgeist(get_turf(loc))
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 5519c9be95..c6c6cf3c09 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -352,12 +352,12 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
/mob/proc/reagent_check(datum/reagent/R) // utilized in the species code
return 1
-/proc/notify_ghosts(var/message, var/ghost_sound = null, var/enter_link = null, var/atom/source = null, var/mutable_appearance/alert_overlay = null, var/action = NOTIFY_JUMP, flashwindow = TRUE, ignore_mapload = TRUE, ignore_key) //Easy notification of ghosts.
+/proc/notify_ghosts(message, ghost_sound, enter_link, atom/source, mutable_appearance/alert_overlay, action = NOTIFY_JUMP, flashwindow = TRUE, ignore_mapload = TRUE, ignore_key, ignore_dnr_observers = FALSE) //Easy notification of ghosts.
if(ignore_mapload && SSatoms.initialized != INITIALIZATION_INNEW_REGULAR) //don't notify for objects created during a map load
return
for(var/mob/dead/observer/O in GLOB.player_list)
if(O.client)
- if (ignore_key && O.ckey in GLOB.poll_ignore[ignore_key])
+ if ((ignore_key && (O.ckey in GLOB.poll_ignore[ignore_key])) || (ignore_dnr_observers && !O.can_reenter_round(TRUE)))
continue
to_chat(O, "[message][(enter_link) ? " [enter_link]" : ""]")
if(ghost_sound)
diff --git a/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm b/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm
index fdc271a158..b177687ab2 100644
--- a/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm
+++ b/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm
@@ -83,7 +83,7 @@
. = ..()
var/area/A = get_area(src)
if(A)
- notify_ghosts("A banana spider has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE)
+ notify_ghosts("A banana spider has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE)
/mob/living/simple_animal/banana_spider/attack_ghost(mob/user)
if(key) //please stop using src. without a good reason.
@@ -91,12 +91,19 @@
if(CONFIG_GET(flag/use_age_restriction_for_jobs))
if(!isnum(user.client.player_age))
return
+ if(isobserver(user))
+ var/mob/dead/observer/O = user
+ if(!O.can_reenter_round())
+ return
if(!SSticker.mode)
to_chat(user, "Can't become a banana spider before the game has started.")
return
var/be_spider = alert("Become a banana spider? (Warning, You can no longer be cloned!)",,"Yes","No")
if(be_spider == "No" || QDELETED(src) || !isobserver(user))
return
+ if(key)
+ to_chat(user, "Someone else already took this banana spider.")
+ return
sentience_act()
user.transfer_ckey(src, FALSE)
density = TRUE
From 7e8101abc3a1ff62d3cfcd1197be9c8b129f13e2 Mon Sep 17 00:00:00 2001
From: MrJWhit <48370570+MrJWhit@users.noreply.github.com>
Date: Sun, 20 Oct 2019 03:30:18 -0400
Subject: [PATCH 007/144] Changes brain damage lines
Adds the noise emotes, as well as makes the brain damage not lean towards OOC in IC language.
---
strings/traumas.json | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/strings/traumas.json b/strings/traumas.json
index 45e31f2367..c487926ace 100644
--- a/strings/traumas.json
+++ b/strings/traumas.json
@@ -70,7 +70,6 @@
"NO PRED CAN eVER CATCH MI",
"SCIENCE GIB SHINK RAY PLS",
"KILL PUNPUN 4 FUN xDD",
- "ooc wow rly?",
"i play @pick(roles) to only ORDER not DO",
"CRAGO ORDER @pick(cargo) PLS",
"erp?",
@@ -84,18 +83,15 @@
"LINCH VIRO",
"VIRO GIB SuPR VIrUS!!",
"Ai plai vxtest2!",
- "ahelp kan i b pick@(s_roles)???",
";taitor trie to make meh malk/?!1!!",
";ENGIE TATOR HE SET UP SINGULO!!!11",
"WHEN NAGAS ADdED?/?",
"SINDYIE ON SAtIONS GiB gUNS PLISE",
"CcLOWN IV SlIPPING MI, SEc t BAR@",
- "ahelp iT's RP vALiDZ!",
"HYDROBONIX PLS WEED PLIESe PLIsE BLAzE IT1!!!",
"HALP GOLIATH TENETCAL RAPPPP!!!!111",
"DudSE it'S 4:20 LmAO BLAZZ IT xDDDDD",
- "ahelp DUDE I JUT LOST MY JOBB!!",
- "looc dude rly",
+ "dude rly",
"pray can i heff spells",
"aI state dem1!",
"SINGULO eNGINE 2 DANGER, SOLARS PLS!",
@@ -112,15 +108,13 @@
"HOW DO i VORE",
"HOW DO i HAV SEX",
"@pick(semicolon)how do u cum",
- "@pick(semicolon)ahelp how do u use dildo",
+ "@pick(semicolon)how do u use dildo",
";AI LAW 3 OPEN THIS.",
- "ahelp hos pwrgamre they have 24 inch dick",
";KERPTAN IS A KERNDUM",
"@pick(semicolon)RESEARCH NANITES FIRST",
"@pick(semicolon)how use comms?????????",
"@pick(semicolon)im SICK of ths fuckign humans runin g my furry server",
"@pick(semicolon)ai ROUGE",
- "ahelp want a big titty @pick(create_nouns) gf to deepthroat my pp",
"@pick(semicolon)CHEMISST MAKE HEXACROCON OR REPORT",
"@pick(semicolon)drone 765 law 2 state LAWS NOW",
"@pick(semicolon)SM ROGUE",
@@ -128,13 +122,15 @@
"@pick(semicolon)lING DORMS i hear Suking noises!!!",
"@pick(semicolon)@pick(roles) tator they have @pick(mutations)!!",
"@pick(semicolon)aooc how do i steel @pick(cargo)?",
- "@pick(semicolon)how do i play",
- "ahelp help security powergaming with mindshields???",
";,g absorbing @pick(roles)",
";chemist can u @pick(create_verbs) holy @pick(mellens) for @pick(s_roles)???!!",
"@pick(semicolon) LIZZARRD SPEAKIGN IN EVIL BULL LANGUAGE SCI!!",
"@pick(semicolon)POST REBOOT MESSAGE LOLOL FUCK FUCK FUCK YOU",
"@pick(semicolon)so, i was trying to talk to someone on rp today, and then a mime walks up and pies them in the face along with some other prankster--i thought that mimes and clowns are supposed to be hired to entertain not to be a nuisance, and that if entertainment comes at someone elses expense then it's not supposed to be done. is that enough to like submit a player complaint or some shit or am i just being petty?"
+ "@pick(semicolon)*nya",
+ "@pick(semicolon)*awoo",
+ "@pick(semicolon)*merp"
+ "@pick(semicolon)*weh"
],
"mutations": [
From 6a73abfe32da5c191cd72743e1b9fe8880b8e930 Mon Sep 17 00:00:00 2001
From: Anonymous
Date: Sun, 20 Oct 2019 23:52:06 +0300
Subject: [PATCH 008/144] Adds ASSU suit+helmet and loadout stuff
Also adds newlines reeeeeeeeeeee
---
.../code/modules/client/loadout/_service.dm | 16 +++++++++++++++-
.../code/modules/clothing/head/head.dm | 11 ++++++++++-
.../code/modules/clothing/suits/suits.dm | 15 ++++++++++++++-
modular_citadel/icons/mob/clothing/assu.dmi | Bin 0 -> 1078 bytes
modular_citadel/icons/obj/clothing/assu.dmi | Bin 0 -> 593 bytes
5 files changed, 39 insertions(+), 3 deletions(-)
create mode 100644 modular_citadel/icons/mob/clothing/assu.dmi
create mode 100644 modular_citadel/icons/obj/clothing/assu.dmi
diff --git a/modular_citadel/code/modules/client/loadout/_service.dm b/modular_citadel/code/modules/client/loadout/_service.dm
index 062e22f966..7872ddcf99 100644
--- a/modular_citadel/code/modules/client/loadout/_service.dm
+++ b/modular_citadel/code/modules/client/loadout/_service.dm
@@ -4,6 +4,20 @@
path = /obj/item/clothing/under/color/grey
restricted_roles = list("Assistant")
+/datum/gear/neetsuit
+ name = "ASSU suit"
+ category = SLOT_WEAR_SUIT
+ path = /obj/item/clothing/suit/assu_suit
+ restricted_roles = list("Assistant")
+ cost = 2
+
+/datum/gear/neethelm
+ name = "ASSU helmet"
+ category = SLOT_HEAD
+ path = /obj/item/clothing/head/assu_helmet
+ restricted_roles = list("Assistant")
+ cost = 2
+
/datum/gear/plushvar
name = "Ratvar Plushie"
category = SLOT_IN_BACKPACK
@@ -16,4 +30,4 @@
category = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/narplush
cost = 5
- restricted_roles = list("Chaplain")
\ No newline at end of file
+ restricted_roles = list("Chaplain")
diff --git a/modular_citadel/code/modules/clothing/head/head.dm b/modular_citadel/code/modules/clothing/head/head.dm
index 7656766053..e15583be2c 100644
--- a/modular_citadel/code/modules/clothing/head/head.dm
+++ b/modular_citadel/code/modules/clothing/head/head.dm
@@ -17,4 +17,13 @@
//The "pocket" for the M1 helmet so you can tuck things into the elastic band
/datum/component/storage/concrete/pockets/tiny/spacenam
- attack_hand_interact = TRUE //So you can actually see what you stuff in there
\ No newline at end of file
+ attack_hand_interact = TRUE //So you can actually see what you stuff in there
+
+/obj/item/clothing/head/assu_helmet
+ name = "ASSU helmet"
+ icon = 'modular_citadel/icons/obj/clothing/assu.dmi'
+ alternate_worn_icon = 'modular_citadel/icons/mob/clothing/assu.dmi'
+ icon_state = "assu_helmet"
+ item_state = "assu_helmet"
+ desc = "A cheap replica of old riot helmet without visor. It has \"A.S.S.U.\" written on the front."
+ flags_inv = HIDEHAIR
diff --git a/modular_citadel/code/modules/clothing/suits/suits.dm b/modular_citadel/code/modules/clothing/suits/suits.dm
index 5cce40ad09..0098386929 100644
--- a/modular_citadel/code/modules/clothing/suits/suits.dm
+++ b/modular_citadel/code/modules/clothing/suits/suits.dm
@@ -40,4 +40,17 @@
body_parts_covered = CHEST
resistance_flags = NONE
mutantrace_variation = NO_MUTANTRACE_VARIATION
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 5, "bio" = 0, "rad" = 0, "fire" = -5, "acid" = -15) //nylon sucks against acid
\ No newline at end of file
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 5, "bio" = 0, "rad" = 0, "fire" = -5, "acid" = -15) //nylon sucks against acid
+
+/obj/item/clothing/suit/assu_suit
+ name = "ASSU suit"
+ desc = "A cheap replica of old SWAT armor. On its back, it is written: \"Assistance Skipping Special Unit\"."
+ icon = 'modular_citadel/icons/obj/clothing/assu.dmi'
+ alternate_worn_icon = 'modular_citadel/icons/mob/clothing/assu.dmi'
+ icon_state = "assu_suit"
+ item_state = "assu_suit"
+ blood_overlay_type = "armor"
+ body_parts_covered = CHEST|GROIN|ARMS|LEGS
+ flags_inv = HIDEJUMPSUIT
+ resistance_flags = NONE
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
diff --git a/modular_citadel/icons/mob/clothing/assu.dmi b/modular_citadel/icons/mob/clothing/assu.dmi
new file mode 100644
index 0000000000000000000000000000000000000000..2592442dc5e0dae1f493356e5fefb8a795cfa7d0
GIT binary patch
literal 1078
zcmV-61j+k}P)SXe+nKqMn0
zBO@ao9v&PV9632TfZbD)00001bW%=J06^y0W&i*Hc6wA;bVOxyV{&P5bZKvH004NL
zQ&w6*pqEe7;XSijyd%6L^Gj_`VUCd=~-zICc_v8es^}C0p5j=M#1tSkExl|L`t2cLBl
zS+r=;qD6}q{VvUY!SLoM?&bgd{KWHuF&BWZH@B3AW2wti?mV*=+I${L7Y)erZJb
zK8XTE33;AFDWLe8F!@=Q5x!5ds;9P
zE`0#pe#l8W?*E}6{~iDy=5p%*IQ{7UZaKNH)035qq<#Yj>-4TKT;G|r$G
zT6aSrpu=E|0Np>^{O4XHz|?f1EizkksZxOJg&x=sJ`wa$OU$ac;HZIM-f0R09wklfeXIRF3v07*qoM6N<$g2F-22LJ#7
literal 0
HcmV?d00001
diff --git a/modular_citadel/icons/obj/clothing/assu.dmi b/modular_citadel/icons/obj/clothing/assu.dmi
new file mode 100644
index 0000000000000000000000000000000000000000..63788a590d55d39b4a2b907cd90e730b8746ea20
GIT binary patch
literal 593
zcmV-X0gwwM|Nl=`T0B5N6ciLXIyxI0
z8%Re-9UUFr-Q5=#7Znv1A0Q+kAR9+ZOB@^=K}Sk5F(@@PH7zSECMG5xo*Qrg0004W
zQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>
zRWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5DY3Y?G(ICWCpWc3iHkEOv#1y-
zYRJWzR+N~V3SpzFEiTQ(sZv?N)z1a&3;_QkDIU@M>OnGG#Gi~oh)V{5o;MBxK;vaa2YRK7uW#+*lB{Tkf>JR6`BTs6Rk?NKsPqd>ALL-+yv+cz$_ud
z;C2okxIHdQWH$()zYTM4JqOS$EKm#|&kWpmAo|1%2K6v-pMd)g(651>1IjAJ_-R%0
z|KU%7I}u|DUm?WE_6xBF*aJGzK?KwtKn%-g
Date: Mon, 21 Oct 2019 01:04:56 +0300
Subject: [PATCH 009/144] Digi variant added
---
modular_citadel/icons/mob/suit_digi.dmi | Bin 376073 -> 378019 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/modular_citadel/icons/mob/suit_digi.dmi b/modular_citadel/icons/mob/suit_digi.dmi
index eba761ff793e98dbce1ac15840c342c44277ca66..8e8b2bd7592b5eba60d3d514e6484b52ab721f4b 100644
GIT binary patch
delta 23209
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
delta 21249
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