diff --git a/_maps/RandomZLevels/centcomAway.dmm b/_maps/RandomZLevels/centcomAway.dmm
index 8fab986fdb..97b8381ff2 100644
--- a/_maps/RandomZLevels/centcomAway.dmm
+++ b/_maps/RandomZLevels/centcomAway.dmm
@@ -3502,7 +3502,7 @@
/area/awaymission/centcomAway/general)
"kN" = (
/obj/structure/table/wood,
-/obj/item/clothing/tie/medal,
+/obj/item/clothing/accessory/medal,
/turf/open/floor/carpet,
/area/awaymission/centcomAway/general)
"kO" = (
@@ -3516,7 +3516,7 @@
/area/awaymission/centcomAway/general)
"kQ" = (
/obj/structure/table/wood,
-/obj/item/clothing/tie/medal/gold,
+/obj/item/clothing/accessory/medal/gold,
/turf/open/floor/carpet,
/area/awaymission/centcomAway/general)
"kR" = (
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 62311b4885..c64fb4b84e 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -30611,11 +30611,11 @@
"blx" = (
/obj/structure/table/reinforced,
/obj/item/weapon/clipboard,
-/obj/item/clothing/tie/armband/deputy,
-/obj/item/clothing/tie/armband/deputy,
-/obj/item/clothing/tie/armband/deputy,
-/obj/item/clothing/tie/armband/deputy,
-/obj/item/clothing/tie/armband/deputy,
+/obj/item/clothing/accessory/armband/deputy,
+/obj/item/clothing/accessory/armband/deputy,
+/obj/item/clothing/accessory/armband/deputy,
+/obj/item/clothing/accessory/armband/deputy,
+/obj/item/clothing/accessory/armband/deputy,
/obj/item/weapon/reagent_containers/food/snacks/donut/jelly/cherryjelly,
/turf/open/floor/plasteel/red/side{
dir = 8
@@ -52672,7 +52672,6 @@
/obj/machinery/camera/emp_proof{
c_tag = "Containment - Fore Starboard";
dir = 8;
- icon_state = "camera";
network = list("Singularity")
},
/turf/open/floor/plating/airless,
@@ -54400,7 +54399,6 @@
/obj/machinery/camera/emp_proof{
c_tag = "Containment - Fore Port";
dir = 4;
- icon_state = "camera";
network = list("Singularity")
},
/turf/open/space,
@@ -62751,7 +62749,6 @@
/obj/machinery/camera/emp_proof{
c_tag = "Containment - Aft Port";
dir = 4;
- icon_state = "camera";
network = list("Singularity")
},
/turf/open/space,
@@ -64431,7 +64428,6 @@
/obj/machinery/camera/emp_proof{
c_tag = "Containment - Aft Starboard";
dir = 8;
- icon_state = "camera";
network = list("Singularity")
},
/turf/open/floor/plating/airless,
@@ -103271,7 +103267,7 @@
/obj/item/weapon/wirerod,
/obj/item/weapon/wrench,
/obj/item/clothing/under/waiter,
-/obj/item/clothing/tie/waistcoat,
+/obj/item/clothing/accessory/waistcoat,
/obj/structure/sign/poster/contraband/random{
pixel_x = -32
},
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 9290c25c95..6be7048719 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -13412,9 +13412,7 @@
"aza" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 4;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/turf/open/floor/plasteel/black,
/area/engine/engineering)
@@ -14011,7 +14009,7 @@
name = "Station Intercom (General)";
pixel_y = 28
},
-/obj/item/clothing/tie/waistcoat,
+/obj/item/clothing/accessory/waistcoat,
/obj/item/clothing/suit/toggle/lawyer/black,
/obj/item/clothing/under/suit_jacket/red,
/obj/item/clothing/neck/tie/black,
@@ -15128,7 +15126,7 @@
contents = newlist(/obj/item/clothing/suit/armor/vest,/obj/item/weapon/gun/ballistic/automatic/pistol,/obj/item/weapon/suppressor,/obj/item/weapon/melee/classic_baton/telescopic,/obj/item/clothing/mask/balaclava,/obj/item/bodybag,/obj/item/weapon/soap/nanotrasen)
},
/obj/item/weapon/storage/backpack/dufflebag{
- contents = newlist(/obj/item/clothing/under/lawyer/blacksuit,/obj/item/clothing/tie/waistcoat,/obj/item/clothing/suit/toggle/lawyer/black,/obj/item/clothing/shoes/laceup,/obj/item/clothing/gloves/color/black,/obj/item/clothing/glasses/sunglasses,/obj/item/clothing/head/fedora);
+ contents = newlist(/obj/item/clothing/under/lawyer/blacksuit,/obj/item/clothing/accessory/waistcoat,/obj/item/clothing/suit/toggle/lawyer/black,/obj/item/clothing/shoes/laceup,/obj/item/clothing/gloves/color/black,/obj/item/clothing/glasses/sunglasses,/obj/item/clothing/head/fedora);
desc = "A large dufflebag for holding extra things. There is a NanoTrasen logo on the back.";
icon_state = "duffle-syndieammo";
item_state = "duffle-syndieammo"
@@ -31819,9 +31817,7 @@
"bhv" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 8;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/turf/open/floor/carpet,
/area/crew_quarters/heads/captain/private)
@@ -34604,9 +34600,7 @@
"bmy" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 8;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/obj/structure/cable/yellow{
d1 = 1;
@@ -38251,9 +38245,7 @@
"bsN" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 2;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/obj/structure/cable/yellow{
d1 = 1;
@@ -38333,9 +38325,7 @@
req_access_txt = "19"
},
/obj/machinery/atmospherics/components/unary/vent_scrubber{
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/obj/machinery/button/door{
id = "council blast";
@@ -41604,11 +41594,6 @@
},
/area/engine/atmos)
"bzc" = (
-/obj/machinery/atmospherics/components/binary/pump{
- dir = 8;
- name = "Distro to Waste";
- on = 0
- },
/obj/machinery/light{
dir = 1
},
@@ -41616,6 +41601,11 @@
dir = 1;
on = 1
},
+/obj/machinery/atmospherics/components/binary/pump{
+ dir = 8;
+ name = "Distro to Waste";
+ on = 0
+ },
/turf/open/floor/plasteel/caution{
dir = 1
},
@@ -42035,9 +42025,7 @@
"bzT" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 8;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/obj/machinery/vending/coffee{
pixel_x = -3
@@ -42155,9 +42143,7 @@
"bAg" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 2;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/obj/structure/extinguisher_cabinet{
pixel_x = 27
@@ -43639,9 +43625,7 @@
},
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 2;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/turf/open/floor/plasteel/neutral/corner{
dir = 1
@@ -43787,9 +43771,7 @@
},
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 2;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/turf/open/floor/plasteel/neutral/corner{
dir = 4
@@ -47556,9 +47538,7 @@
"bKz" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 8;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/turf/open/floor/plasteel,
/area/engine/atmos)
@@ -47986,9 +47966,7 @@
"bLs" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 1;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/obj/effect/turf_decal/stripes/line{
dir = 8
@@ -50400,9 +50378,7 @@
"bQa" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 1;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -50531,9 +50507,7 @@
},
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 2;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/turf/open/floor/wood,
/area/bridge/showroom/corporate)
@@ -50570,9 +50544,7 @@
"bQq" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 4;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/obj/structure/cable/yellow{
d1 = 1;
@@ -50641,9 +50613,7 @@
"bQu" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 8;
- on = 1;
- scrub_N2O = 1;
- scrub_Toxins = 1
+ on = 1
},
/obj/structure/cable/yellow{
d1 = 4;
@@ -57182,7 +57152,7 @@
"ccz" = (
/obj/item/weapon/wrench,
/obj/item/clothing/suit/apron,
-/obj/item/clothing/tie/armband/hydro,
+/obj/item/clothing/accessory/armband/hydro,
/obj/structure/table/glass,
/obj/effect/turf_decal/stripes/line{
dir = 9
diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm
index 16a623b495..f732a4dc79 100644
--- a/_maps/map_files/OmegaStation/OmegaStation.dmm
+++ b/_maps/map_files/OmegaStation/OmegaStation.dmm
@@ -2443,10 +2443,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 2
},
-/turf/open/floor/plating{
- tag = "icon-plating_warn_side (EAST)";
- icon_state = "plating_warn_side"
- },
+/turf/open/floor/plating,
/area/quartermaster/storage)
"aeg" = (
/obj/machinery/conveyor{
@@ -2457,10 +2454,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 2
},
-/turf/open/floor/plating{
- tag = "icon-plating_warn_side (EAST)";
- icon_state = "plating_warn_side"
- },
+/turf/open/floor/plating,
/area/quartermaster/storage)
"aeh" = (
/obj/machinery/conveyor{
@@ -2478,10 +2472,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 2
},
-/turf/open/floor/plating{
- tag = "icon-plating_warn_side (EAST)";
- icon_state = "plating_warn_side"
- },
+/turf/open/floor/plating,
/area/quartermaster/storage)
"aei" = (
/obj/machinery/conveyor{
@@ -4417,10 +4408,7 @@
dir = 9
},
/obj/effect/turf_decal/stripes/corner,
-/turf/open/floor/plating{
- tag = "icon-plating_warn_end (WEST)";
- icon_state = "plating_warn_end"
- },
+/turf/open/floor/plating,
/area/quartermaster/storage)
"aho" = (
/obj/machinery/conveyor{
@@ -4467,10 +4455,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/turf/open/floor/plating{
- tag = "icon-plating_warn_side (EAST)";
- icon_state = "plating_warn_side"
- },
+/turf/open/floor/plating,
/area/quartermaster/storage)
"ahr" = (
/obj/machinery/conveyor{
@@ -4485,10 +4470,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/turf/open/floor/plating{
- tag = "icon-plating_warn_side (EAST)";
- icon_state = "plating_warn_side"
- },
+/turf/open/floor/plating,
/area/quartermaster/storage)
"ahs" = (
/obj/machinery/conveyor{
@@ -4510,10 +4492,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/turf/open/floor/plating{
- tag = "icon-plating_warn_side (EAST)";
- icon_state = "plating_warn_side"
- },
+/turf/open/floor/plating,
/area/quartermaster/storage)
"aht" = (
/obj/machinery/door/poddoor{
diff --git a/_maps/map_files/generic/Centcomm.dmm b/_maps/map_files/generic/Centcomm.dmm
index d7df57e8ee..ac4d218ce2 100644
--- a/_maps/map_files/generic/Centcomm.dmm
+++ b/_maps/map_files/generic/Centcomm.dmm
@@ -5590,8 +5590,8 @@
/obj/item/clothing/under/skirt/black,
/obj/item/clothing/under/shorts/black,
/obj/item/clothing/under/pants/track,
-/obj/item/clothing/tie/armband/deputy,
-/obj/item/clothing/tie/waistcoat,
+/obj/item/clothing/accessory/armband/deputy,
+/obj/item/clothing/accessory/waistcoat,
/obj/item/clothing/shoes/jackboots,
/obj/item/clothing/shoes/laceup,
/obj/item/clothing/neck/stripedredscarf,
@@ -11175,7 +11175,7 @@
/obj/structure/rack,
/obj/item/clothing/head/that,
/obj/item/clothing/under/suit_jacket,
-/obj/item/clothing/tie/waistcoat,
+/obj/item/clothing/accessory/waistcoat,
/turf/open/floor/plasteel/cafeteria,
/area/centcom/holding)
"BI" = (
@@ -11379,7 +11379,7 @@
/obj/structure/sign/goldenplaque{
pixel_y = 32
},
-/obj/item/clothing/tie/lawyers_badge{
+/obj/item/clothing/accessory/lawyers_badge{
desc = "A badge of upmost glory.";
name = "thunderdome badge"
},
@@ -11400,7 +11400,7 @@
/obj/structure/sign/goldenplaque{
pixel_y = 32
},
-/obj/item/clothing/tie/medal/silver{
+/obj/item/clothing/accessory/medal/silver{
pixel_y = 5
},
/turf/open/floor/plasteel/grimy,
@@ -11605,11 +11605,11 @@
name = "Thunderdome Plaque";
pixel_y = -32
},
-/obj/item/clothing/tie/medal/gold{
+/obj/item/clothing/accessory/medal/gold{
pixel_x = 3;
pixel_y = 5
},
-/obj/item/clothing/tie/medal/gold,
+/obj/item/clothing/accessory/medal/gold,
/turf/open/floor/plasteel/grimy,
/area/tdome/tdomeobserve)
"CF" = (
@@ -11625,7 +11625,7 @@
name = "Thunderdome Plaque";
pixel_y = -32
},
-/obj/item/clothing/tie/medal{
+/obj/item/clothing/accessory/medal{
pixel_y = 5
},
/turf/open/floor/plasteel/grimy,
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index ab8fcb7d70..6ea8cd64ee 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -429,4 +429,8 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define GIBTONITE_UNSTRUCK 0
#define GIBTONITE_ACTIVE 1
#define GIBTONITE_STABLE 2
-#define GIBTONITE_DETONATE 3
\ No newline at end of file
+#define GIBTONITE_DETONATE 3
+//Gangster starting influences
+
+#define GANGSTER_SOLDIER_STARTING_INFLUENCE 5
+#define GANGSTER_BOSS_STARTING_INFLUENCE 20
diff --git a/code/controllers/subsystem/dbcore.dm b/code/controllers/subsystem/dbcore.dm
index b052b20f5d..864274b8fb 100644
--- a/code/controllers/subsystem/dbcore.dm
+++ b/code/controllers/subsystem/dbcore.dm
@@ -33,7 +33,7 @@ SUBSYSTEM_DEF(dbcore)
//This is as close as we can get to the true round end before Disconnect() without changing where it's called, defeating the reason this is a subsystem
if(SSdbcore.Connect())
var/sql_station_name = sanitizeSQL(station_name())
- var/datum/DBQuery/query_round_end = SSdbcore.NewQuery("INSERT INTO [format_table_name("round")] (end_datetime, game_mode_result, end_state, station_name) VALUES (Now(), '[SSticker.mode_result]', '[SSticker.end_state]', '[sql_station_name]') WHERE id = [GLOB.round_id]")
+ var/datum/DBQuery/query_round_end = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET end_datetime = Now(), game_mode_result = '[SSticker.mode_result]', end_state = '[SSticker.end_state]', station_name = '[sql_station_name]' WHERE id = [GLOB.round_id]")
query_round_end.Execute()
if(IsConnected())
Disconnect()
diff --git a/code/controllers/subsystem/processing/overlays.dm b/code/controllers/subsystem/processing/overlays.dm
index 4e1d2d64d5..c856ab165b 100644
--- a/code/controllers/subsystem/processing/overlays.dm
+++ b/code/controllers/subsystem/processing/overlays.dm
@@ -161,7 +161,7 @@ PROCESSING_SUBSYSTEM_DEF(overlays)
if(NOT_QUEUED_ALREADY && need_compile) //have we caught more pokemon?
QUEUE_FOR_COMPILE
-/atom/proc/copy_overlays(atom/other, cut_old = FALSE) //copys our_overlays from another atom
+/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom
if(!other)
if(cut_old)
cut_overlays()
@@ -190,3 +190,18 @@ PROCESSING_SUBSYSTEM_DEF(overlays)
/image/proc/cut_overlays(x)
overlays.Cut()
+
+/image/proc/copy_overlays(atom/other, cut_old)
+ if(!other)
+ if(cut_old)
+ cut_overlays()
+ return
+
+ var/list/cached_other = other.our_overlays
+ if(cached_other)
+ if(cut_old || !overlays.len)
+ overlays = cached_other.Copy()
+ else
+ overlays |= cached_other
+ else if(cut_old)
+ cut_overlays()
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 9dce620e25..e335669acc 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -581,43 +581,6 @@ SUBSYSTEM_DEF(ticker)
CHECK_TICK
- //Borers
- var/borerwin = FALSE
- if(GLOB.borers.len)
- var/borertext = "
The borers were:"
- for(var/mob/living/simple_animal/borer/B in GLOB.borers)
- if((B.key || B.controlling) && B.stat != DEAD)
- borertext += "
[B.controlling ? B.victim.key : B.key] was [B.truename] ("
- var/turf/location = get_turf(B)
- if(location.z == ZLEVEL_CENTCOM && B.victim)
- borertext += "escaped with host"
- else
- borertext += "failed"
- borertext += ")"
- to_chat(world, borertext)
-
- var/total_borers = 0
- for(var/mob/living/simple_animal/borer/B in GLOB.borers)
- if((B.key || B.victim) && B.stat != DEAD)
- total_borers++
- if(total_borers)
- var/total_borer_hosts = 0
- for(var/mob/living/carbon/C in GLOB.mob_list)
- var/mob/living/simple_animal/borer/D = C.has_brain_worms()
- var/turf/location = get_turf(C)
- if(location.z == ZLEVEL_CENTCOM && D && D.stat != DEAD)
- total_borer_hosts++
- if(GLOB.total_borer_hosts_needed <= total_borer_hosts)
- borerwin = TRUE
- to_chat(world, "There were [total_borers] borers alive at round end!")
- to_chat(world, "A total of [total_borer_hosts] borers with hosts escaped on the shuttle alive. The borers needed [GLOB.total_borer_hosts_needed] hosts to escape.")
- if(borerwin)
- to_chat(world, "The borers were successful!")
- else
- to_chat(world, "The borers have failed!")
-
- CHECK_TICK
-
mode.declare_station_goal_completion()
CHECK_TICK
diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm
index fbf6af136e..cc11d0e6d2 100644
--- a/code/datums/diseases/_disease.dm
+++ b/code/datums/diseases/_disease.dm
@@ -115,12 +115,19 @@
else
return
- if(isturf(source.loc))
+ var/turf/T = source.loc
+ if(istype(T))
for(var/mob/living/carbon/C in oview(spread_range, source))
- if(isturf(C.loc))
- if(AStar(source, C.loc,/turf/proc/Distance, spread_range, adjacent = (spread_flags & AIRBORNE) ? /turf/proc/reachableAdjacentAtmosTurfs : /turf/proc/reachableAdjacentTurfs))
- C.ContractDisease(src)
-
+ var/turf/V = get_turf(C)
+ if(V)
+ while(TRUE)
+ if(V == T)
+ C.ContractDisease(src)
+ break
+ var/turf/Temp = get_step_towards(V, T)
+ if(!CANATMOSPASS(V, Temp))
+ break
+ V = Temp
/datum/disease/process()
if(!holder)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index be5180c2ae..e1c6606400 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -989,7 +989,7 @@
if(!G || (src in G.bosses))
return
SSticker.mode.remove_gangster(src,0,2,1)
- G.bosses += src
+ G.bosses[src] = GANGSTER_BOSS_STARTING_INFLUENCE
gang_datum = G
special_role = "[G.name] Gang Boss"
G.add_gang_hud(src)
diff --git a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm
index e5d193d74a..914804185e 100644
--- a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm
+++ b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm
@@ -59,3 +59,6 @@
//changes construction value
/proc/change_construction_value(amount)
GLOB.clockwork_construction_value += amount
+
+/proc/can_recite_scripture(mob/living/L)
+ return (is_servant_of_ratvar(L) && L.stat == CONSCIOUS && L.can_speak_vocal() && (GLOB.ratvar_awakens || (ishuman(L) || issilicon(L))))
diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_armor.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_armor.dm
index 49c2bb4c13..3b0c220b87 100644
--- a/code/game/gamemodes/clock_cult/clock_items/clockwork_armor.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/clockwork_armor.dm
@@ -25,7 +25,7 @@
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
- flags &= STOPSPRESSUREDMAGE
+ flags &= ~STOPSPRESSUREDMAGE
max_heat_protection_temperature = initial(max_heat_protection_temperature)
min_cold_protection_temperature = initial(min_cold_protection_temperature)
@@ -81,7 +81,7 @@
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
- flags &= STOPSPRESSUREDMAGE
+ flags &= ~STOPSPRESSUREDMAGE
max_heat_protection_temperature = initial(max_heat_protection_temperature)
min_cold_protection_temperature = initial(min_cold_protection_temperature)
@@ -142,7 +142,7 @@
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
- flags &= STOPSPRESSUREDMAGE
+ flags &= ~STOPSPRESSUREDMAGE
max_heat_protection_temperature = initial(max_heat_protection_temperature)
min_cold_protection_temperature = initial(min_cold_protection_temperature)
@@ -194,7 +194,7 @@
if(GLOB.ratvar_awakens)
flags |= NOSLIP
else
- flags &= NOSLIP
+ flags &= ~NOSLIP
/obj/item/clothing/shoes/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
if(equipper && !is_servant_of_ratvar(equipper))
diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm
index 8b3aa01533..72dba26bed 100644
--- a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm
@@ -14,7 +14,6 @@
var/target_component_id //the target component ID to create, if any
var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks
var/speed_multiplier = 1 //multiples how fast this slab recites scripture
- var/nonhuman_usable = FALSE //if the slab can be used by nonhumans, defaults to off
var/produces_components = TRUE //if it produces components at all
var/selected_scripture = SCRIPTURE_DRIVER
var/recollecting = FALSE //if we're looking at fancy recollection
@@ -33,13 +32,9 @@
no_cost = TRUE
produces_components = FALSE
-/obj/item/clockwork/slab/scarab
- nonhuman_usable = TRUE
-
/obj/item/clockwork/slab/debug
speed_multiplier = 0
no_cost = TRUE
- nonhuman_usable = TRUE
/obj/item/clockwork/slab/debug/attack_hand(mob/living/user)
..()
@@ -49,7 +44,6 @@
/obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and proselytizer
clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture.\n\
Hitting a slab, a Servant with a slab, or a cache will transfer this slab's components into the target, the target's slab, or the global cache, respectively."
- nonhuman_usable = TRUE
quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \
/datum/clockwork_scripture/create_object/tinkerers_cache)
maximum_quickbound = 6 //we usually have one or two unique scriptures, so if ratvar is up let us bind one more
@@ -106,12 +100,6 @@
slab_ability = null
return ..()
-/obj/item/clockwork/slab/ratvar_act()
- if(GLOB.ratvar_awakens)
- nonhuman_usable = TRUE
- else
- nonhuman_usable = initial(nonhuman_usable)
-
/obj/item/clockwork/slab/dropped(mob/user)
. = ..()
addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later
@@ -138,7 +126,7 @@
production_time = world.time + SLAB_PRODUCTION_TIME + production_slowdown
var/mob/living/L
L = get_atom_on_turf(src, /mob/living)
- if(istype(L) && is_servant_of_ratvar(L) && (nonhuman_usable || ishuman(L)))
+ if(istype(L) && can_recite_scripture(L))
var/component_to_generate = target_component_id
if(!component_to_generate)
component_to_generate = get_weighted_component_id(src) //more likely to generate components that we have less of
@@ -268,7 +256,7 @@
if(busy)
to_chat(user, "[src] refuses to work, displaying the message: \"[busy]!\"")
return 0
- if(!nonhuman_usable && !ishuman(user))
+ if(!can_recite_scripture(user))
to_chat(user, "[src] hums fitfully in your hands, but doesn't seem to do anything...")
return 0
access_display(user)
@@ -288,7 +276,7 @@
ui.open()
/obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user)
- if(!scripture || !user || !user.canUseTopic(src) || (!nonhuman_usable && !ishuman(user)))
+ if(!scripture || !user || !user.canUseTopic(src) || !can_recite_scripture(user))
return FALSE
if(user.get_active_held_item() != src)
to_chat(user, "You need to hold the slab in your active hand to recite scripture!")
diff --git a/code/game/gamemodes/clock_cult/clock_scripture.dm b/code/game/gamemodes/clock_cult/clock_scripture.dm
index e8f1e8dbbc..9050d4569c 100644
--- a/code/game/gamemodes/clock_cult/clock_scripture.dm
+++ b/code/game/gamemodes/clock_cult/clock_scripture.dm
@@ -120,7 +120,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
if(multiple_invokers_used && !multiple_invokers_optional && !GLOB.ratvar_awakens && !slab.no_cost)
var/nearby_servants = 0
for(var/mob/living/L in range(1, get_turf(invoker)))
- if(is_servant_of_ratvar(L) && L.stat == CONSCIOUS && L.can_speak_vocal())
+ if(can_recite_scripture(L))
nearby_servants++
if(nearby_servants < invokers_required)
to_chat(invoker, "There aren't enough non-mute servants nearby ([nearby_servants]/[invokers_required])!")
@@ -170,7 +170,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
if(!channel_time && invocations.len)
if(multiple_invokers_used)
for(var/mob/living/L in range(1, invoker))
- if(is_servant_of_ratvar(L) && L.stat == CONSCIOUS && L.can_speak_vocal())
+ if(can_recite_scripture(L))
for(var/invocation in invocations)
clockwork_say(L, text2ratvar(invocation), whispered)
else
@@ -185,7 +185,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
return FALSE
if(multiple_invokers_used)
for(var/mob/living/L in range(1, get_turf(invoker)))
- if(is_servant_of_ratvar(L) && L.stat == CONSCIOUS && L.can_speak_vocal())
+ if(can_recite_scripture(L))
clockwork_say(L, text2ratvar(invocation), whispered)
else
clockwork_say(invoker, text2ratvar(invocation), whispered)
diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
index 21da8fab00..c3e40692c2 100644
--- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
+++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm
@@ -53,7 +53,7 @@
/datum/clockwork_scripture/fellowship_armory/run_scripture()
for(var/mob/living/L in orange(1, invoker))
- if(is_servant_of_ratvar(L) && L.stat == CONSCIOUS && L.can_speak_vocal())
+ if(can_recite_scripture(L))
channel_time = max(channel_time - 10, 0)
return ..()
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 4c03417aa9..85639f2180 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -1,567 +1,603 @@
-
-
-/*
- * GAMEMODES (by Rastaf0)
- *
- * In the new mode system all special roles are fully supported.
- * You can have proper wizards/traitors/changelings/cultists during any mode.
- * Only two things really depends on gamemode:
- * 1. Starting roles, equipment and preparations
- * 2. Conditions of finishing the round.
- *
- */
-
-
-/datum/game_mode
- var/name = "invalid"
- var/config_tag = null
- var/votable = 1
- var/probability = 0
- var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
- var/explosion_in_progress = 0 //sit back and relax
- var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such
- var/list/datum/mind/modePlayer = new
- var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here
- var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist
- var/list/protected_jobs = list() // Jobs that can't be traitors because
- var/required_players = 0
- var/maximum_players = -1 // -1 is no maximum, positive numbers limit the selection of a mode on overstaffed stations
- var/required_enemies = 0
- var/recommended_enemies = 0
- var/antag_flag = null //preferences flag such as BE_WIZARD that need to be turned on for players to be antag
- var/mob/living/living_antag_player = null
- var/list/datum/game_mode/replacementmode = null
- var/round_converted = 0 //0: round not converted, 1: round going to convert, 2: round converted
- var/reroll_friendly //During mode conversion only these are in the running
- var/continuous_sanity_checked //Catches some cases where config options could be used to suggest that modes without antagonists should end when all antagonists die
- var/enemy_minimum_age = 7 //How many days must players have been playing before they can play this antagonist
-
- var/announce_span = "warning" //The gamemode's name will be in this span during announcement.
- var/announce_text = "This gamemode forgot to set a descriptive text! Uh oh!" //Used to describe a gamemode when it's announced.
-
- var/const/waittime_l = 600
- var/const/waittime_h = 1800 // started at 1800
-
- var/list/datum/station_goal/station_goals = list()
-
-
-/datum/game_mode/proc/announce() //Shows the gamemode's name and a fast description.
- to_chat(world, "The gamemode is: [name]!")
- to_chat(world, "[announce_text]")
-
-
-///Checks to see if the game can be setup and ran with the current number of players or whatnot.
-/datum/game_mode/proc/can_start()
- var/playerC = 0
- for(var/mob/dead/new_player/player in GLOB.player_list)
- if((player.client)&&(player.ready))
- playerC++
- if(!GLOB.Debug2)
- if(playerC < required_players || (maximum_players >= 0 && playerC > maximum_players))
- return 0
- antag_candidates = get_players_for_role(antag_flag)
- if(!GLOB.Debug2)
- if(antag_candidates.len < required_enemies)
- return 0
- return 1
- else
- message_admins("DEBUG: GAME STARTING WITHOUT PLAYER NUMBER CHECKS, THIS WILL PROBABLY BREAK SHIT.")
- return 1
-
-
-///Attempts to select players for special roles the mode might have.
-/datum/game_mode/proc/pre_setup()
- return 1
-
-
-///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
-/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
- if(!report)
- report = config.intercept
- addtimer(CALLBACK(GLOBAL_PROC, .proc/display_roundstart_logout_report), ROUNDSTART_LOGOUT_REPORT_TIME)
-
- if(SSdbcore.Connect())
- var/sql
- if(SSticker && SSticker.mode)
- sql += "game_mode = '[SSticker.mode]'"
- if(sql)
- sql += ", "
- if(GLOB.revdata.commit)
- sql += "commit_hash = '[GLOB.revdata.commit]'"
- if(sql)
- var/datum/DBQuery/query_round_game_mode = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET [sql] WHERE id = [GLOB.round_id]")
- query_round_game_mode.Execute()
-
- if(report)
- addtimer(CALLBACK(src, .proc/send_intercept, 0), rand(waittime_l, waittime_h))
- generate_station_goals()
- return 1
-
-
-///Handles late-join antag assignments
-/datum/game_mode/proc/make_antag_chance(mob/living/carbon/human/character)
- if(replacementmode && round_converted == 2)
- replacementmode.make_antag_chance(character)
- return
-
-
-///Allows rounds to basically be "rerolled" should the initial premise fall through. Also known as mulligan antags.
-/datum/game_mode/proc/convert_roundtype()
- set waitfor = FALSE
- var/list/living_crew = list()
-
- for(var/mob/Player in GLOB.mob_list)
- if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player))
- living_crew += Player
- if(living_crew.len / GLOB.joined_player_list.len <= config.midround_antag_life_check) //If a lot of the player base died, we start fresh
- message_admins("Convert_roundtype failed due to too many dead people. Limit is [config.midround_antag_life_check * 100]% living crew")
- return null
-
- var/list/datum/game_mode/runnable_modes = config.get_runnable_midround_modes(living_crew.len)
- var/list/datum/game_mode/usable_modes = list()
- for(var/datum/game_mode/G in runnable_modes)
- if(G.reroll_friendly)
- usable_modes += G
- else
- qdel(G)
-
- if(!usable_modes)
- message_admins("Convert_roundtype failed due to no valid modes to convert to. Please report this error to the Coders.")
- return null
-
- replacementmode = pickweight(usable_modes)
-
- switch(SSshuttle.emergency.mode) //Rounds on the verge of ending don't get new antags, they just run out
- if(SHUTTLE_STRANDED, SHUTTLE_ESCAPE)
- return 1
- if(SHUTTLE_CALL)
- if(SSshuttle.emergency.timeLeft(1) < initial(SSshuttle.emergencyCallTime)*0.5)
- return 1
-
- if(world.time >= (config.midround_antag_time_check * 600))
- message_admins("Convert_roundtype failed due to round length. Limit is [config.midround_antag_time_check] minutes.")
- return null
-
- var/list/antag_candidates = list()
-
- for(var/mob/living/carbon/human/H in living_crew)
- if(H.client && H.client.prefs.allow_midround_antag)
- antag_candidates += H
-
- if(!antag_candidates)
- message_admins("Convert_roundtype failed due to no antag candidates.")
- return null
-
- antag_candidates = shuffle(antag_candidates)
-
- if(config.protect_roles_from_antagonist)
- replacementmode.restricted_jobs += replacementmode.protected_jobs
- if(config.protect_assistant_from_antagonist)
- replacementmode.restricted_jobs += "Assistant"
-
- message_admins("The roundtype will be converted. If you have other plans for the station or feel the station is too messed up to inhabit stop the creation of antags or end the round now.")
-
- . = 1
- sleep(rand(600,1800))
- //somewhere between 1 and 3 minutes from now
- if(!config.midround_antag[SSticker.mode.config_tag])
- round_converted = 0
- return 1
- for(var/mob/living/carbon/human/H in antag_candidates)
- replacementmode.make_antag_chance(H)
- round_converted = 2
- message_admins("-- IMPORTANT: The roundtype has been converted to [replacementmode.name], antagonists may have been created! --")
-
-
-///Called by the gameSSticker
-/datum/game_mode/process()
- return 0
-
-
-/datum/game_mode/proc/check_finished() //to be called by SSticker
- if(replacementmode && round_converted == 2)
- return replacementmode.check_finished()
- if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME))
- return TRUE
- if(station_was_nuked)
- return TRUE
- if(!round_converted && (!config.continuous[config_tag] || (config.continuous[config_tag] && config.midround_antag[config_tag]))) //Non-continuous or continous with replacement antags
- if(!continuous_sanity_checked) //make sure we have antags to be checking in the first place
- for(var/mob/Player in GLOB.mob_list)
- if(Player.mind)
- if(Player.mind.special_role)
- continuous_sanity_checked = 1
- return 0
- if(!continuous_sanity_checked)
- message_admins("The roundtype ([config_tag]) has no antagonists, continuous round has been defaulted to on and midround_antag has been defaulted to off.")
- config.continuous[config_tag] = 1
- config.midround_antag[config_tag] = 0
- SSshuttle.clearHostileEnvironment(src)
- return 0
-
-
- if(living_antag_player && living_antag_player.mind && isliving(living_antag_player) && living_antag_player.stat != DEAD && !isnewplayer(living_antag_player) &&!isbrain(living_antag_player))
- return 0 //A resource saver: once we find someone who has to die for all antags to be dead, we can just keep checking them, cycling over everyone only when we lose our mark.
-
- for(var/mob/Player in GLOB.living_mob_list)
- if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player))
- if(Player.mind.special_role) //Someone's still antaging!
- living_antag_player = Player
- return 0
-
- if(!config.continuous[config_tag])
- return 1
-
- else
- round_converted = convert_roundtype()
- if(!round_converted)
- if(round_ends_with_antag_death)
- return 1
- else
- config.midround_antag[config_tag] = 0
- return 0
-
- return 0
-
-
-/datum/game_mode/proc/declare_completion()
- var/clients = 0
- var/surviving_humans = 0
- var/surviving_total = 0
- var/ghosts = 0
- var/escaped_humans = 0
- var/escaped_total = 0
-
- for(var/mob/M in GLOB.player_list)
- if(M.client)
- clients++
- if(ishuman(M))
- if(!M.stat)
- surviving_humans++
- if(M.z == ZLEVEL_CENTCOM)
- escaped_humans++
- if(!M.stat)
- surviving_total++
- if(M.z == ZLEVEL_CENTCOM)
- escaped_total++
-
-
- if(isobserver(M))
- ghosts++
-
- if(clients > 0)
- SSblackbox.set_val("round_end_clients",clients)
- if(ghosts > 0)
- SSblackbox.set_val("round_end_ghosts",ghosts)
- if(surviving_humans > 0)
- SSblackbox.set_val("survived_human",surviving_humans)
- if(surviving_total > 0)
- SSblackbox.set_val("survived_total",surviving_total)
- if(escaped_humans > 0)
- SSblackbox.set_val("escaped_human",escaped_humans)
- if(escaped_total > 0)
- SSblackbox.set_val("escaped_total",escaped_total)
- send2irc("Server", "Round just ended.")
- if(cult.len && !istype(SSticker.mode,/datum/game_mode/cult))
- datum_cult_completion()
- return 0
-
-
-/datum/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere.
- return 0
-
-
-/datum/game_mode/proc/send_intercept()
- var/intercepttext = "Central Command Status Summary
"
- intercepttext += "Central Command has intercepted and partially decoded a Syndicate transmission with vital information regarding their movements. The following report outlines the most \
- likely threats to appear in your sector."
- var/list/possible_modes = list()
- possible_modes.Add("blob", "changeling", "clock_cult", "cult", "extended", "gang", "malf", "nuclear", "revolution", "traitor", "wizard")
- possible_modes -= name //remove the current gamemode to prevent it from being randomly deleted, it will be readded later
-
- for(var/i in 1 to 6) //Remove a few modes to leave four
- possible_modes -= pick(possible_modes)
-
- possible_modes |= name //Re-add the actual gamemode - the intercept will thus always have the correct mode in its list
- possible_modes = shuffle(possible_modes) //Meta prevention
-
- var/datum/intercept_text/i_text = new /datum/intercept_text
- for(var/V in possible_modes)
- intercepttext += i_text.build(V)
-
- if(station_goals.len)
- intercepttext += "
Special Orders for [station_name()]:"
- for(var/datum/station_goal/G in station_goals)
- G.on_report()
- intercepttext += G.get_report()
-
- print_command_report(intercepttext, "Central Command Status Summary", announce=FALSE)
- priority_announce("A summary has been copied and printed to all communications consoles.", "Enemy communication intercepted. Security level elevated.", 'sound/AI/intercept.ogg')
- if(GLOB.security_level < SEC_LEVEL_BLUE)
- set_security_level(SEC_LEVEL_BLUE)
-
-
-/datum/game_mode/proc/get_players_for_role(role)
- var/list/players = list()
- var/list/candidates = list()
- var/list/drafted = list()
- var/datum/mind/applicant = null
-
- // Ultimate randomizing code right here
- for(var/mob/dead/new_player/player in GLOB.player_list)
- if(player.client && player.ready)
- players += player
-
- // Shuffling, the players list is now ping-independent!!!
- // Goodbye antag dante
- players = shuffle(players)
-
- for(var/mob/dead/new_player/player in players)
- if(player.client && player.ready)
- if(role in player.client.prefs.be_special)
- if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, role)) //Nodrak/Carn: Antag Job-bans
- if(age_check(player.client)) //Must be older than the minimum age
- candidates += player.mind // Get a list of all the people who want to be the antagonist for this round
-
- if(restricted_jobs)
- for(var/datum/mind/player in candidates)
- for(var/job in restricted_jobs) // Remove people who want to be antagonist but have a job already that precludes it
- if(player.assigned_role == job)
- candidates -= player
-
- if(candidates.len < recommended_enemies)
- for(var/mob/dead/new_player/player in players)
- if(player.client && player.ready)
- if(!(role in player.client.prefs.be_special)) // We don't have enough people who want to be antagonist, make a seperate list of people who don't want to be one
- if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, role)) //Nodrak/Carn: Antag Job-bans
- drafted += player.mind
-
- if(restricted_jobs)
- for(var/datum/mind/player in drafted) // Remove people who can't be an antagonist
- for(var/job in restricted_jobs)
- if(player.assigned_role == job)
- drafted -= player
-
- drafted = shuffle(drafted) // Will hopefully increase randomness, Donkie
-
- while(candidates.len < recommended_enemies) // Pick randomlly just the number of people we need and add them to our list of candidates
- if(drafted.len > 0)
- applicant = pick(drafted)
- if(applicant)
- candidates += applicant
- drafted.Remove(applicant)
-
- else // Not enough scrubs, ABORT ABORT ABORT
- break
-/*
- if(candidates.len < recommended_enemies && override_jobbans) //If we still don't have enough people, we're going to start drafting banned people.
- for(var/mob/dead/new_player/player in players)
- if (player.client && player.ready)
- if(jobban_isbanned(player, "Syndicate") || jobban_isbanned(player, roletext)) //Nodrak/Carn: Antag Job-bans
- drafted += player.mind
-*/
- if(restricted_jobs)
- for(var/datum/mind/player in drafted) // Remove people who can't be an antagonist
- for(var/job in restricted_jobs)
- if(player.assigned_role == job)
- drafted -= player
-
- drafted = shuffle(drafted) // Will hopefully increase randomness, Donkie
-
- while(candidates.len < recommended_enemies) // Pick randomlly just the number of people we need and add them to our list of candidates
- if(drafted.len > 0)
- applicant = pick(drafted)
- if(applicant)
- candidates += applicant
- drafted.Remove(applicant)
-
- else // Not enough scrubs, ABORT ABORT ABORT
- break
-
- return candidates // Returns: The number of people who had the antagonist role set to yes, regardless of recomended_enemies, if that number is greater than recommended_enemies
- // recommended_enemies if the number of people with that role set to yes is less than recomended_enemies,
- // Less if there are not enough valid players in the game entirely to make recommended_enemies.
-
-/*
-/datum/game_mode/proc/check_player_role_pref(var/role, var/mob/dead/new_player/player)
- if(player.preferences.be_special & role)
- return 1
- return 0
-*/
-
-/datum/game_mode/proc/num_players()
- . = 0
- for(var/mob/dead/new_player/P in GLOB.player_list)
- if(P.client && P.ready)
- . ++
-
-///////////////////////////////////
-//Keeps track of all living heads//
-///////////////////////////////////
-/datum/game_mode/proc/get_living_heads()
- . = list()
- for(var/mob/living/carbon/human/player in GLOB.mob_list)
- if(player.stat != DEAD && player.mind && (player.mind.assigned_role in GLOB.command_positions))
- . |= player.mind
-
-
-////////////////////////////
-//Keeps track of all heads//
-////////////////////////////
-/datum/game_mode/proc/get_all_heads()
- . = list()
- for(var/mob/player in GLOB.mob_list)
- if(player.mind && (player.mind.assigned_role in GLOB.command_positions))
- . |= player.mind
-
-//////////////////////////////////////////////
-//Keeps track of all living security members//
-//////////////////////////////////////////////
-/datum/game_mode/proc/get_living_sec()
- . = list()
- for(var/mob/living/carbon/human/player in GLOB.mob_list)
- if(player.stat != DEAD && player.mind && (player.mind.assigned_role in GLOB.security_positions))
- . |= player.mind
-
-////////////////////////////////////////
-//Keeps track of all security members//
-////////////////////////////////////////
-/datum/game_mode/proc/get_all_sec()
- . = list()
- for(var/mob/living/carbon/human/player in GLOB.mob_list)
- if(player.mind && (player.mind.assigned_role in GLOB.security_positions))
- . |= player.mind
-
-//////////////////////////
-//Reports player logouts//
-//////////////////////////
-/proc/display_roundstart_logout_report()
- var/msg = "Roundstart logout report\n\n"
- for(var/mob/living/L in GLOB.mob_list)
-
- if(L.ckey)
- var/found = 0
- for(var/client/C in GLOB.clients)
- if(C.ckey == L.ckey)
- found = 1
- break
- if(!found)
- msg += "[L.name] ([L.ckey]), the [L.job] (Disconnected)\n"
-
-
- if(L.ckey && L.client)
- if(L.client.inactivity >= (ROUNDSTART_LOGOUT_REPORT_TIME / 2)) //Connected, but inactive (alt+tabbed or something)
- msg += "[L.name] ([L.ckey]), the [L.job] (Connected, Inactive)\n"
- continue //AFK client
- if(L.stat)
- if(L.suiciding) //Suicider
- msg += "[L.name] ([L.ckey]), the [L.job] (Suicide)\n"
- continue //Disconnected client
- if(L.stat == UNCONSCIOUS)
- msg += "[L.name] ([L.ckey]), the [L.job] (Dying)\n"
- continue //Unconscious
- if(L.stat == DEAD)
- msg += "[L.name] ([L.ckey]), the [L.job] (Dead)\n"
- continue //Dead
-
- continue //Happy connected client
- for(var/mob/dead/observer/D in GLOB.mob_list)
- if(D.mind && D.mind.current == L)
- if(L.stat == DEAD)
- if(L.suiciding) //Suicider
- msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Suicide)\n"
- continue //Disconnected client
- else
- msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Dead)\n"
- continue //Dead mob, ghost abandoned
- else
- if(D.can_reenter_corpse)
- continue //Adminghost, or cult/wizard ghost
- else
- msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Ghosted)\n"
- continue //Ghosted while alive
-
-
-
- for(var/mob/M in GLOB.mob_list)
- if(M.client && M.client.holder)
- to_chat(M, msg)
-
-/datum/game_mode/proc/printplayer(datum/mind/ply, fleecheck)
- var/text = "
[ply.key] was [ply.name] the [ply.assigned_role] and"
- if(ply.current)
- if(ply.current.stat == DEAD)
- text += " died"
- else
- text += " survived"
- if(fleecheck && ply.current.z > ZLEVEL_STATION)
- text += " while fleeing the station"
- if(ply.current.real_name != ply.name)
- text += " as [ply.current.real_name]"
- else
- text += " had their body destroyed"
- return text
-
-/datum/game_mode/proc/printobjectives(datum/mind/ply)
- var/text = ""
- var/count = 1
- for(var/datum/objective/objective in ply.objectives)
- if(objective.check_completion())
- text += "
Objective #[count]: [objective.explanation_text] Success!"
- else
- text += "
Objective #[count]: [objective.explanation_text] Fail."
- count++
- return text
-
-//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
-/datum/game_mode/proc/age_check(client/C)
- if(get_remaining_days(C) == 0)
- return 1 //Available in 0 days = available right now = player is old enough to play.
- return 0
-
-
-/datum/game_mode/proc/get_remaining_days(client/C)
- if(!C)
- return 0
- if(!config.use_age_restriction_for_jobs)
- return 0
- if(!isnum(C.player_age))
- return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced
- if(!isnum(enemy_minimum_age))
- return 0
-
- return max(0, enemy_minimum_age - C.player_age)
-
-/datum/game_mode/proc/replace_jobbaned_player(mob/living/M, role_type, pref)
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [role_type]?", "[role_type]", null, pref, 50, M)
- var/mob/dead/observer/theghost = null
- if(candidates.len)
- theghost = pick(candidates)
- to_chat(M, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
- message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(M)]) to replace a jobbaned player.")
- M.ghostize(0)
- M.key = theghost.key
-
-/datum/game_mode/proc/remove_antag_for_borging(datum/mind/newborgie)
- SSticker.mode.remove_cultist(newborgie, 0, 0)
- SSticker.mode.remove_revolutionary(newborgie, 0)
- SSticker.mode.remove_gangster(newborgie, 0, remove_bosses=1)
-
-/datum/game_mode/proc/generate_station_goals()
- var/list/possible = list()
- for(var/T in subtypesof(/datum/station_goal))
- var/datum/station_goal/G = T
- if(config_tag in initial(G.gamemode_blacklist))
- continue
- possible += T
- var/goal_weights = 0
- while(possible.len && goal_weights < STATION_GOAL_BUDGET)
- var/datum/station_goal/picked = pick_n_take(possible)
- goal_weights += initial(picked.weight)
- station_goals += new picked
-
-
-/datum/game_mode/proc/declare_station_goal_completion()
- for(var/V in station_goals)
- var/datum/station_goal/G = V
- G.print_result()
+
+
+/*
+ * GAMEMODES (by Rastaf0)
+ *
+ * In the new mode system all special roles are fully supported.
+ * You can have proper wizards/traitors/changelings/cultists during any mode.
+ * Only two things really depends on gamemode:
+ * 1. Starting roles, equipment and preparations
+ * 2. Conditions of finishing the round.
+ *
+ */
+
+
+/datum/game_mode
+ var/name = "invalid"
+ var/config_tag = null
+ var/votable = 1
+ var/probability = 0
+ var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
+ var/explosion_in_progress = 0 //sit back and relax
+ var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such
+ var/list/datum/mind/modePlayer = new
+ var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here
+ var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist
+ var/list/protected_jobs = list() // Jobs that can't be traitors because
+ var/required_players = 0
+ var/maximum_players = -1 // -1 is no maximum, positive numbers limit the selection of a mode on overstaffed stations
+ var/required_enemies = 0
+ var/recommended_enemies = 0
+ var/antag_flag = null //preferences flag such as BE_WIZARD that need to be turned on for players to be antag
+ var/mob/living/living_antag_player = null
+ var/list/datum/game_mode/replacementmode = null
+ var/round_converted = 0 //0: round not converted, 1: round going to convert, 2: round converted
+ var/reroll_friendly //During mode conversion only these are in the running
+ var/continuous_sanity_checked //Catches some cases where config options could be used to suggest that modes without antagonists should end when all antagonists die
+ var/enemy_minimum_age = 7 //How many days must players have been playing before they can play this antagonist
+
+ var/announce_span = "warning" //The gamemode's name will be in this span during announcement.
+ var/announce_text = "This gamemode forgot to set a descriptive text! Uh oh!" //Used to describe a gamemode when it's announced.
+
+ var/const/waittime_l = 600
+ var/const/waittime_h = 1800 // started at 1800
+
+ var/list/datum/station_goal/station_goals = list()
+
+
+/datum/game_mode/proc/announce() //Shows the gamemode's name and a fast description.
+ to_chat(world, "The gamemode is: [name]!")
+ to_chat(world, "[announce_text]")
+
+
+///Checks to see if the game can be setup and ran with the current number of players or whatnot.
+/datum/game_mode/proc/can_start()
+ var/playerC = 0
+ for(var/mob/dead/new_player/player in GLOB.player_list)
+ if((player.client)&&(player.ready))
+ playerC++
+ if(!GLOB.Debug2)
+ if(playerC < required_players || (maximum_players >= 0 && playerC > maximum_players))
+ return 0
+ antag_candidates = get_players_for_role(antag_flag)
+ if(!GLOB.Debug2)
+ if(antag_candidates.len < required_enemies)
+ return 0
+ return 1
+ else
+ message_admins("DEBUG: GAME STARTING WITHOUT PLAYER NUMBER CHECKS, THIS WILL PROBABLY BREAK SHIT.")
+ return 1
+
+
+///Attempts to select players for special roles the mode might have.
+/datum/game_mode/proc/pre_setup()
+ return 1
+
+
+///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
+/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
+ if(!report)
+ report = config.intercept
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/display_roundstart_logout_report), ROUNDSTART_LOGOUT_REPORT_TIME)
+
+ if(SSdbcore.Connect())
+ var/sql
+ if(SSticker && SSticker.mode)
+ sql += "game_mode = '[SSticker.mode]'"
+ if(GLOB.revdata.originmastercommit)
+ if(sql)
+ sql += ", "
+ sql += "commit_hash = '[GLOB.revdata.originmastercommit]'"
+ if(sql)
+ var/datum/DBQuery/query_round_game_mode = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET [sql] WHERE id = [GLOB.round_id]")
+ query_round_game_mode.Execute()
+ if(report)
+ addtimer(CALLBACK(src, .proc/send_intercept, 0), rand(waittime_l, waittime_h))
+ generate_station_goals()
+ return 1
+
+
+///Handles late-join antag assignments
+/datum/game_mode/proc/make_antag_chance(mob/living/carbon/human/character)
+ if(replacementmode && round_converted == 2)
+ replacementmode.make_antag_chance(character)
+ return
+
+
+///Allows rounds to basically be "rerolled" should the initial premise fall through. Also known as mulligan antags.
+/datum/game_mode/proc/convert_roundtype()
+ set waitfor = FALSE
+ var/list/living_crew = list()
+
+ for(var/mob/Player in GLOB.mob_list)
+ if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player))
+ living_crew += Player
+ if(living_crew.len / GLOB.joined_player_list.len <= config.midround_antag_life_check) //If a lot of the player base died, we start fresh
+ message_admins("Convert_roundtype failed due to too many dead people. Limit is [config.midround_antag_life_check * 100]% living crew")
+ return null
+
+ var/list/datum/game_mode/runnable_modes = config.get_runnable_midround_modes(living_crew.len)
+ var/list/datum/game_mode/usable_modes = list()
+ for(var/datum/game_mode/G in runnable_modes)
+ if(G.reroll_friendly)
+ usable_modes += G
+ else
+ qdel(G)
+
+ if(!usable_modes)
+ message_admins("Convert_roundtype failed due to no valid modes to convert to. Please report this error to the Coders.")
+ return null
+
+ replacementmode = pickweight(usable_modes)
+
+ switch(SSshuttle.emergency.mode) //Rounds on the verge of ending don't get new antags, they just run out
+ if(SHUTTLE_STRANDED, SHUTTLE_ESCAPE)
+ return 1
+ if(SHUTTLE_CALL)
+ if(SSshuttle.emergency.timeLeft(1) < initial(SSshuttle.emergencyCallTime)*0.5)
+ return 1
+
+ if(world.time >= (config.midround_antag_time_check * 600))
+ message_admins("Convert_roundtype failed due to round length. Limit is [config.midround_antag_time_check] minutes.")
+ return null
+
+ var/list/antag_candidates = list()
+
+ for(var/mob/living/carbon/human/H in living_crew)
+ if(H.client && H.client.prefs.allow_midround_antag)
+ antag_candidates += H
+
+ if(!antag_candidates)
+ message_admins("Convert_roundtype failed due to no antag candidates.")
+ return null
+
+ antag_candidates = shuffle(antag_candidates)
+
+ if(config.protect_roles_from_antagonist)
+ replacementmode.restricted_jobs += replacementmode.protected_jobs
+ if(config.protect_assistant_from_antagonist)
+ replacementmode.restricted_jobs += "Assistant"
+
+ message_admins("The roundtype will be converted. If you have other plans for the station or feel the station is too messed up to inhabit stop the creation of antags or end the round now.")
+
+ . = 1
+ sleep(rand(600,1800))
+ //somewhere between 1 and 3 minutes from now
+ if(!config.midround_antag[SSticker.mode.config_tag])
+ round_converted = 0
+ return 1
+ for(var/mob/living/carbon/human/H in antag_candidates)
+ replacementmode.make_antag_chance(H)
+ round_converted = 2
+ message_admins("-- IMPORTANT: The roundtype has been converted to [replacementmode.name], antagonists may have been created! --")
+
+
+///Called by the gameSSticker
+/datum/game_mode/process()
+ return 0
+
+
+/datum/game_mode/proc/check_finished() //to be called by SSticker
+ if(replacementmode && round_converted == 2)
+ return replacementmode.check_finished()
+ if(SSshuttle.emergency && (SSshuttle.emergency.mode == SHUTTLE_ENDGAME))
+ return TRUE
+ if(station_was_nuked)
+ return TRUE
+ if(!round_converted && (!config.continuous[config_tag] || (config.continuous[config_tag] && config.midround_antag[config_tag]))) //Non-continuous or continous with replacement antags
+ if(!continuous_sanity_checked) //make sure we have antags to be checking in the first place
+ for(var/mob/Player in GLOB.mob_list)
+ if(Player.mind)
+ if(Player.mind.special_role)
+ continuous_sanity_checked = 1
+ return 0
+ if(!continuous_sanity_checked)
+ message_admins("The roundtype ([config_tag]) has no antagonists, continuous round has been defaulted to on and midround_antag has been defaulted to off.")
+ config.continuous[config_tag] = 1
+ config.midround_antag[config_tag] = 0
+ SSshuttle.clearHostileEnvironment(src)
+ return 0
+
+
+ if(living_antag_player && living_antag_player.mind && isliving(living_antag_player) && living_antag_player.stat != DEAD && !isnewplayer(living_antag_player) &&!isbrain(living_antag_player))
+ return 0 //A resource saver: once we find someone who has to die for all antags to be dead, we can just keep checking them, cycling over everyone only when we lose our mark.
+
+ for(var/mob/Player in GLOB.living_mob_list)
+ if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player))
+ if(Player.mind.special_role) //Someone's still antaging!
+ living_antag_player = Player
+ return 0
+
+ if(!config.continuous[config_tag])
+ return 1
+
+ else
+ round_converted = convert_roundtype()
+ if(!round_converted)
+ if(round_ends_with_antag_death)
+ return 1
+ else
+ config.midround_antag[config_tag] = 0
+ return 0
+
+ return 0
+
+
+/datum/game_mode/proc/declare_completion()
+ var/clients = 0
+ var/surviving_humans = 0
+ var/surviving_total = 0
+ var/ghosts = 0
+ var/escaped_humans = 0
+ var/escaped_total = 0
+
+ for(var/mob/M in GLOB.player_list)
+ if(M.client)
+ clients++
+ if(ishuman(M))
+ if(!M.stat)
+ surviving_humans++
+ if(M.z == ZLEVEL_CENTCOM)
+ escaped_humans++
+ if(!M.stat)
+ surviving_total++
+ if(M.z == ZLEVEL_CENTCOM)
+ escaped_total++
+
+
+ if(isobserver(M))
+ ghosts++
+
+ if(clients > 0)
+ SSblackbox.set_val("round_end_clients",clients)
+ if(ghosts > 0)
+ SSblackbox.set_val("round_end_ghosts",ghosts)
+ if(surviving_humans > 0)
+ SSblackbox.set_val("survived_human",surviving_humans)
+ if(surviving_total > 0)
+ SSblackbox.set_val("survived_total",surviving_total)
+ if(escaped_humans > 0)
+ SSblackbox.set_val("escaped_human",escaped_humans)
+ if(escaped_total > 0)
+ SSblackbox.set_val("escaped_total",escaped_total)
+ send2irc("Server", "Round just ended.")
+ if(cult.len && !istype(SSticker.mode,/datum/game_mode/cult))
+ datum_cult_completion()
+
+ if(GLOB.borers.len)
+ var/borerwin = FALSE
+ var/borertext = "
The borers were:"
+ for(var/mob/living/simple_animal/borer/B in GLOB.borers)
+ if((B.key || B.controlling) && B.stat != DEAD)
+ borertext += "
[B.controlling ? B.victim.key : B.key] was [B.truename] ("
+ var/turf/location = get_turf(B)
+ if(location.z == ZLEVEL_CENTCOM && B.victim)
+ borertext += "escaped with host"
+ else
+ borertext += "failed"
+ borertext += ")"
+ to_chat(world, borertext)
+
+ var/total_borers = 0
+ for(var/mob/living/simple_animal/borer/B in GLOB.borers)
+ if((B.key || B.victim) && B.stat != DEAD)
+ total_borers++
+ if(total_borers)
+ var/total_borer_hosts = 0
+ for(var/mob/living/carbon/C in GLOB.mob_list)
+ var/mob/living/simple_animal/borer/D = C.has_brain_worms()
+ var/turf/location = get_turf(C)
+ if(location.z == ZLEVEL_CENTCOM && D && D.stat != DEAD)
+ total_borer_hosts++
+ if(GLOB.total_borer_hosts_needed <= total_borer_hosts)
+ borerwin = TRUE
+ to_chat(world, "There were [total_borers] borers alive at round end!")
+ to_chat(world, "A total of [total_borer_hosts] borers with hosts escaped on the shuttle alive. The borers needed [GLOB.total_borer_hosts_needed] hosts to escape.")
+ if(borerwin)
+ to_chat(world, "The borers were successful!")
+ else
+ to_chat(world, "The borers have failed!")
+
+ CHECK_TICK
+
+ return 0
+
+
+/datum/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere.
+ return 0
+
+
+/datum/game_mode/proc/send_intercept()
+ var/intercepttext = "Central Command Status Summary
"
+ intercepttext += "Central Command has intercepted and partially decoded a Syndicate transmission with vital information regarding their movements. The following report outlines the most \
+ likely threats to appear in your sector."
+ var/list/possible_modes = list()
+ possible_modes.Add("blob", "changeling", "clock_cult", "cult", "extended", "gang", "malf", "nuclear", "revolution", "traitor", "wizard")
+ possible_modes -= name //remove the current gamemode to prevent it from being randomly deleted, it will be readded later
+
+ for(var/i in 1 to 6) //Remove a few modes to leave four
+ possible_modes -= pick(possible_modes)
+
+ possible_modes |= name //Re-add the actual gamemode - the intercept will thus always have the correct mode in its list
+ possible_modes = shuffle(possible_modes) //Meta prevention
+
+ var/datum/intercept_text/i_text = new /datum/intercept_text
+ for(var/V in possible_modes)
+ intercepttext += i_text.build(V)
+
+ if(station_goals.len)
+ intercepttext += "
Special Orders for [station_name()]:"
+ for(var/datum/station_goal/G in station_goals)
+ G.on_report()
+ intercepttext += G.get_report()
+
+ print_command_report(intercepttext, "Central Command Status Summary", announce=FALSE)
+ priority_announce("A summary has been copied and printed to all communications consoles.", "Enemy communication intercepted. Security level elevated.", 'sound/AI/intercept.ogg')
+ if(GLOB.security_level < SEC_LEVEL_BLUE)
+ set_security_level(SEC_LEVEL_BLUE)
+
+
+/datum/game_mode/proc/get_players_for_role(role)
+ var/list/players = list()
+ var/list/candidates = list()
+ var/list/drafted = list()
+ var/datum/mind/applicant = null
+
+ // Ultimate randomizing code right here
+ for(var/mob/dead/new_player/player in GLOB.player_list)
+ if(player.client && player.ready)
+ players += player
+
+ // Shuffling, the players list is now ping-independent!!!
+ // Goodbye antag dante
+ players = shuffle(players)
+
+ for(var/mob/dead/new_player/player in players)
+ if(player.client && player.ready)
+ if(role in player.client.prefs.be_special)
+ if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, role)) //Nodrak/Carn: Antag Job-bans
+ if(age_check(player.client)) //Must be older than the minimum age
+ candidates += player.mind // Get a list of all the people who want to be the antagonist for this round
+
+ if(restricted_jobs)
+ for(var/datum/mind/player in candidates)
+ for(var/job in restricted_jobs) // Remove people who want to be antagonist but have a job already that precludes it
+ if(player.assigned_role == job)
+ candidates -= player
+
+ if(candidates.len < recommended_enemies)
+ for(var/mob/dead/new_player/player in players)
+ if(player.client && player.ready)
+ if(!(role in player.client.prefs.be_special)) // We don't have enough people who want to be antagonist, make a seperate list of people who don't want to be one
+ if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, role)) //Nodrak/Carn: Antag Job-bans
+ drafted += player.mind
+
+ if(restricted_jobs)
+ for(var/datum/mind/player in drafted) // Remove people who can't be an antagonist
+ for(var/job in restricted_jobs)
+ if(player.assigned_role == job)
+ drafted -= player
+
+ drafted = shuffle(drafted) // Will hopefully increase randomness, Donkie
+
+ while(candidates.len < recommended_enemies) // Pick randomlly just the number of people we need and add them to our list of candidates
+ if(drafted.len > 0)
+ applicant = pick(drafted)
+ if(applicant)
+ candidates += applicant
+ drafted.Remove(applicant)
+
+ else // Not enough scrubs, ABORT ABORT ABORT
+ break
+/*
+ if(candidates.len < recommended_enemies && override_jobbans) //If we still don't have enough people, we're going to start drafting banned people.
+ for(var/mob/dead/new_player/player in players)
+ if (player.client && player.ready)
+ if(jobban_isbanned(player, "Syndicate") || jobban_isbanned(player, roletext)) //Nodrak/Carn: Antag Job-bans
+ drafted += player.mind
+*/
+ if(restricted_jobs)
+ for(var/datum/mind/player in drafted) // Remove people who can't be an antagonist
+ for(var/job in restricted_jobs)
+ if(player.assigned_role == job)
+ drafted -= player
+
+ drafted = shuffle(drafted) // Will hopefully increase randomness, Donkie
+
+ while(candidates.len < recommended_enemies) // Pick randomlly just the number of people we need and add them to our list of candidates
+ if(drafted.len > 0)
+ applicant = pick(drafted)
+ if(applicant)
+ candidates += applicant
+ drafted.Remove(applicant)
+
+ else // Not enough scrubs, ABORT ABORT ABORT
+ break
+
+ return candidates // Returns: The number of people who had the antagonist role set to yes, regardless of recomended_enemies, if that number is greater than recommended_enemies
+ // recommended_enemies if the number of people with that role set to yes is less than recomended_enemies,
+ // Less if there are not enough valid players in the game entirely to make recommended_enemies.
+
+/*
+/datum/game_mode/proc/check_player_role_pref(var/role, var/mob/dead/new_player/player)
+ if(player.preferences.be_special & role)
+ return 1
+ return 0
+*/
+
+/datum/game_mode/proc/num_players()
+ . = 0
+ for(var/mob/dead/new_player/P in GLOB.player_list)
+ if(P.client && P.ready)
+ . ++
+
+///////////////////////////////////
+//Keeps track of all living heads//
+///////////////////////////////////
+/datum/game_mode/proc/get_living_heads()
+ . = list()
+ for(var/mob/living/carbon/human/player in GLOB.mob_list)
+ if(player.stat != DEAD && player.mind && (player.mind.assigned_role in GLOB.command_positions))
+ . |= player.mind
+
+
+////////////////////////////
+//Keeps track of all heads//
+////////////////////////////
+/datum/game_mode/proc/get_all_heads()
+ . = list()
+ for(var/mob/player in GLOB.mob_list)
+ if(player.mind && (player.mind.assigned_role in GLOB.command_positions))
+ . |= player.mind
+
+//////////////////////////////////////////////
+//Keeps track of all living security members//
+//////////////////////////////////////////////
+/datum/game_mode/proc/get_living_sec()
+ . = list()
+ for(var/mob/living/carbon/human/player in GLOB.mob_list)
+ if(player.stat != DEAD && player.mind && (player.mind.assigned_role in GLOB.security_positions))
+ . |= player.mind
+
+////////////////////////////////////////
+//Keeps track of all security members//
+////////////////////////////////////////
+/datum/game_mode/proc/get_all_sec()
+ . = list()
+ for(var/mob/living/carbon/human/player in GLOB.mob_list)
+ if(player.mind && (player.mind.assigned_role in GLOB.security_positions))
+ . |= player.mind
+
+//////////////////////////
+//Reports player logouts//
+//////////////////////////
+/proc/display_roundstart_logout_report()
+ var/msg = "Roundstart logout report\n\n"
+ for(var/mob/living/L in GLOB.mob_list)
+
+ if(L.ckey)
+ var/found = 0
+ for(var/client/C in GLOB.clients)
+ if(C.ckey == L.ckey)
+ found = 1
+ break
+ if(!found)
+ msg += "[L.name] ([L.ckey]), the [L.job] (Disconnected)\n"
+
+
+ if(L.ckey && L.client)
+ if(L.client.inactivity >= (ROUNDSTART_LOGOUT_REPORT_TIME / 2)) //Connected, but inactive (alt+tabbed or something)
+ msg += "[L.name] ([L.ckey]), the [L.job] (Connected, Inactive)\n"
+ continue //AFK client
+ if(L.stat)
+ if(L.suiciding) //Suicider
+ msg += "[L.name] ([L.ckey]), the [L.job] (Suicide)\n"
+ continue //Disconnected client
+ if(L.stat == UNCONSCIOUS)
+ msg += "[L.name] ([L.ckey]), the [L.job] (Dying)\n"
+ continue //Unconscious
+ if(L.stat == DEAD)
+ msg += "[L.name] ([L.ckey]), the [L.job] (Dead)\n"
+ continue //Dead
+
+ continue //Happy connected client
+ for(var/mob/dead/observer/D in GLOB.mob_list)
+ if(D.mind && D.mind.current == L)
+ if(L.stat == DEAD)
+ if(L.suiciding) //Suicider
+ msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Suicide)\n"
+ continue //Disconnected client
+ else
+ msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Dead)\n"
+ continue //Dead mob, ghost abandoned
+ else
+ if(D.can_reenter_corpse)
+ continue //Adminghost, or cult/wizard ghost
+ else
+ msg += "[L.name] ([ckey(D.mind.key)]), the [L.job] (Ghosted)\n"
+ continue //Ghosted while alive
+
+
+
+ for(var/mob/M in GLOB.mob_list)
+ if(M.client && M.client.holder)
+ to_chat(M, msg)
+
+/datum/game_mode/proc/printplayer(datum/mind/ply, fleecheck)
+ var/text = "
[ply.key] was [ply.name] the [ply.assigned_role] and"
+ if(ply.current)
+ if(ply.current.stat == DEAD)
+ text += " died"
+ else
+ text += " survived"
+ if(fleecheck && ply.current.z > ZLEVEL_STATION)
+ text += " while fleeing the station"
+ if(ply.current.real_name != ply.name)
+ text += " as [ply.current.real_name]"
+ else
+ text += " had their body destroyed"
+ return text
+
+/datum/game_mode/proc/printobjectives(datum/mind/ply)
+ var/text = ""
+ var/count = 1
+ for(var/datum/objective/objective in ply.objectives)
+ if(objective.check_completion())
+ text += "
Objective #[count]: [objective.explanation_text] Success!"
+ else
+ text += "
Objective #[count]: [objective.explanation_text] Fail."
+ count++
+ return text
+
+//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
+/datum/game_mode/proc/age_check(client/C)
+ if(get_remaining_days(C) == 0)
+ return 1 //Available in 0 days = available right now = player is old enough to play.
+ return 0
+
+
+/datum/game_mode/proc/get_remaining_days(client/C)
+ if(!C)
+ return 0
+ if(!config.use_age_restriction_for_jobs)
+ return 0
+ if(!isnum(C.player_age))
+ return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced
+ if(!isnum(enemy_minimum_age))
+ return 0
+
+ return max(0, enemy_minimum_age - C.player_age)
+
+/datum/game_mode/proc/replace_jobbaned_player(mob/living/M, role_type, pref)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [role_type]?", "[role_type]", null, pref, 50, M)
+ var/mob/dead/observer/theghost = null
+ if(candidates.len)
+ theghost = pick(candidates)
+ to_chat(M, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
+ message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(M)]) to replace a jobbaned player.")
+ M.ghostize(0)
+ M.key = theghost.key
+
+/datum/game_mode/proc/remove_antag_for_borging(datum/mind/newborgie)
+ SSticker.mode.remove_cultist(newborgie, 0, 0)
+ SSticker.mode.remove_revolutionary(newborgie, 0)
+ SSticker.mode.remove_gangster(newborgie, 0, remove_bosses=1)
+
+/datum/game_mode/proc/generate_station_goals()
+ var/list/possible = list()
+ for(var/T in subtypesof(/datum/station_goal))
+ var/datum/station_goal/G = T
+ if(config_tag in initial(G.gamemode_blacklist))
+ continue
+ possible += T
+ var/goal_weights = 0
+ while(possible.len && goal_weights < STATION_GOAL_BUDGET)
+ var/datum/station_goal/picked = pick_n_take(possible)
+ goal_weights += initial(picked.weight)
+ station_goals += new picked
+
+
+/datum/game_mode/proc/declare_station_goal_completion()
+ for(var/V in station_goals)
+ var/datum/station_goal/G = V
+ G.print_result()
\ No newline at end of file
diff --git a/code/game/gamemodes/gang/gang.dm b/code/game/gamemodes/gang/gang.dm
index 6606a0d871..5b97280e9a 100644
--- a/code/game/gamemodes/gang/gang.dm
+++ b/code/game/gamemodes/gang/gang.dm
@@ -62,7 +62,7 @@ GLOBAL_LIST_INIT(gang_outfit_pool, list(/obj/item/clothing/suit/jacket/leather,/
for(var/n in 1 to 3)
var/datum/mind/boss = pick(antag_candidates)
antag_candidates -= boss
- G.bosses += boss
+ G.bosses[boss] = GANGSTER_BOSS_STARTING_INFLUENCE
boss.gang_datum = G
var/title
if(n == 1)
@@ -85,6 +85,7 @@ GLOBAL_LIST_INIT(gang_outfit_pool, list(/obj/item/clothing/suit/jacket/leather,/
sleep(rand(10,100))
for(var/datum/gang/G in gangs)
for(var/datum/mind/boss_mind in G.bosses)
+ G.bosses[boss_mind] = GANGSTER_BOSS_STARTING_INFLUENCE //Force influence to be put on it.
G.add_gang_hud(boss_mind)
forge_gang_objectives(boss_mind)
greet_gang(boss_mind)
@@ -170,7 +171,7 @@ GLOBAL_LIST_INIT(gang_outfit_pool, list(/obj/item/clothing/suit/jacket/leather,/
return 0
if(check && gangster_mind.current.isloyal()) //Check to see if the potential gangster is implanted
return 1
- G.gangsters += gangster_mind
+ G.gangsters[gangster_mind] = GANGSTER_SOLDIER_STARTING_INFLUENCE
gangster_mind.gang_datum = G
if(check)
if(iscarbon(gangster_mind.current))
@@ -209,15 +210,24 @@ GLOBAL_LIST_INIT(gang_outfit_pool, list(/obj/item/clothing/suit/jacket/leather,/
if(!G.is_deconvertible && !remove_bosses)
return 0
if(gangster_mind in G.gangsters)
+ G.reclaim_points(G.gangsters[gangster_mind])
G.gangsters -= gangster_mind
removed = 1
if(remove_bosses && (gangster_mind in G.bosses))
+ G.reclaim_points(G.bosses[gangster_mind])
G.bosses -= gangster_mind
removed = 1
+ if(G.tags_by_mind[gangster_mind] && islist(G.tags_by_mind[gangster_mind]))
+ var/list/tags_cache = G.tags_by_mind[gangster_mind]
+ for(var/v in tags_cache)
+ var/obj/effect/decal/cleanable/crayon/gang/c = v
+ c.set_mind_owner(null)
+ G.tags_by_mind -= gangster_mind
if(!removed)
return 0
+
gangster_mind.special_role = null
gangster_mind.gang_datum = null
diff --git a/code/game/gamemodes/gang/gang_datum.dm b/code/game/gamemodes/gang/gang_datum.dm
index d6aa1830f2..a2e7220106 100644
--- a/code/game/gamemodes/gang/gang_datum.dm
+++ b/code/game/gamemodes/gang/gang_datum.dm
@@ -8,6 +8,7 @@
var/list/datum/mind/gangsters = list() //gang B Members
var/list/datum/mind/bosses = list() //gang A Bosses
var/list/obj/item/device/gangtool/gangtools = list()
+ var/list/tags_by_mind = list() //Assoc list in format of tags_by_mind[mind_of_gangster] = list(tag1, tag2, tag3) where tags are the actual object decals.
var/style
var/fighting_style = "normal"
var/list/territory = list()
@@ -202,9 +203,9 @@
return
var/added_names = ""
var/lost_names = ""
-
+
SSticker.mode.shuttle_check() // See if its time to start wrapping things up
-
+
//Re-add territories that were reclaimed, so if they got tagged over, they can still earn income if they tag it back before the next status report
var/list/reclaimed_territories = territory_new & territory_lost
territory |= reclaimed_territories
@@ -245,47 +246,90 @@
set_domination_time(new_time)
message += "[seconds_remaining] seconds remain in hostile takeover.
"
else
- for(var/obj/item/device/gangtool/G in gangtools)
- var/pmessage = message
- var/points_new = 0
- if(istype(G, /obj/item/device/gangtool/soldier))
- points_new = max(0,round(3 - G.points/10)) + (sbonus) + (LAZYLEN(G.tags)/2) // Soldier points
- pmessage += "Your influence has increased by [round(sbonus)] from your gang holding [LAZYLEN(territory)] territories, and a bonus of [round(LAZYLEN(G.tags)/2)] for territories you have personally marked and kept intact.
"
- else
- points_new = max(0,round(5 - G.points/10)) + LAZYLEN(territory) // Boss points, more focused on big picture
- pmessage += "Your influence has increased by [round(points_new)] from your gang holding [territory.len] territories
"
- G.points += points_new
- var/mob/living/carbon/human/ganger = get(G.loc, /mob/living)
- var/points_newer = 0
- var/static/inner = inner_outfit
- var/static/outer = outer_outfit
- if(ishuman(ganger) && ganger.mind in (gangsters|bosses))
- for(var/obj/C in ganger.contents)
- if(C.type == inner_outfit)
- points_newer += 2
- continue
- if(C.type == outer_outfit)
- points_newer += 2
- continue
- switch(C.type)
- if(/obj/item/clothing/neck/necklace/dope)
- points_newer += 2
- if(/obj/item/clothing/head/collectable/petehat/gang)
- points_newer += 4
- if(/obj/item/clothing/shoes/gang)
- points_newer += 6
- if(/obj/item/clothing/mask/gskull)
- points_newer += 5
- if(/obj/item/clothing/gloves/gang)
- points_newer += 3
- if(/obj/item/weapon/storage/belt/military/gang)
- points_newer += 4
- if(points_newer)
- G.points += points_newer
- pmessage += "Your influential choice of clothing has further increased your influence by [points_newer] points.
"
- pmessage += "You now have [G.points] influence.
"
- to_chat(ganger, "\icon[G] [pmessage]")
+ pay_territory_income_to_bosses()
+ pay_territory_income_to_soldiers(sbonus)
+ pay_all_clothing_bonuses()
+ announce_all_influence()
+/datum/gang/proc/pay_all_clothing_bonuses()
+ for(var/datum/mind/mind in gangsters|bosses)
+ pay_clothing_bonus(mind)
+
+/datum/gang/proc/pay_clothing_bonus(var/datum/mind/gangsta)
+ var/mob/living/carbon/human/gangbanger = gangsta.current
+ . = 0
+ if(!istype(gangbanger) || gangbanger.stat == DEAD) //Dead gangsters aren't influential at all!
+ return 0
+ var/static/inner = inner_outfit
+ var/static/outer = outer_outfit
+ for(var/obj/item/C in gangbanger.contents)
+ if(C.type == inner_outfit)
+ . += 2
+ continue
+ else if(C.type == outer_outfit)
+ . += 2
+ continue
+ . += C.gang_contraband_value()
+ adjust_influence(gangsta, .)
+ if(.)
+ announce_to_mind(gangsta, "Your influential choice of clothing has increased your influence by [.] points!")
+ else
+ announce_to_mind(gangsta, "Unfortunately, you have not gained any additional influence from your drab, old, boring clothing. Learn to dress like a gangsta, bro!") //Kek
+
+/datum/gang/proc/pay_soldier_territory_income(datum/mind/soldier, sbonus = 0)
+ . = 0
+ . = max(0,round(3 - gangsters[soldier]/10)) + (sbonus) + (get_soldier_territories(soldier)/2)
+ adjust_influence(soldier, .)
+
+/datum/gang/proc/get_soldier_territories(datum/mind/soldier)
+ if(!islist(tags_by_mind[soldier])) //They have no tagged territories!
+ return 0
+ var/list/tags = tags_by_mind[soldier]
+ return tags.len
+
+/datum/gang/proc/pay_territory_income_to_soldiers(sbonus = 0)
+ for(var/datum/mind/soldier in gangsters)
+ var/returned = pay_soldier_territory_income(soldier)
+ if(!returned)
+ announce_to_mind(soldier, "You have not gained any influence from territories you personally tagged. Get to work, soldier!")
+ else
+ announce_to_mind(soldier, "You have gained [returned] influence from [get_soldier_territories(soldier)] territories you have personally tagged.")
+
+/datum/gang/proc/announce_all_influence()
+ for(var/datum/mind/MG in bosses|gangsters)
+ announce_total_influence(MG)
+
+/datum/gang/proc/pay_territory_income_to_bosses()
+ . = 0
+ for(var/datum/mind/boss_mind in bosses)
+ var/inc = max(0,round(5 - bosses[boss_mind]/10)) + LAZYLEN(territory)
+ . += inc
+ adjust_influence(boss_mind, inc)
+ announce_to_mind(boss_mind, "Your influence has increased by [inc] from your gang holding [LAZYLEN(territory)] territories!")
+
+/datum/gang/proc/get_influence(datum/mind/gangster_mind)
+ if(gangster_mind in gangsters)
+ return gangsters[gangster_mind]
+ if(gangster_mind in bosses)
+ return bosses[gangster_mind]
+
+/datum/gang/proc/adjust_influence(datum/mind/gangster_mind, amount)
+ if(gangster_mind in gangsters)
+ gangsters[gangster_mind] += amount
+ if(gangster_mind in bosses)
+ bosses[gangster_mind] += amount
+
+/datum/gang/proc/announce_to_mind(datum/mind/gangster_mind, message)
+ if(gangster_mind.current && gangster_mind.current.stat != DEAD)
+ to_chat(gangster_mind.current, message)
+
+/datum/gang/proc/announce_total_influence(datum/mind/gangster_mind)
+ announce_to_mind(gangster_mind, "[name] Gang: You now have a total of [get_influence(gangster_mind)] influence!")
+
+/datum/gang/proc/reclaim_points(amount)
+ for(var/datum/mind/bawss in bosses)
+ adjust_influence(bawss, amount/bosses.len)
+ announce_to_mind(bawss, "[name] Gang: [amount/bosses.len] influence given from internal automatic restructuring.")
//Multiverse
diff --git a/code/game/gamemodes/gang/gang_items.dm b/code/game/gamemodes/gang/gang_items.dm
index dae3c85be1..22b3758379 100644
--- a/code/game/gamemodes/gang/gang_items.dm
+++ b/code/game/gamemodes/gang/gang_items.dm
@@ -11,7 +11,7 @@
if(check_canbuy && !can_buy(user, gang, gangtool))
return FALSE
var/real_cost = get_cost(user, gang, gangtool)
- gangtool.points -= real_cost
+ gang.adjust_influence(user.mind, -real_cost)
spawn_item(user, gang, gangtool)
return TRUE
@@ -23,7 +23,7 @@
to_chat(user, spawn_msg)
/datum/gang_item/proc/can_buy(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
- return gang && (gangtool.points >= get_cost(user, gang, gangtool)) && can_see(user, gang, gangtool)
+ return gang && (gang.get_influence(user.mind) >= get_cost(user, gang, gangtool)) && can_see(user, gang, gangtool)
/datum/gang_item/proc/can_see(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
return TRUE
@@ -118,6 +118,9 @@
name = "pimpin' hat"
desc = "The undisputed king of style."
+/obj/item/clothing/head/collectable/petehat/gang/gang_contraband_value()
+ return 4
+
/datum/gang_item/clothing/mask
name = "Golden Death Mask"
id = "mask"
@@ -129,6 +132,8 @@
icon_state = "gskull"
desc = "Strike terror, and envy, into the hearts of your enemies."
+/obj/item/clothing/mask/gskull/gang_contraband_value()
+ return 5
/datum/gang_item/clothing/shoes
name = "Bling Boots"
@@ -141,13 +146,15 @@
desc = "Stand aside peasants."
icon_state = "bling"
+/obj/item/clothing/shoes/gang/gang_contraband_value()
+ return 6
+
/datum/gang_item/clothing/neck
name = "Gold Necklace"
id = "necklace"
cost = 9
item_path = /obj/item/clothing/neck/necklace/dope
-
/datum/gang_item/clothing/hands
name = "Decorative Brass Knuckles"
id = "hand"
@@ -160,6 +167,9 @@
icon_state = "knuckles"
w_class = 3
+/obj/item/clothing/gloves/gang/gang_contraband_value()
+ return 3
+
/datum/gang_item/clothing/belt
name = "Badass Belt"
id = "belt"
@@ -173,7 +183,8 @@
desc = "The belt buckle simply reads 'BAMF'."
storage_slots = 1
-
+/obj/item/weapon/storage/belt/military/gang/gang_contraband_value()
+ return 4
///////////////////
//WEAPONS
@@ -215,6 +226,7 @@
name = "Sawn-Off Improvised Shotgun"
id = "sawn"
cost = 6
+ item_path = /obj/item/weapon/gun/ballistic/revolver/doublebarrel/improvised/sawn
/datum/gang_item/weapon/ammo/improvised_ammo
name = "Box of Buckshot"
diff --git a/code/game/gamemodes/gang/recaller.dm b/code/game/gamemodes/gang/recaller.dm
index 8363261c5d..8533ccf49e 100644
--- a/code/game/gamemodes/gang/recaller.dm
+++ b/code/game/gamemodes/gang/recaller.dm
@@ -15,7 +15,6 @@
var/outfits = 2
var/free_pen = 0
var/promotable = 0
- var/points = 15
var/list/tags = list()
/obj/item/device/gangtool/Initialize() //Initialize supply point income if it hasn't already been started
@@ -50,7 +49,7 @@
var/isboss = (user.mind == gang.bosses[1])
dat += "Registration: [gang.name] Gang [isboss ? "Boss" : "Lieutenant"]
"
dat += "Organization Size: [gang.gangsters.len + gang.bosses.len] | Station Control: [round((gang.territory.len/GLOB.start_state.num_territories)*100, 1)]%
"
- dat += "Your Influence: [points]
"
+ dat += "Your Influence: [gang.get_influence(user.mind)]
"
dat += "Time until Influence grows: [time2text(SSticker.mode.gang_points.next_point_time - world.time, "mm:ss")]
"
dat += "
"
@@ -147,8 +146,9 @@
gang.gangtools += src
icon_state = "gangtool-[gang.color]"
if(!(user.mind in gang.bosses))
+ var/cached_influence = gang.gangsters[user.mind]
SSticker.mode.remove_gangster(user.mind, 0, 2)
- gang.bosses += user.mind
+ gang.bosses[user.mind] = cached_influence
user.mind.gang_datum = gang
user.mind.special_role = "[gang.name] Gang Lieutenant"
gang.add_gang_hud(user.mind)
@@ -246,9 +246,6 @@
///////////// Internal tool used by gang regulars ///////////
-/obj/item/device/gangtool/soldier
- points = 5
-
/obj/item/device/gangtool/soldier/New(mob/user)
. = ..()
gang = user.mind.gang_datum
@@ -264,7 +261,7 @@
dat += "Takeover In Progress:
[gang.domination_time_remaining()] seconds remain"
dat += "Registration: [gang.name] - Foot Soldier
"
dat += "Organization Size: [gang.gangsters.len + gang.bosses.len] | Station Control: [round((gang.territory.len/GLOB.start_state.num_territories)*100, 1)]%
"
- dat += "Your Influence: [points]
"
+ dat += "Your Influence: [gang.get_influence(user.mind)]
"
if(LAZYLEN(tags))
dat += "Your tags generate bonus influence for you.
You have tagged the following territories:"
for(var/obj/effect/decal/cleanable/crayon/gang/T in tags)
diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm
index 5dfb0b5515..29b75d75d1 100644
--- a/code/game/gamemodes/objective_items.dm
+++ b/code/game/gamemodes/objective_items.dm
@@ -43,7 +43,7 @@
/datum/objective_item/steal/capmedal
name = "the medal of captaincy"
- targetitem = /obj/item/clothing/tie/medal/gold/captain
+ targetitem = /obj/item/clothing/accessory/medal/gold/captain
difficulty = 5
excludefromjob = list("Captain")
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index f89833d315..9a21400653 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -243,7 +243,7 @@
if(!is_gangster(user))
var/datum/gang/multiverse/G = new(src, "[user.real_name]")
SSticker.mode.gangs += G
- G.bosses += user.mind
+ G.bosses[user.mind] = 0
G.add_gang_hud(user.mind)
user.mind.gang_datum = G
to_chat(user, "With your new found power you could easily conquer the station!")
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
old mode 100644
new mode 100755
index 605cd60ce6..8bfbbd1348
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -1,7 +1,7 @@
// The communications computer
/obj/machinery/computer/communications
name = "communications console"
- desc = "This can be used for various important functions. Still under developement."
+ desc = "A console used for high-priority announcements and emergencies."
icon_screen = "comm"
icon_keyboard = "tech_key"
req_access = list(GLOB.access_heads)
diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm
index 5baa169e99..b0970edbad 100644
--- a/code/game/machinery/computer/security.dm
+++ b/code/game/machinery/computer/security.dm
@@ -620,7 +620,7 @@ What a mess.*/
if("mi_crim_add")
if(istype(active1, /datum/data/record))
var/t1 = stripped_input(usr, "Please input minor crime names:", "Secure. records", "", null)
- var/t2 = stripped_multiline_input(usr, "Please input minor crime details:", "Secure. records", "", null)
+ var/t2 = stripped_input(usr, "Please input minor crime details:", "Secure. records", "", null)
if(!canUseSecurityRecordsConsole(usr, t1, null, a2))
return
var/crime = GLOB.data_core.createCrimeEntry(t1, t2, authenticated, worldtime2text())
@@ -634,7 +634,7 @@ What a mess.*/
if("ma_crim_add")
if(istype(active1, /datum/data/record))
var/t1 = stripped_input(usr, "Please input major crime names:", "Secure. records", "", null)
- var/t2 = stripped_multiline_input(usr, "Please input major crime details:", "Secure. records", "", null)
+ var/t2 = stripped_input(usr, "Please input major crime details:", "Secure. records", "", null)
if(!canUseSecurityRecordsConsole(usr, t1, null, a2))
return
var/crime = GLOB.data_core.createCrimeEntry(t1, t2, authenticated, worldtime2text())
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 6c86899cf0..ba1717485e 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -995,7 +995,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
/obj/item/clothing/head/helmet/gladiator = 1,/obj/item/clothing/under/gimmick/rank/captain/suit = 1,/obj/item/clothing/head/flatcap = 1,
/obj/item/clothing/suit/toggle/labcoat/mad = 1,/obj/item/clothing/shoes/jackboots = 1,
/obj/item/clothing/under/schoolgirl = 1,/obj/item/clothing/under/schoolgirl/red = 1,/obj/item/clothing/under/schoolgirl/green = 1,/obj/item/clothing/under/schoolgirl/orange = 1,/obj/item/clothing/head/kitty = 1,/obj/item/clothing/under/skirt/black = 1,/obj/item/clothing/head/beret = 1,
- /obj/item/clothing/tie/waistcoat = 1,/obj/item/clothing/under/suit_jacket = 1,/obj/item/clothing/head/that =1,/obj/item/clothing/under/kilt = 1,/obj/item/clothing/head/beret = 1,/obj/item/clothing/tie/waistcoat = 1,
+ /obj/item/clothing/accessory/waistcoat = 1,/obj/item/clothing/under/suit_jacket = 1,/obj/item/clothing/head/that =1,/obj/item/clothing/under/kilt = 1,/obj/item/clothing/head/beret = 1,/obj/item/clothing/accessory/waistcoat = 1,
/obj/item/clothing/glasses/monocle =1,/obj/item/clothing/head/bowler = 1,/obj/item/weapon/cane = 1,/obj/item/clothing/under/sl_suit = 1,
/obj/item/clothing/mask/fakemoustache = 1,/obj/item/clothing/suit/bio_suit/plaguedoctorsuit = 1,/obj/item/clothing/head/plaguedoctorhat = 1,/obj/item/clothing/mask/gas/plaguedoctor = 1,
/obj/item/clothing/suit/toggle/owlwings = 1, /obj/item/clothing/under/owl = 1,/obj/item/clothing/mask/gas/owl_mask = 1,
@@ -1136,7 +1136,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
/obj/item/clothing/neck/scarf/purple=1,/obj/item/clothing/neck/scarf/yellow=1,/obj/item/clothing/neck/scarf/orange=1,
/obj/item/clothing/neck/scarf/cyan=1,/obj/item/clothing/neck/scarf=1,/obj/item/clothing/neck/scarf/black=1,
/obj/item/clothing/neck/scarf/zebra=1,/obj/item/clothing/neck/scarf/christmas=1,/obj/item/clothing/neck/stripedredscarf=1,
- /obj/item/clothing/neck/stripedbluescarf=1,/obj/item/clothing/neck/stripedgreenscarf=1,/obj/item/clothing/tie/waistcoat=1,
+ /obj/item/clothing/neck/stripedbluescarf=1,/obj/item/clothing/neck/stripedgreenscarf=1,/obj/item/clothing/accessory/waistcoat=1,
/obj/item/clothing/under/skirt/black=1,/obj/item/clothing/under/skirt/blue=1,/obj/item/clothing/under/skirt/red=1,/obj/item/clothing/under/skirt/purple=1,
/obj/item/clothing/under/sundress=2,/obj/item/clothing/under/stripeddress=1, /obj/item/clothing/under/sailordress=1, /obj/item/clothing/under/redeveninggown=1, /obj/item/clothing/under/blacktango=1,
/obj/item/clothing/under/plaid_skirt=1,/obj/item/clothing/under/plaid_skirt/blue=1,/obj/item/clothing/under/plaid_skirt/purple=1,/obj/item/clothing/under/plaid_skirt/green=1,
diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm
index 53ecfc8d62..2361510e46 100644
--- a/code/game/objects/effects/decals/crayon.dm
+++ b/code/game/objects/effects/decals/crayon.dm
@@ -30,27 +30,35 @@
layer = HIGH_OBJ_LAYER //Harder to hide
do_icon_rotate = FALSE //These are designed to always face south, so no rotation please.
var/datum/gang/gang
- var/obj/item/device/gangtool/linked_tool
+ var/datum/mind/user_mind
var/area/territory
/obj/effect/decal/cleanable/crayon/gang/Initialize(mapload, var/datum/gang/G, var/e_name = "gang tag", var/rotation = 0, var/mob/user)
if(!type || !G)
qdel(src)
+ user_mind = user.mind
territory = get_area(src)
gang = G
var/newcolor = G.color_hex
icon_state = G.name
G.territory_new |= list(territory.type = territory.name)
- linked_tool = locate(/obj/item/device/gangtool) in user.contents
- if(linked_tool)
- linked_tool.tags += src
+ //If this isn't tagged by a specific gangster there's no bonus income.
+ set_mind_owner(user_mind)
..(mapload, newcolor, icon_state, e_name, rotation)
+/obj/effect/decal/cleanable/crayon/gang/proc/set_mind_owner(datum/mind/mind)
+ if(istype(user_mind) && istype(gang) && islist(gang.tags_by_mind[user_mind])) //Clear us out of old ownership
+ gang.tags_by_mind[user_mind] -= src
+ if(istype(mind))
+ if(!islist(gang.tags_by_mind[mind]))
+ gang.tags_by_mind[mind] = list()
+ gang.tags_by_mind[mind] += src
+ user_mind = mind
+
/obj/effect/decal/cleanable/crayon/gang/Destroy()
- if(linked_tool)
- linked_tool.tags -= src
if(gang)
gang.territory -= territory.type
+ set_mind_owner(null)
gang.territory_new -= territory.type
gang.territory_lost |= list(territory.type = territory.name)
return ..()
diff --git a/code/game/objects/effects/spawners/bundle.dm b/code/game/objects/effects/spawners/bundle.dm
index c272c383e9..c316b7e209 100644
--- a/code/game/objects/effects/spawners/bundle.dm
+++ b/code/game/objects/effects/spawners/bundle.dm
@@ -60,7 +60,7 @@
/obj/effect/spawner/bundle/costume/butler
name = "butler costume spawner"
items = list(
- /obj/item/clothing/tie/waistcoat,
+ /obj/item/clothing/accessory/waistcoat,
/obj/item/clothing/under/suit_jacket,
/obj/item/clothing/head/that)
@@ -73,7 +73,7 @@
/obj/effect/spawner/bundle/costume/prig
name = "prig costume spawner"
items = list(
- /obj/item/clothing/tie/waistcoat,
+ /obj/item/clothing/accessory/waistcoat,
/obj/item/clothing/glasses/monocle,
/obj/effect/spawner/lootdrop/minor/bowler_or_that,
/obj/item/clothing/shoes/sneakers/black,
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index de0cdaf494..01a0940e53 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -112,6 +112,9 @@
icon_state = "tile-carpet-black"
turf_type = /turf/open/floor/carpet/black
+/obj/item/stack/tile/carpet/black/fifty
+ amount = 50
+
/obj/item/stack/tile/fakespace
name = "astral carpet"
diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm
index 4bdf6ddf3c..886d875edc 100644
--- a/code/game/objects/items/weapons/defib.dm
+++ b/code/game/objects/items/weapons/defib.dm
@@ -273,7 +273,6 @@
force = 0
throwforce = 6
w_class = WEIGHT_CLASS_BULKY
- flags = NODROP
var/revivecost = 1000
var/cooldown = 0
diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm
index 646768cea8..f35cff56a9 100644
--- a/code/game/objects/items/weapons/storage/boxes.dm
+++ b/code/game/objects/items/weapons/storage/boxes.dm
@@ -568,7 +568,7 @@
/obj/item/weapon/storage/box/deputy/PopulateContents()
for(var/i in 1 to 7)
- new /obj/item/clothing/tie/armband/deputy(src)
+ new /obj/item/clothing/accessory/armband/deputy(src)
/obj/item/weapon/storage/box/metalfoam
name = "box of metal foam grenades"
diff --git a/code/game/objects/items/weapons/storage/lockbox.dm b/code/game/objects/items/weapons/storage/lockbox.dm
index 2a026a8f9e..94f34e0e3b 100644
--- a/code/game/objects/items/weapons/storage/lockbox.dm
+++ b/code/game/objects/items/weapons/storage/lockbox.dm
@@ -1,116 +1,157 @@
-/obj/item/weapon/storage/lockbox
- name = "lockbox"
- desc = "A locked box."
- icon_state = "lockbox+l"
- item_state = "syringe_kit"
- w_class = WEIGHT_CLASS_BULKY
- max_w_class = WEIGHT_CLASS_NORMAL
- max_combined_w_class = 14 //The sum of the w_classes of all the items in this storage item.
- storage_slots = 4
- req_access = list(GLOB.access_armory)
- var/locked = 1
- var/broken = 0
- var/icon_locked = "lockbox+l"
- var/icon_closed = "lockbox"
- var/icon_broken = "lockbox+b"
-
-
-/obj/item/weapon/storage/lockbox/attackby(obj/item/weapon/W, mob/user, params)
- if(W.GetID())
- if(broken)
- to_chat(user, "It appears to be broken.")
- return
- if(allowed(user))
- locked = !locked
- if(locked)
- icon_state = icon_locked
- to_chat(user, "You lock the [src.name]!")
- close_all()
- return
- else
- icon_state = icon_closed
- to_chat(user, "You unlock the [src.name]!")
- return
- else
- to_chat(user, "Access Denied.")
- return
- if(!locked)
- return ..()
- else
- to_chat(user, "It's locked!")
-
-/obj/item/weapon/storage/lockbox/MouseDrop(over_object, src_location, over_location)
- if (locked)
- src.add_fingerprint(usr)
- to_chat(usr, "It's locked!")
- return 0
- ..()
-
-/obj/item/weapon/storage/lockbox/emag_act(mob/user)
- if(!broken)
- broken = 1
- locked = 0
- desc += "It appears to be broken."
- icon_state = src.icon_broken
- if(user)
- visible_message("\The [src] has been broken by [user] with an electromagnetic card!")
- return
-/obj/item/weapon/storage/lockbox/show_to(mob/user)
- if(locked)
- to_chat(user, "It's locked!")
- else
- ..()
- return
-
-//Check the destination item type for contentto.
-/obj/item/weapon/storage/lockbox/storage_contents_dump_act(obj/item/weapon/storage/src_object, mob/user)
- if(locked)
- to_chat(user, "It's locked!")
- return 0
- return ..()
-
-/obj/item/weapon/storage/lockbox/can_be_inserted(obj/item/W, stop_messages = 0)
- if(locked)
- return 0
- return ..()
-
-/obj/item/weapon/storage/lockbox/loyalty
- name = "lockbox of mindshield implants"
- req_access = list(GLOB.access_security)
-
-/obj/item/weapon/storage/lockbox/loyalty/PopulateContents()
- for(var/i in 1 to 3)
- new /obj/item/weapon/implantcase/mindshield(src)
- new /obj/item/weapon/implanter/mindshield(src)
-
-
-/obj/item/weapon/storage/lockbox/clusterbang
- name = "lockbox of clusterbangs"
- desc = "You have a bad feeling about opening this."
- req_access = list(GLOB.access_security)
-
-/obj/item/weapon/storage/lockbox/clusterbang/PopulateContents()
- new /obj/item/weapon/grenade/clusterbuster(src)
-
-/obj/item/weapon/storage/lockbox/medal
- name = "medal box"
- desc = "A locked box used to store medals of honor."
- icon_state = "medalbox+l"
- item_state = "syringe_kit"
- w_class = WEIGHT_CLASS_NORMAL
- max_w_class = WEIGHT_CLASS_SMALL
- storage_slots = 10
- req_access = list(GLOB.access_captain)
- icon_locked = "medalbox+l"
- icon_closed = "medalbox"
- icon_broken = "medalbox+b"
-
-/obj/item/weapon/storage/lockbox/medal/PopulateContents()
- new /obj/item/clothing/tie/medal/silver/valor(src)
- new /obj/item/clothing/tie/medal/bronze_heart(src)
- for(var/i in 1 to 3)
- new /obj/item/clothing/tie/medal/conduct(src)
- new /obj/item/clothing/tie/medal/gold/captain(src)
- new /obj/item/clothing/tie/medal/silver/security(src)
- new /obj/item/clothing/tie/medal/nobel_science(src)
- new /obj/item/clothing/tie/medal/gold/heroism(src)
+/obj/item/weapon/storage/lockbox
+ name = "lockbox"
+ desc = "A locked box."
+ icon_state = "lockbox+l"
+ item_state = "syringe_kit"
+ w_class = WEIGHT_CLASS_BULKY
+ max_w_class = WEIGHT_CLASS_NORMAL
+ max_combined_w_class = 14 //The sum of the w_classes of all the items in this storage item.
+ storage_slots = 4
+ req_access = list(GLOB.access_armory)
+ var/locked = 1
+ var/broken = 0
+ var/icon_locked = "lockbox+l"
+ var/icon_closed = "lockbox"
+ var/icon_broken = "lockbox+b"
+
+
+/obj/item/weapon/storage/lockbox/attackby(obj/item/weapon/W, mob/user, params)
+ if(W.GetID())
+ if(broken)
+ to_chat(user, "It appears to be broken.")
+ return
+ if(allowed(user))
+ locked = !locked
+ if(locked)
+ icon_state = icon_locked
+ to_chat(user, "You lock the [src.name]!")
+ close_all()
+ return
+ else
+ icon_state = icon_closed
+ to_chat(user, "You unlock the [src.name]!")
+ return
+ else
+ to_chat(user, "Access Denied.")
+ return
+ if(!locked)
+ return ..()
+ else
+ to_chat(user, "It's locked!")
+
+/obj/item/weapon/storage/lockbox/MouseDrop(over_object, src_location, over_location)
+ if (locked)
+ src.add_fingerprint(usr)
+ to_chat(usr, "It's locked!")
+ return 0
+ ..()
+
+/obj/item/weapon/storage/lockbox/emag_act(mob/user)
+ if(!broken)
+ broken = 1
+ locked = 0
+ desc += "It appears to be broken."
+ icon_state = src.icon_broken
+ if(user)
+ visible_message("\The [src] has been broken by [user] with an electromagnetic card!")
+ return
+/obj/item/weapon/storage/lockbox/show_to(mob/user)
+ if(locked)
+ to_chat(user, "It's locked!")
+ else
+ ..()
+ return
+
+//Check the destination item type for contentto.
+/obj/item/weapon/storage/lockbox/storage_contents_dump_act(obj/item/weapon/storage/src_object, mob/user)
+ if(locked)
+ to_chat(user, "It's locked!")
+ return 0
+ return ..()
+
+/obj/item/weapon/storage/lockbox/can_be_inserted(obj/item/W, stop_messages = 0)
+ if(locked)
+ return 0
+ return ..()
+
+/obj/item/weapon/storage/lockbox/loyalty
+ name = "lockbox of mindshield implants"
+ req_access = list(GLOB.access_security)
+
+/obj/item/weapon/storage/lockbox/loyalty/PopulateContents()
+ for(var/i in 1 to 3)
+ new /obj/item/weapon/implantcase/mindshield(src)
+ new /obj/item/weapon/implanter/mindshield(src)
+
+
+/obj/item/weapon/storage/lockbox/clusterbang
+ name = "lockbox of clusterbangs"
+ desc = "You have a bad feeling about opening this."
+ req_access = list(GLOB.access_security)
+
+/obj/item/weapon/storage/lockbox/clusterbang/PopulateContents()
+ new /obj/item/weapon/grenade/clusterbuster(src)
+
+/obj/item/weapon/storage/lockbox/medal
+ name = "medal box"
+ desc = "A locked box used to store medals of honor."
+ icon_state = "medalbox+l"
+ item_state = "syringe_kit"
+ w_class = WEIGHT_CLASS_NORMAL
+ max_w_class = WEIGHT_CLASS_SMALL
+ storage_slots = 10
+ max_combined_w_class = 20
+ req_access = list(GLOB.access_captain)
+ icon_locked = "medalbox+l"
+ icon_closed = "medalbox"
+ icon_broken = "medalbox+b"
+ can_hold = list(/obj/item/clothing/accessory/medal)
+
+/obj/item/weapon/storage/lockbox/medal/PopulateContents()
+ new /obj/item/clothing/accessory/medal/silver/valor(src)
+ new /obj/item/clothing/accessory/medal/bronze_heart(src)
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/accessory/medal/conduct(src)
+ new /obj/item/clothing/accessory/medal/gold/captain(src)
+ new /obj/item/clothing/accessory/medal/silver/security(src)
+ new /obj/item/clothing/accessory/medal/plasma(src)
+ new /obj/item/clothing/accessory/medal/plasma/nobel_science(src)
+ new /obj/item/clothing/accessory/medal/gold/heroism(src)
+
+/obj/item/weapon/storage/lockbox/secmedal
+ name = "security medal box"
+ desc = "A locked box used to store medals to be given to members of the security department."
+ icon_state = "medalbox+l"
+ item_state = "syringe_kit"
+ w_class = WEIGHT_CLASS_NORMAL
+ max_w_class = WEIGHT_CLASS_SMALL
+ storage_slots = 10
+ max_combined_w_class = 20
+ req_access = list(GLOB.access_hos)
+ icon_locked = "medalbox+l"
+ icon_closed = "medalbox"
+ icon_broken = "medalbox+b"
+ can_hold = list(/obj/item/clothing/accessory/medal)
+
+/obj/item/weapon/storage/lockbox/secmedal/PopulateContents()
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/accessory/medal/silver/security(src)
+
+/obj/item/weapon/storage/lockbox/scimedal
+ name = "science medal box"
+ desc = "A locked box used to store medals to be given to members of the science department."
+ icon_state = "medalbox+l"
+ item_state = "syringe_kit"
+ w_class = WEIGHT_CLASS_NORMAL
+ max_w_class = WEIGHT_CLASS_SMALL
+ storage_slots = 10
+ max_combined_w_class = 20
+ req_access = list(GLOB.access_rd)
+ icon_locked = "medalbox+l"
+ icon_closed = "medalbox"
+ icon_broken = "medalbox+b"
+ can_hold = list(/obj/item/clothing/accessory/medal)
+
+/obj/item/weapon/storage/lockbox/scimedal/PopulateContents()
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/accessory/medal/plasma/nobel_science(src)
diff --git a/code/game/objects/items/weapons/storage/toolbox.dm b/code/game/objects/items/weapons/storage/toolbox.dm
index d73a7ab058..d90c42fe4a 100644
--- a/code/game/objects/items/weapons/storage/toolbox.dm
+++ b/code/game/objects/items/weapons/storage/toolbox.dm
@@ -151,7 +151,7 @@
new /obj/item/weapon/weldingtool/experimental/brass(src)
/obj/item/weapon/storage/toolbox/brass/prefilled/ratvar
- var/slab_type = /obj/item/clockwork/slab/scarab
+ var/slab_type = /obj/item/clockwork/slab
/obj/item/weapon/storage/toolbox/brass/prefilled/ratvar/PopulateContents()
..()
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 9766dbc26d..7482b4ca14 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -193,3 +193,6 @@
..()
if(unique_rename)
to_chat(user, "Use a pen on it to rename it or change its description.")
+
+/obj/proc/gang_contraband_value()
+ return 0
diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm
index de8d807f93..ca304dc62f 100644
--- a/code/game/objects/structures/crates_lockers/closets/job_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm
@@ -15,8 +15,8 @@
new /obj/item/clothing/under/sl_suit(src)
new /obj/item/clothing/under/rank/bartender(src)
new /obj/item/clothing/under/rank/bartender(src)
- new /obj/item/clothing/tie/waistcoat(src)
- new /obj/item/clothing/tie/waistcoat(src)
+ new /obj/item/clothing/accessory/waistcoat(src)
+ new /obj/item/clothing/accessory/waistcoat(src)
new /obj/item/clothing/head/soft/black(src)
new /obj/item/clothing/head/soft/black(src)
new /obj/item/clothing/shoes/sneakers/black(src)
@@ -39,8 +39,8 @@
new /obj/item/clothing/under/waiter(src)
new /obj/item/device/radio/headset/headset_srv(src)
new /obj/item/device/radio/headset/headset_srv(src)
- new /obj/item/clothing/tie/waistcoat(src)
- new /obj/item/clothing/tie/waistcoat(src)
+ new /obj/item/clothing/accessory/waistcoat(src)
+ new /obj/item/clothing/accessory/waistcoat(src)
for(var/i in 1 to 3)
new /obj/item/clothing/suit/apron/chef(src)
new /obj/item/clothing/head/soft/mime(src)
@@ -95,8 +95,8 @@
new /obj/item/clothing/suit/toggle/lawyer/black(src)
new /obj/item/clothing/shoes/laceup(src)
new /obj/item/clothing/shoes/laceup(src)
- new /obj/item/clothing/tie/lawyers_badge(src)
- new /obj/item/clothing/tie/lawyers_badge(src)
+ new /obj/item/clothing/accessory/lawyers_badge(src)
+ new /obj/item/clothing/accessory/lawyers_badge(src)
/obj/structure/closet/wardrobe/chaplain_black
name = "chapel wardrobe"
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
index 684ba9af55..feee04d56e 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
@@ -24,3 +24,4 @@
new /obj/item/device/laser_pointer(src)
new /obj/item/weapon/door_remote/research_director(src)
new /obj/item/weapon/storage/box/firingpins(src)
+ new /obj/item/weapon/storage/lockbox/scimedal(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index 9d24b44f33..4934636948 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -11,7 +11,7 @@
else
new /obj/item/weapon/storage/backpack/satchel/cap(src)
new /obj/item/clothing/neck/cloak/cap(src)
- new /obj/item/weapon/storage/daki(src)
+ new /obj/item/weapon/storage/daki(src)
new /obj/item/weapon/storage/backpack/dufflebag/captain(src)
new /obj/item/clothing/head/crown/fancy(src)
new /obj/item/clothing/suit/captunic(src)
@@ -83,6 +83,8 @@
new /obj/item/weapon/gun/energy/e_gun/hos(src)
new /obj/item/device/flashlight/seclite(src)
new /obj/item/weapon/pinpointer(src)
+ new /obj/item/clothing/under/rank/head_of_security/grey(src)
+ new /obj/item/weapon/storage/lockbox/secmedal(src)
/obj/structure/closet/secure_closet/warden
name = "\proper warden's locker"
@@ -106,7 +108,7 @@
new /obj/item/device/flashlight/seclite(src)
new /obj/item/clothing/gloves/krav_maga/sec(src)
new /obj/item/weapon/door_remote/head_of_security(src)
- new /obj/item/weapon/gun/ballistic/shotgun/automatic/combat/compact(src)
+ new /obj/item/weapon/gun/ballistic/shotgun/automatic/combat/compact(src)
/obj/structure/closet/secure_closet/security
name = "security officer's locker"
@@ -132,28 +134,28 @@
/obj/structure/closet/secure_closet/security/cargo/PopulateContents()
..()
- new /obj/item/clothing/tie/armband/cargo(src)
+ new /obj/item/clothing/accessory/armband/cargo(src)
new /obj/item/device/encryptionkey/headset_cargo(src)
/obj/structure/closet/secure_closet/security/engine
/obj/structure/closet/secure_closet/security/engine/PopulateContents()
..()
- new /obj/item/clothing/tie/armband/engine(src)
+ new /obj/item/clothing/accessory/armband/engine(src)
new /obj/item/device/encryptionkey/headset_eng(src)
/obj/structure/closet/secure_closet/security/science
/obj/structure/closet/secure_closet/security/science/PopulateContents()
..()
- new /obj/item/clothing/tie/armband/science(src)
+ new /obj/item/clothing/accessory/armband/science(src)
new /obj/item/device/encryptionkey/headset_sci(src)
/obj/structure/closet/secure_closet/security/med
/obj/structure/closet/secure_closet/security/med/PopulateContents()
..()
- new /obj/item/clothing/tie/armband/medblue(src)
+ new /obj/item/clothing/accessory/armband/medblue(src)
new /obj/item/device/encryptionkey/headset_med(src)
/obj/structure/closet/secure_closet/detective
@@ -171,7 +173,7 @@
new /obj/item/clothing/head/det_hat(src)
new /obj/item/clothing/gloves/color/black(src)
new /obj/item/clothing/under/rank/det/grey(src)
- new /obj/item/clothing/tie/waistcoat(src)
+ new /obj/item/clothing/accessory/waistcoat(src)
new /obj/item/clothing/suit/det_suit/grey(src)
new /obj/item/clothing/head/fedora(src)
new /obj/item/clothing/shoes/laceup(src)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index a1f98cb89f..d31a9a7edf 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -38,7 +38,7 @@
if(M.client)
body += "
\[First Seen: [M.client.player_join_date]\]\[Byond account registered on: [M.client.account_join_date]\]"
- body += "
Show related accounts by: "
+ body += "
Show related accounts by: "
body += "\[ CID | "
body += "IP \]"
diff --git a/code/modules/admin/adminmenu.dm b/code/modules/admin/adminmenu.dm
index fc7a57e212..8954244da4 100644
--- a/code/modules/admin/adminmenu.dm
+++ b/code/modules/admin/adminmenu.dm
@@ -6,6 +6,6 @@
set name = "Player Panel"
set desc = "Player Panel"
set category = "Admin"
- usr.client.holder.player_panel_new()
- SSblackbox.add_details("admin_verb","Player Panel New") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- return
\ No newline at end of file
+ if(usr.client.holder)
+ usr.client.holder.player_panel_new()
+ SSblackbox.add_details("admin_verb","Player Panel New") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 4756318ee7..21e3961c64 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -2239,7 +2239,7 @@
error_viewer.show_to(owner, null, href_list["viewruntime_linear"])
else if(href_list["showrelatedacc"])
var/client/C = locate(href_list["client"]) in GLOB.clients
- var/list/thing_to_check
+ var/thing_to_check
if(href_list["showrelatedacc"] == "cid")
thing_to_check = C.related_accounts_cid
else
@@ -2247,9 +2247,8 @@
thing_to_check = splittext(thing_to_check, ", ")
- var/dat = "Related accounts by [uppertext(href_list["showrelatedacc"])]:
"
- for(var/thing in thing_to_check)
- dat += "[thing]
"
+ var/list/dat = list("Related accounts by [uppertext(href_list["showrelatedacc"])]:")
+ dat += thing_to_check
- usr << browse(dat, "size=420x300")
+ usr << browse(dat.Join("
"), "window=related_[C];size=420x300")
diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm
index 37dab65b0c..299853ae53 100644
--- a/code/modules/admin/verbs/onlyone.dm
+++ b/code/modules/admin/verbs/onlyone.dm
@@ -99,7 +99,7 @@ GLOBAL_VAR_INIT(highlander, FALSE)
var/datum/gang/multiverse/G = new(src, "[H.real_name]")
SSticker.mode.gangs += G
- G.bosses += H.mind
+ G.bosses[H.mind] = 0 //No they don't use influence but this prevents runtimes.
G.add_gang_hud(H.mind)
H.mind.gang_datum = G
diff --git a/code/modules/admin/whitelist.dm b/code/modules/admin/whitelist.dm
index d6e8fc908f..974a753027 100644
--- a/code/modules/admin/whitelist.dm
+++ b/code/modules/admin/whitelist.dm
@@ -10,7 +10,7 @@ GLOBAL_PROTECT(whitelist)
continue
if(findtextEx(line,"#",1,2))
continue
- GLOB.whitelist += line
+ GLOB.whitelist += ckey(line)
if(!GLOB.whitelist.len)
GLOB.whitelist = null
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index 421b8a057e..efda086af5 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -1630,7 +1630,7 @@
/obj/item/clothing/suit/toggle/lawyer/purple,
/obj/item/clothing/under/lawyer/blacksuit,
/obj/item/clothing/suit/toggle/lawyer/black,
- /obj/item/clothing/tie/waistcoat,
+ /obj/item/clothing/accessory/waistcoat,
/obj/item/clothing/neck/tie/blue,
/obj/item/clothing/neck/tie/red,
/obj/item/clothing/neck/tie/black,
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 8a943b4c26..fcbaace6fb 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -529,7 +529,7 @@ BLIND // can't see anything
var/can_adjust = 1
var/adjusted = NORMAL_STYLE
var/alt_covers_chest = 0 // for adjusted/rolled-down jumpsuits, 0 = exposes chest and arms, 1 = exposes arms only
- var/obj/item/clothing/tie/hastie = null
+ var/obj/item/clothing/accessory/attached_accessory
var/mutantrace_variation = NO_MUTANTRACE_VARIATION //Are there special sprites for specific situations? Don't use this unless you need to.
/obj/item/clothing/under/worn_overlays(isinhands = FALSE)
@@ -541,14 +541,14 @@ BLIND // can't see anything
. += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform")
if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "uniformblood")
- if(hastie)
- var/tie_color = hastie.item_color
- if(!tie_color)
- tie_color = hastie.icon_state
- var/mutable_appearance/tie = mutable_appearance('icons/mob/ties.dmi', "[tie_color]")
- tie.alpha = hastie.alpha
- tie.color = hastie.color
- . += tie
+ if(attached_accessory)
+ var/accessory_color = attached_accessory.item_color
+ if(!accessory_color)
+ accessory_color = attached_accessory.icon_state
+ var/mutable_appearance/accessory = mutable_appearance('icons/mob/accessories.dmi', "[accessory_color]")
+ accessory.alpha = attached_accessory.alpha
+ accessory.color = attached_accessory.color
+ . += accessory
/obj/item/clothing/under/attackby(obj/item/W, mob/user, params)
if((has_sensor == BROKEN_SENSORS) && istype(W, /obj/item/stack/cable_coil))
@@ -587,29 +587,30 @@ BLIND // can't see anything
adjusted = DIGITIGRADE_STYLE
H.update_inv_w_uniform()
- if(hastie && slot != slot_hands)
- hastie.on_uniform_equip(src, user)
+ if(attached_accessory && slot != slot_hands)
+ attached_accessory.on_uniform_equip(src, user)
/obj/item/clothing/under/dropped(mob/user)
- if(hastie)
- hastie.on_uniform_dropped(src, user)
+ if(attached_accessory)
+ attached_accessory.on_uniform_dropped(src, user)
..()
/obj/item/clothing/under/attackby(obj/item/I, mob/user, params)
- if(!attachTie(I, user))
+ if(!attach_accessory(I, user))
..()
-/obj/item/clothing/under/proc/attachTie(obj/item/I, mob/user, notifyAttach = 1)
- if(istype(I, /obj/item/clothing/tie))
- var/obj/item/clothing/tie/T = I
- if(hastie)
+/obj/item/clothing/under/proc/attach_accessory(obj/item/I, mob/user, notifyAttach = 1)
+ . = FALSE
+ if(istype(I, /obj/item/clothing/accessory))
+ var/obj/item/clothing/accessory/A = I
+ if(attached_accessory)
if(user)
to_chat(user, "[src] already has an accessory.")
- return 0
+ return
else
if(user && !user.drop_item())
return
- if(!T.attach(src, user))
+ if(!A.attach(src, user))
return
if(user && notifyAttach)
@@ -619,21 +620,21 @@ BLIND // can't see anything
var/mob/living/carbon/human/H = loc
H.update_inv_w_uniform()
- return 1
+ return TRUE
-/obj/item/clothing/under/proc/removetie(mob/user)
+/obj/item/clothing/under/proc/remove_accessory(mob/user)
if(!isliving(user))
return
if(!can_use(user))
return
- if(hastie)
- var/obj/item/clothing/tie/T = hastie
- hastie.detach(src, user)
- if(user.put_in_hands(T))
- to_chat(user, "You detach [T] from [src].")
+ if(attached_accessory)
+ var/obj/item/clothing/accessory/A = attached_accessory
+ attached_accessory.detach(src, user)
+ if(user.put_in_hands(A))
+ to_chat(user, "You detach [A] from [src].")
else
- to_chat(user, "You detach [T] from [src] and it falls on the floor.")
+ to_chat(user, "You detach [A] from [src] and it falls on the floor.")
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
@@ -659,8 +660,8 @@ BLIND // can't see anything
to_chat(user, "Its vital tracker appears to be enabled.")
if(SENSOR_COORDS)
to_chat(user, "Its vital tracker and tracking beacon appear to be enabled.")
- if(hastie)
- to_chat(user, "\A [hastie] is attached to it.")
+ if(attached_accessory)
+ to_chat(user, "\A [attached_accessory] is attached to it.")
/proc/generate_female_clothing(index,t_color,icon,type)
var/icon/female_clothing_icon = icon("icon"=icon, "icon_state"=t_color)
@@ -721,8 +722,8 @@ BLIND // can't see anything
to_chat(user, "You can't do that right now!")
return
else
- if(hastie)
- removetie(user)
+ if(attached_accessory)
+ remove_accessory(user)
else
rolldown()
diff --git a/code/modules/clothing/neck/ties.dm b/code/modules/clothing/neck/neck.dm
similarity index 92%
rename from code/modules/clothing/neck/ties.dm
rename to code/modules/clothing/neck/neck.dm
index 59dc504098..de4858e23e 100644
--- a/code/modules/clothing/neck/ties.dm
+++ b/code/modules/clothing/neck/neck.dm
@@ -160,17 +160,6 @@
/obj/item/clothing/neck/necklace/dope
name = "gold necklace"
desc = "Damn, it feels good to be a gangster."
- icon = 'icons/obj/clothing/ties.dmi'
+ icon = 'icons/obj/clothing/neck.dmi'
icon_state = "bling"
- item_color = "bling"
-
-////////////////
-//OONGA BOONGA//
-////////////////
-
-/obj/item/clothing/neck/talisman
- name = "bone talisman"
- desc = "A hunter's talisman, some say the old gods smile on those who wear it."
- icon_state = "talisman"
- item_color = "talisman"
- armor = list(melee = 5, bullet = 5, laser = 5, energy = 5, bomb = 20, bio = 20, rad = 5, fire = 0, acid = 25)
\ No newline at end of file
+ item_color = "bling"
\ No newline at end of file
diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm
index 6344ef22d7..ff60b5366e 100644
--- a/code/modules/clothing/outfits/standard.dm
+++ b/code/modules/clothing/outfits/standard.dm
@@ -154,7 +154,7 @@
/datum/outfit/assassin/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
var/obj/item/clothing/under/U = H.w_uniform
- U.attachTie(new /obj/item/clothing/tie/waistcoat(H))
+ U.attach_accessory(new /obj/item/clothing/accessory/waistcoat(H))
if(visualsOnly)
return
diff --git a/code/modules/clothing/under/ties.dm b/code/modules/clothing/under/accessories.dm
similarity index 63%
rename from code/modules/clothing/under/ties.dm
rename to code/modules/clothing/under/accessories.dm
index 9db9941f8c..3653d7a395 100644
--- a/code/modules/clothing/under/ties.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -1,23 +1,23 @@
-/obj/item/clothing/tie //Ties moved to neck slot items, but as there are still things like medals and armbands, this accessory system is being kept as-is
- name = "tie"
- desc = "A neosilk clip-on tie."
- icon = 'icons/obj/clothing/ties.dmi'
- icon_state = "bluetie"
+/obj/item/clothing/accessory //Ties moved to neck slot items, but as there are still things like medals and armbands, this accessory system is being kept as-is
+ name = "Accessory"
+ desc = "Something has gone wrong!"
+ icon = 'icons/obj/clothing/accessories.dmi'
+ icon_state = "plasma"
item_state = "" //no inhands
- item_color = "bluetie"
+ item_color = "plasma" //On accessories, this controls the worn sprite. That's a bit weird.
slot_flags = 0
w_class = WEIGHT_CLASS_SMALL
var/minimize_when_attached = TRUE // TRUE if shown as a small icon in corner, FALSE if overlayed
-/obj/item/clothing/tie/proc/attach(obj/item/clothing/under/U, user)
+/obj/item/clothing/accessory/proc/attach(obj/item/clothing/under/U, user)
if(pockets) // Attach storage to jumpsuit
if(U.pockets) // storage items conflict
- return 0
+ return FALSE
pockets.loc = U
U.pockets = pockets
- U.hastie = src
+ U.attached_accessory = src
loc = U
layer = FLOAT_LAYER
plane = FLOAT_PLANE
@@ -30,10 +30,13 @@
for(var/armor_type in armor)
U.armor[armor_type] += armor[armor_type]
- return 1
+ if(isliving(user))
+ on_uniform_equip(U, user)
+
+ return TRUE
-/obj/item/clothing/tie/proc/detach(obj/item/clothing/under/U, user)
+/obj/item/clothing/accessory/proc/detach(obj/item/clothing/under/U, user)
if(pockets && pockets == U.pockets)
pockets.loc = src
U.pockets = null
@@ -41,6 +44,9 @@
for(var/armor_type in armor)
U.armor[armor_type] -= armor[armor_type]
+ if(isliving(user))
+ on_uniform_dropped(U, user)
+
if(minimize_when_attached)
transform *= 2
pixel_x -= 8
@@ -48,27 +54,31 @@
layer = initial(layer)
plane = initial(plane)
U.cut_overlays()
- U.hastie = null
+ U.attached_accessory = null
-/obj/item/clothing/tie/proc/on_uniform_equip(obj/item/clothing/under/U, user)
+/obj/item/clothing/accessory/proc/on_uniform_equip(obj/item/clothing/under/U, user)
return
-/obj/item/clothing/tie/proc/on_uniform_dropped(obj/item/clothing/under/U, user)
+/obj/item/clothing/accessory/proc/on_uniform_dropped(obj/item/clothing/under/U, user)
return
-/obj/item/clothing/tie/waistcoat
+/obj/item/clothing/accessory/examine(mob/user)
+ ..()
+ to_chat(user, "\The [src] can be attached to a uniform. Alt-click to remove it once attached.")
+
+/obj/item/clothing/accessory/waistcoat
name = "waistcoat"
desc = "For some classy, murderous fun."
icon_state = "waistcoat"
item_state = "waistcoat"
item_color = "waistcoat"
minimize_when_attached = FALSE
-
+
//////////
//Medals//
//////////
-/obj/item/clothing/tie/medal
+/obj/item/clothing/accessory/medal
name = "bronze medal"
desc = "A bronze medal."
icon_state = "bronze"
@@ -77,7 +87,7 @@
resistance_flags = FIRE_PROOF
//Pinning medals on people
-/obj/item/clothing/tie/medal/attack(mob/living/carbon/human/M, mob/living/user)
+/obj/item/clothing/accessory/medal/attack(mob/living/carbon/human/M, mob/living/user)
if(ishuman(M) && (user.a_intent == INTENT_HELP))
if(M.wear_suit)
@@ -94,7 +104,7 @@
user.visible_message("[user] is trying to pin [src] on [M]'s chest.", \
"You try to pin [src] on [M]'s chest.")
if(do_after(user, delay, target = M))
- if(U.attachTie(src, user, 0)) //Attach it, do not notify the user of the attachment
+ if(U.attach_accessory(src, user, 0)) //Attach it, do not notify the user of the attachment
if(user == M)
to_chat(user, "You attach [src] to [U].")
else
@@ -104,95 +114,111 @@
else to_chat(user, "Medals can only be pinned on jumpsuits!")
else ..()
-/obj/item/clothing/tie/medal/conduct
+/obj/item/clothing/accessory/medal/conduct
name = "distinguished conduct medal"
desc = "A bronze medal awarded for distinguished conduct. Whilst a great honor, this is the most basic award given by Nanotrasen. It is often awarded by a captain to a member of his crew."
-/obj/item/clothing/tie/medal/bronze_heart
+/obj/item/clothing/accessory/medal/bronze_heart
name = "bronze heart medal"
desc = "A bronze heart-shaped medal awarded for sacrifice. It is often awarded posthumously or for severe injury in the line of duty."
icon_state = "bronze_heart"
-/obj/item/clothing/tie/medal/nobel_science
- name = "nobel sciences award"
- desc = "A bronze medal which represents significant contributions to the field of science or engineering."
-
-/obj/item/clothing/tie/medal/silver
+/obj/item/clothing/accessory/medal/silver
name = "silver medal"
desc = "A silver medal."
icon_state = "silver"
item_color = "silver"
materials = list(MAT_SILVER=1000)
-/obj/item/clothing/tie/medal/silver/valor
+/obj/item/clothing/accessory/medal/silver/valor
name = "medal of valor"
desc = "A silver medal awarded for acts of exceptional valor."
-/obj/item/clothing/tie/medal/silver/security
+/obj/item/clothing/accessory/medal/silver/security
name = "robust security award"
desc = "An award for distinguished combat and sacrifice in defence of Nanotrasen's commercial interests. Often awarded to security staff."
-/obj/item/clothing/tie/medal/gold
+/obj/item/clothing/accessory/medal/gold
name = "gold medal"
desc = "A prestigious golden medal."
icon_state = "gold"
item_color = "gold"
materials = list(MAT_GOLD=1000)
-/obj/item/clothing/tie/medal/gold/captain
+/obj/item/clothing/accessory/medal/gold/captain
name = "medal of captaincy"
desc = "A golden medal awarded exclusively to those promoted to the rank of captain. It signifies the codified responsibilities of a captain to Nanotrasen, and their undisputable authority over their crew."
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
-/obj/item/clothing/tie/medal/gold/heroism
+/obj/item/clothing/accessory/medal/gold/heroism
name = "medal of exceptional heroism"
desc = "An extremely rare golden medal awarded only by Centcom. To receive such a medal is the highest honor and as such, very few exist. This medal is almost never awarded to anybody but commanders."
+/obj/item/clothing/accessory/medal/plasma
+ name = "plasma medal"
+ desc = "An eccentric medal made of plasma."
+ icon_state = "plasma"
+ item_color = "plasma"
+ armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = -10, acid = 0) //It's made of plasma. Of course it's flammable.
+ materials = list(MAT_PLASMA=1000)
+
+/obj/item/clothing/accessory/medal/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ if(exposed_temperature > 300)
+ atmos_spawn_air("plasma=20;TEMP=[exposed_temperature]")
+ visible_message(" \The [src] bursts into flame!","Your [src] bursts into flame!")
+ qdel(src)
+
+/obj/item/clothing/accessory/medal/plasma/nobel_science
+ name = "nobel sciences award"
+ desc = "A plasma medal which represents significant contributions to the field of science or engineering."
+
+
+
////////////
//Armbands//
////////////
-/obj/item/clothing/tie/armband
+/obj/item/clothing/accessory/armband
name = "red armband"
desc = "An fancy red armband!"
icon_state = "redband"
item_color = "redband"
-/obj/item/clothing/tie/armband/deputy
+/obj/item/clothing/accessory/armband/deputy
name = "security deputy armband"
desc = "An armband, worn by personnel authorized to act as a deputy of station security."
-/obj/item/clothing/tie/armband/cargo
+/obj/item/clothing/accessory/armband/cargo
name = "cargo bay guard armband"
desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is brown."
icon_state = "cargoband"
item_color = "cargoband"
-/obj/item/clothing/tie/armband/engine
+/obj/item/clothing/accessory/armband/engine
name = "engineering guard armband"
desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is orange with a reflective strip!"
icon_state = "engieband"
item_color = "engieband"
-/obj/item/clothing/tie/armband/science
+/obj/item/clothing/accessory/armband/science
name = "science guard armband"
desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is purple."
icon_state = "rndband"
item_color = "rndband"
-/obj/item/clothing/tie/armband/hydro
+/obj/item/clothing/accessory/armband/hydro
name = "hydroponics guard armband"
desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is green and blue."
icon_state = "hydroband"
item_color = "hydroband"
-/obj/item/clothing/tie/armband/med
+/obj/item/clothing/accessory/armband/med
name = "medical guard armband"
desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is white."
icon_state = "medband"
item_color = "medband"
-/obj/item/clothing/tie/armband/medblue
+/obj/item/clothing/accessory/armband/medblue
name = "medical guard armband"
desc = "An armband, worn by the station's security forces to display which department they're assigned to. This one is white and blue."
icon_state = "medblueband"
@@ -202,29 +228,29 @@
//OBJECTION!//
//////////////
-/obj/item/clothing/tie/lawyers_badge
+/obj/item/clothing/accessory/lawyers_badge
name = "attorney's badge"
desc = "Fills you with the conviction of JUSTICE. Lawyers tend to want to show it to everyone they meet."
icon_state = "lawyerbadge"
item_color = "lawyerbadge"
-/obj/item/clothing/tie/lawyers_badge/attach(obj/item/clothing/under/U, user)
- if(!..())
- return 0
- if(isliving(U.loc))
- on_uniform_equip(U, user)
-
-/obj/item/clothing/tie/lawyers_badge/detach(obj/item/clothing/under/U, user)
- ..()
- if(isliving(U.loc))
- on_uniform_dropped(U, user)
-
-/obj/item/clothing/tie/lawyers_badge/on_uniform_equip(obj/item/clothing/under/U, user)
+/obj/item/clothing/accessory/lawyers_badge/on_uniform_equip(obj/item/clothing/under/U, user)
var/mob/living/L = user
if(L)
L.bubble_icon = "lawyer"
-/obj/item/clothing/tie/lawyers_badge/on_uniform_dropped(obj/item/clothing/under/U, user)
+/obj/item/clothing/accessory/lawyers_badge/on_uniform_dropped(obj/item/clothing/under/U, user)
var/mob/living/L = user
if(L)
L.bubble_icon = initial(L.bubble_icon)
+
+////////////////
+//OONGA BOONGA//
+////////////////
+
+/obj/item/clothing/accessory/talisman
+ name = "bone talisman"
+ desc = "A hunter's talisman, some say the old gods smile on those who wear it."
+ icon_state = "talisman"
+ item_color = "talisman"
+ armor = list(melee = 5, bullet = 5, laser = 5, energy = 5, bomb = 20, bio = 20, rad = 5, fire = 0, acid = 25)
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index 67464adc12..b8fc651a55 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -382,7 +382,7 @@
/datum/crafting_recipe/blackcarpet
name = "Black Carpet"
reqs = list(/obj/item/stack/tile/carpet = 50, /obj/item/toy/crayon/black = 1)
- result = /obj/item/stack/tile/carpet/black
+ result = /obj/item/stack/tile/carpet/black/fifty
category = CAT_MISC
/datum/crafting_recipe/showercurtain
@@ -427,7 +427,7 @@
/datum/crafting_recipe/bonetalisman
name = "Bone Talisman"
- result = /obj/item/clothing/neck/talisman
+ result = /obj/item/clothing/accessory/talisman
time = 20
reqs = list(/obj/item/stack/sheet/bone = 2,
/obj/item/stack/sheet/sinew = 1)
diff --git a/code/modules/jobs/job_types/civilian.dm b/code/modules/jobs/job_types/civilian.dm
index fd01846467..704496ad67 100644
--- a/code/modules/jobs/job_types/civilian.dm
+++ b/code/modules/jobs/job_types/civilian.dm
@@ -186,7 +186,7 @@ Lawyer
shoes = /obj/item/clothing/shoes/laceup
l_hand = /obj/item/weapon/storage/briefcase/lawyer
l_pocket = /obj/item/device/laser_pointer
- r_pocket = /obj/item/clothing/tie/lawyers_badge
+ r_pocket = /obj/item/clothing/accessory/lawyers_badge
/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
diff --git a/code/modules/jobs/job_types/security.dm b/code/modules/jobs/job_types/security.dm
index d3ae011f60..3756d1e3e7 100644
--- a/code/modules/jobs/job_types/security.dm
+++ b/code/modules/jobs/job_types/security.dm
@@ -195,7 +195,7 @@ GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, S
else
department = pick_n_take(GLOB.available_depts)
var/ears = null
- var/tie = null
+ var/accessory = null
var/list/dep_access = null
var/destination = null
var/spawn_point = null
@@ -205,29 +205,29 @@ GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, S
dep_access = list(GLOB.access_mailsorting, GLOB.access_mining, GLOB.access_mining_station)
destination = /area/security/checkpoint/supply
spawn_point = locate(/obj/effect/landmark/start/depsec/supply) in GLOB.department_security_spawns
- tie = /obj/item/clothing/tie/armband/cargo
+ accessory = /obj/item/clothing/accessory/armband/cargo
if(SEC_DEPT_ENGINEERING)
ears = /obj/item/device/radio/headset/headset_sec/alt/department/engi
dep_access = list(GLOB.access_construction, GLOB.access_engine)
destination = /area/security/checkpoint/engineering
spawn_point = locate(/obj/effect/landmark/start/depsec/engineering) in GLOB.department_security_spawns
- tie = /obj/item/clothing/tie/armband/engine
+ accessory = /obj/item/clothing/accessory/armband/engine
if(SEC_DEPT_MEDICAL)
ears = /obj/item/device/radio/headset/headset_sec/alt/department/med
dep_access = list(GLOB.access_medical)
destination = /area/security/checkpoint/medical
spawn_point = locate(/obj/effect/landmark/start/depsec/medical) in GLOB.department_security_spawns
- tie = /obj/item/clothing/tie/armband/medblue
+ accessory = /obj/item/clothing/accessory/armband/medblue
if(SEC_DEPT_SCIENCE)
ears = /obj/item/device/radio/headset/headset_sec/alt/department/sci
dep_access = list(GLOB.access_research)
destination = /area/security/checkpoint/science
spawn_point = locate(/obj/effect/landmark/start/depsec/science) in GLOB.department_security_spawns
- tie = /obj/item/clothing/tie/armband/science
+ accessory = /obj/item/clothing/accessory/armband/science
- if(tie)
+ if(accessory)
var/obj/item/clothing/under/U = H.w_uniform
- U.attachTie(new tie)
+ U.attach_accessory(new accessory)
if(ears)
if(H.ears)
qdel(H.ears)
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index aa9e133165..2ee3007bb1 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -72,6 +72,8 @@
if(!brainmob.stored_dna)
brainmob.stored_dna = new /datum/dna/stored(brainmob)
C.dna.copy_dna(brainmob.stored_dna)
+ if(L.disabilities & NOCLONE)
+ brainmob.disabilities |= NOCLONE //This is so you can't just decapitate a husked guy and clone them without needing to get a new body
var/obj/item/organ/zombie_infection/ZI = L.getorganslot("zombie_infection")
if(ZI)
brainmob.set_species(ZI.old_species) //For if the brain is cloned
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index a3bb2fefde..42765011d1 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -14,17 +14,17 @@
//uniform
if(w_uniform && !(slot_w_uniform in obscured))
- //Ties
- var/tie_msg
+ //accessory
+ var/accessory_msg
if(istype(w_uniform,/obj/item/clothing/under))
var/obj/item/clothing/under/U = w_uniform
- if(U.hastie)
- tie_msg += " with \icon[U.hastie] \a [U.hastie]"
+ if(U.attached_accessory)
+ accessory_msg += " with \icon[U.attached_accessory] \a [U.attached_accessory]"
if(w_uniform.blood_DNA)
- msg += "[t_He] [t_is] wearing \icon[w_uniform] [w_uniform.gender==PLURAL?"some":"a"] blood-stained [w_uniform.name][tie_msg]!\n"
+ msg += "[t_He] [t_is] wearing \icon[w_uniform] [w_uniform.gender==PLURAL?"some":"a"] blood-stained [w_uniform.name][accessory_msg]!\n"
else
- msg += "[t_He] [t_is] wearing \icon[w_uniform] \a [w_uniform][tie_msg].\n"
+ msg += "[t_He] [t_is] wearing \icon[w_uniform] \a [w_uniform][accessory_msg].\n"
//head
if(head)
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index a0aa88779b..42051e8a78 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -95,6 +95,7 @@
message_simple = S.deathmessage
. = ..()
message_simple = initial(message_simple)
+ playsound(user.loc, 'sound/voice/oof.ogg', 80, 1, 1)//Defenitley not copypasta
if(. && isalienadult(user))
playsound(user.loc, 'sound/voice/hiss6.ogg', 80, 1, 1)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 9574533884..27cf0c3a82 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -1140,7 +1140,7 @@
return
if(incapacitated())
return
- if(M.restrained())
+ if(M.incapacitated())
return
if(module)
if(!module.allow_riding)
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index cedec9941b..11db7e8d68 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -613,9 +613,8 @@
/datum/reagent/toxin/amanitin/on_mob_delete(mob/living/M)
var/toxdamage = current_cycle*3*REM
+ M.log_message("has taken [toxdamage] toxin damage from amanitin toxin", INDIVIDUAL_ATTACK_LOG)
M.adjustToxLoss(toxdamage)
- if(M)
- add_logs(M, get_turf(M), "has taken [toxdamage] toxin damage from amanitin toxin")
..()
/datum/reagent/toxin/lipolicide
diff --git a/code/modules/spells/spell_types/devil_boons.dm b/code/modules/spells/spell_types/devil_boons.dm
index e8fcc73010..75b6597f07 100644
--- a/code/modules/spells/spell_types/devil_boons.dm
+++ b/code/modules/spells/spell_types/devil_boons.dm
@@ -18,7 +18,7 @@
new /obj/item/weapon/coin/gold(user.loc),
new /obj/item/weapon/coin/diamond(user.loc),
new /obj/item/weapon/coin/silver(user.loc),
- new /obj/item/clothing/tie/medal/gold(user.loc),
+ new /obj/item/clothing/accessory/medal/gold(user.loc),
new /obj/item/stack/sheet/mineral/gold(user.loc),
new /obj/item/stack/sheet/mineral/silver(user.loc),
new /obj/item/stack/sheet/mineral/diamond(user.loc),
diff --git a/html/changelogs/AutoChangeLog-pr-1327.yml b/html/changelogs/AutoChangeLog-pr-1327.yml
new file mode 100644
index 0000000000..85eddc62fc
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-1327.yml
@@ -0,0 +1,5 @@
+author: "Goodstuff"
+delete-after: True
+changes:
+ - bugfix: "Fixes the crafting recipe for black carpet"
+ - bugfix: "Removed a random white dot on the black carpet sprite"
diff --git a/html/changelogs/AutoChangeLog-pr-1445.yml b/html/changelogs/AutoChangeLog-pr-1445.yml
new file mode 100644
index 0000000000..960d3366f3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-1445.yml
@@ -0,0 +1,11 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - rscadd: "New plasma medals have been added to the Captain's medal box. Don't get them too warm."
+ - imageadd: "New sprites for plasma medals."
+ - imageadd: "Icon and worn sprites for all medals and the lawyer's badge have been improved. Worn medals more closely match their icons."
+ - tweak: "The bone talisman is an accessory again, so it's not useless."
+ - imageadd: "It also has a new worn sprite, based on an arm band."
+ - imagedel: "Ties have been removed from accessories.dmi and vice versa. Same for
+the explorer's webbing sprites that were in there. ties.dmi is now neck.dmi, and has sprites for scarves, ties, sthetoscopes, etc."
+ - tweak: "Examining an accessory now tells you how to use it."
diff --git a/html/changelogs/AutoChangeLog-pr-1487.yml b/html/changelogs/AutoChangeLog-pr-1487.yml
new file mode 100644
index 0000000000..eeed3b359b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-1487.yml
@@ -0,0 +1,4 @@
+author: "Xhuis"
+delete-after: True
+changes:
+ - tweak: "Defibrillator paddles will no longer stick to your hands, and will snap back onto the unit if you drop them somehow."
diff --git a/html/changelogs/AutoChangeLog-pr-1498.yml b/html/changelogs/AutoChangeLog-pr-1498.yml
new file mode 100644
index 0000000000..08f8aaf02b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-1498.yml
@@ -0,0 +1,4 @@
+author: "oranges"
+delete-after: True
+changes:
+ - tweak: "Security minor and major crime descriptors are now a single line input, making it easier to add them"
diff --git a/html/changelogs/AutoChangeLog-pr-1513.yml b/html/changelogs/AutoChangeLog-pr-1513.yml
new file mode 100644
index 0000000000..3066b9af93
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-1513.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - bugfix: "Cloning dismembered heads and brains now respects husking and other clone preventing disabilities."
diff --git a/html/changelogs/AutoChangeLog-pr-1516.yml b/html/changelogs/AutoChangeLog-pr-1516.yml
new file mode 100644
index 0000000000..6bc4bf5372
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-1516.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - imageadd: "Glass tables are shinier"
diff --git a/icons/mob/accessories.dmi b/icons/mob/accessories.dmi
new file mode 100644
index 0000000000..22c42e1eae
Binary files /dev/null and b/icons/mob/accessories.dmi differ
diff --git a/icons/mob/ties.dmi b/icons/mob/ties.dmi
deleted file mode 100644
index 19b36bfc94..0000000000
Binary files a/icons/mob/ties.dmi and /dev/null differ
diff --git a/icons/obj/clothing/accessories.dmi b/icons/obj/clothing/accessories.dmi
new file mode 100644
index 0000000000..99c203cc16
Binary files /dev/null and b/icons/obj/clothing/accessories.dmi differ
diff --git a/icons/obj/clothing/neck.dmi b/icons/obj/clothing/neck.dmi
index 9606e11d63..0f3668ce10 100644
Binary files a/icons/obj/clothing/neck.dmi and b/icons/obj/clothing/neck.dmi differ
diff --git a/icons/obj/clothing/ties.dmi b/icons/obj/clothing/ties.dmi
deleted file mode 100644
index 83c1ffedf2..0000000000
Binary files a/icons/obj/clothing/ties.dmi and /dev/null differ
diff --git a/icons/obj/smooth_structures/glass_table.dmi b/icons/obj/smooth_structures/glass_table.dmi
index 3fa90ea064..112499f380 100644
Binary files a/icons/obj/smooth_structures/glass_table.dmi and b/icons/obj/smooth_structures/glass_table.dmi differ
diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi
index 5372e24c05..1c0ac03abe 100644
Binary files a/icons/obj/tiles.dmi and b/icons/obj/tiles.dmi differ
diff --git a/sound/voice/oof.ogg b/sound/voice/oof.ogg
new file mode 100644
index 0000000000..8d686c0c69
Binary files /dev/null and b/sound/voice/oof.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index f8aa3db8de..c1bbac4d4a 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1210,7 +1210,7 @@
#include "code\modules\clothing\masks\hailer.dm"
#include "code\modules\clothing\masks\miscellaneous.dm"
#include "code\modules\clothing\masks\vg_masks.dm"
-#include "code\modules\clothing\neck\ties.dm"
+#include "code\modules\clothing\neck\neck.dm"
#include "code\modules\clothing\outfits\ert.dm"
#include "code\modules\clothing\outfits\standard.dm"
#include "code\modules\clothing\shoes\bananashoes.dm"
@@ -1235,12 +1235,12 @@
#include "code\modules\clothing\suits\utility.dm"
#include "code\modules\clothing\suits\vg_suits.dm"
#include "code\modules\clothing\suits\wiz_robe.dm"
+#include "code\modules\clothing\under\accessories.dm"
#include "code\modules\clothing\under\color.dm"
#include "code\modules\clothing\under\miscellaneous.dm"
#include "code\modules\clothing\under\pants.dm"
#include "code\modules\clothing\under\shorts.dm"
#include "code\modules\clothing\under\syndicate.dm"
-#include "code\modules\clothing\under\ties.dm"
#include "code\modules\clothing\under\trek.dm"
#include "code\modules\clothing\under\vg_under.dm"
#include "code\modules\clothing\under\jobs\civilian.dm"
@@ -1495,8 +1495,8 @@
#include "code\modules\mining\equipment\lazarus_injector.dm"
#include "code\modules\mining\equipment\marker_beacons.dm"
#include "code\modules\mining\equipment\mineral_scanner.dm"
-#include "code\modules\mining\equipment\regenerative_core.dm"
#include "code\modules\mining\equipment\mining_tools.dm"
+#include "code\modules\mining\equipment\regenerative_core.dm"
#include "code\modules\mining\equipment\resonator.dm"
#include "code\modules\mining\equipment\survival_pod.dm"
#include "code\modules\mining\equipment\vendor_items.dm"
diff --git a/tgstation.dme.rej b/tgstation.dme.rej
new file mode 100644
index 0000000000..64015ccf29
--- /dev/null
+++ b/tgstation.dme.rej
@@ -0,0 +1,10 @@
+diff a/tgstation.dme b/tgstation.dme (rejected hunks)
+@@ -1169,7 +1169,7 @@
+ #include "code\modules\clothing\masks\gasmask.dm"
+ #include "code\modules\clothing\masks\hailer.dm"
+ #include "code\modules\clothing\masks\miscellaneous.dm"
+-#include "code\modules\clothing\neck\ties.dm"
++#include "code\modules\clothing\neck\neck.dm"
+ #include "code\modules\clothing\outfits\ert.dm"
+ #include "code\modules\clothing\outfits\standard.dm"
+ #include "code\modules\clothing\shoes\bananashoes.dm"