diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql
index 91bc36feb3..c4f46b5084 100644
--- a/SQL/tgstation_schema.sql
+++ b/SQL/tgstation_schema.sql
@@ -349,21 +349,3 @@ CREATE TABLE `messages` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Mentor stufs
---
-
-DROP TABLE IF EXISTS `mentor`;
-CREATE TABLE `mentor` (
- `ckey` text NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-
-DROP TABLE IF EXISTS `mentor_memo`;
-CREATE TABLE `mentor_memo` (
- `ckey` varchar(32) NOT NULL,
- `memotext` text NOT NULL,
- `timestamp` datetime NOT NULL,
- `last_editor` varchar(32) DEFAULT NULL,
- `edits` text,
- PRIMARY KEY (`ckey`)
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 940412d12f..c23d3e5ac7 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -20993,6 +20993,7 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 5
},
+/obj/structure/chair/stool,
/turf/open/floor/plasteel/redyellow,
/area/crew_quarters/bar/atrium)
"aMI" = (
@@ -24027,6 +24028,7 @@
/area/crew_quarters/bar/atrium)
"aRI" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/structure/chair/stool,
/turf/open/floor/plasteel/redyellow,
/area/crew_quarters/bar/atrium)
"aRJ" = (
@@ -78208,7 +78210,7 @@
/turf/closed/wall,
/area/maintenance/electrical)
"cHL" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/visible{
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
tag = "icon-manifold (NORTH)";
icon_state = "manifold";
dir = 1
@@ -107878,15 +107880,6 @@
pixel_y = 3
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
-/obj/machinery/doorButtons/access_button{
- dir = 1;
- idDoor = "virology_airlock_exterior";
- idSelf = "virology_airlock_control";
- name = "Virology Access Button";
- pixel_x = 0;
- pixel_y = -24;
- req_access_txt = "39"
- },
/turf/open/floor/plasteel/whitegreen/corner{
dir = 8
},
@@ -108190,6 +108183,15 @@
name = "Virology Exterior Airlock";
req_access_txt = "39"
},
+/obj/machinery/doorButtons/access_button{
+ dir = 1;
+ idDoor = "virology_airlock_exterior";
+ idSelf = "virology_airlock_control";
+ name = "Virology Access Button";
+ pixel_x = -24;
+ pixel_y = -2;
+ req_access_txt = "39"
+ },
/turf/open/floor/plasteel{
tag = "icon-plasteel_warn_side (EAST)"
},
@@ -108660,6 +108662,12 @@
/turf/open/floor/plating,
/area/medical/virology)
"dKi" = (
+/obj/item/weapon/twohanded/required/kirbyplants{
+ icon_state = "plant-21";
+ layer = 4.1;
+ pixel_x = -3;
+ pixel_y = 3
+ },
/turf/open/floor/plasteel/whitegreen/corner{
dir = 1
},
@@ -109068,6 +109076,14 @@
name = "Virology Interior Airlock";
req_access_txt = "39"
},
+/obj/machinery/doorButtons/access_button{
+ idDoor = "virology_airlock_interior";
+ idSelf = "virology_airlock_control";
+ name = "Virology Access Button";
+ pixel_x = 0;
+ pixel_y = 22;
+ req_access_txt = "39"
+ },
/turf/open/floor/plasteel,
/area/medical/virology)
"dKZ" = (
@@ -118113,8 +118129,8 @@
},
/area/crew_quarters/electronic_marketing_den)
"ecc" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
-/turf/closed/wall,
+/obj/structure/closet/wardrobe/grey,
+/turf/open/floor/plasteel/neutral,
/area/crew_quarters/electronic_marketing_den)
"ecd" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
@@ -118148,23 +118164,29 @@
/turf/open/floor/plasteel,
/area/hydroponics/Abandoned_Garden)
"ech" = (
-/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/components/unary/vent_scrubber{
- dir = 4;
- on = 1;
- scrub_Toxins = 0
+/obj/machinery/button/door{
+ id = "Dorm2";
+ name = "Dormitory Door Lock";
+ normaldoorcontrol = 1;
+ pixel_x = -26;
+ pixel_y = 7;
+ req_access_txt = "0";
+ specialfunctions = 4
},
-/turf/open/floor/plasteel/hydrofloor,
-/area/hydroponics/Abandoned_Garden)
+/turf/open/floor/wood,
+/area/crew_quarters/sleep)
"eci" = (
-/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
- tag = "icon-manifold (EAST)";
- icon_state = "manifold";
- dir = 4
+/obj/machinery/button/door{
+ id = "Dorm4";
+ name = "Dormitory Door Lock";
+ normaldoorcontrol = 1;
+ pixel_x = -26;
+ pixel_y = 7;
+ req_access_txt = "0";
+ specialfunctions = 4
},
-/turf/open/floor/plasteel/hydrofloor,
-/area/hydroponics/Abandoned_Garden)
+/turf/open/floor/wood,
+/area/crew_quarters/sleep)
"ecj" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plasteel/hydrofloor,
@@ -118500,102 +118522,51 @@
/obj/machinery/deepfryer,
/turf/open/floor/plasteel/red,
/area/crew_quarters/kitchen)
-"ecc" = (
-/obj/structure/closet/wardrobe/green,
-/turf/open/floor/plasteel/neutral/side,
-/area/shuttle/arrival)
-"ecd" = (
-/obj/machinery/doorButtons/access_button{
+"edc" = (
+/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/turf/closed/wall,
+/area/crew_quarters/electronic_marketing_den)
+"edd" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/components/unary/vent_scrubber{
dir = 4;
- idDoor = "virology_airlock_interior";
- idSelf = "virology_airlock_control";
- name = "Virology Access Button";
- pixel_x = -10;
- pixel_y = 0;
- req_access_txt = "39"
+ on = 1;
+ scrub_Toxins = 0
},
-/turf/closed/wall/r_wall,
-/area/medical/virology)
-"ece" = (
-/obj/structure/cable/white{
- d2 = 2;
- icon_state = "0-2";
- tag = "icon-0-2"
- },
-/turf/closed/wall/r_wall,
-/area/medical/virology)
-"ecf" = (
-/obj/structure/cable/white{
- tag = "icon-4-8";
- icon_state = "4-8"
- },
-/obj/structure/cable/white{
- tag = "icon-2-4";
- icon_state = "2-4"
- },
-/obj/structure/cable/white{
- tag = "icon-1-4";
- icon_state = "1-4"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 2
+/turf/open/floor/plasteel/hydrofloor,
+/area/hydroponics/Abandoned_Garden)
+"ede" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ tag = "icon-manifold (EAST)";
+ icon_state = "manifold";
+ dir = 4
},
+/turf/open/floor/plasteel/hydrofloor,
+/area/hydroponics/Abandoned_Garden)
+"edf" = (
+/obj/structure/table/wood,
+/obj/item/clothing/head/hardhat/cakehat,
+/turf/open/floor/plasteel/redyellow,
+/area/crew_quarters/bar/atrium)
+"edg" = (
/obj/machinery/doorButtons/airlock_controller{
idExterior = "virology_airlock_exterior";
idInterior = "virology_airlock_interior";
idSelf = "virology_airlock_control";
name = "Virology Access Console";
- pixel_x = 0;
- pixel_y = 22;
+ pixel_x = -10;
+ pixel_y = 24;
req_access_txt = "39"
},
+/obj/structure/cable/white{
+ tag = "icon-4-8";
+ icon_state = "4-8"
+ },
/turf/open/floor/plasteel{
tag = "icon-plasteel_warn_side (WEST)"
},
/area/medical/virology)
-"ecg" = (
-/obj/structure/cable/white,
-/turf/closed/wall/r_wall,
-/area/medical/virology)
-"ech" = (
-/obj/machinery/button/door{
- id = "Dorm2";
- name = "Dormitory Door Lock";
- normaldoorcontrol = 1;
- pixel_x = -26;
- pixel_y = 7;
- req_access_txt = "0";
- specialfunctions = 4
- },
-/turf/open/floor/wood,
-/area/crew_quarters/sleep)
-"eci" = (
-/obj/machinery/button/door{
- id = "Dorm4";
- name = "Dormitory Door Lock";
- normaldoorcontrol = 1;
- pixel_x = -26;
- pixel_y = 7;
- req_access_txt = "0";
- specialfunctions = 4
- },
-/turf/open/floor/wood,
-/area/crew_quarters/sleep)
-"ecj" = (
-/obj/item/weapon/reagent_containers/food/condiment/saltshaker{
- pixel_x = -8;
- pixel_y = 5
- },
-/obj/item/weapon/reagent_containers/food/condiment/peppermill{
- pixel_x = -8
- },
-/obj/structure/table/wood,
-/obj/item/clothing/head/hardhat/cakehat{
- pixel_x = 4;
- pixel_y = 3
- },
-/turf/open/floor/plasteel/redyellow,
-/area/crew_quarters/bar/atrium)
(1,1,1) = {"
aaa
@@ -149776,7 +149747,7 @@ aic
awb
awX
ayh
-ech
+edd
azo
azo
aCw
@@ -150024,7 +149995,7 @@ alb
amb
anl
aoj
-ecc
+edc
aUJ
ecd
asz
@@ -150033,7 +150004,7 @@ auT
awc
ecf
ecg
-eci
+ede
ecj
eck
aCx
@@ -155695,7 +155666,7 @@ aEf
aFB
aGX
aGY
-aGY
+aJA
aKZ
aMI
aGY
@@ -155950,7 +155921,7 @@ aBF
aCP
aEg
aFC
-aGY
+aGX
aGY
aJA
aLa
@@ -156213,9 +156184,9 @@ aJA
aLb
aMK
aGY
-ecj
+edf
aRH
-aGY
+aJA
aGY
aGZ
aYv
@@ -165305,7 +165276,7 @@ dGR
cKs
cKs
dJl
-ecd
+dJp
dKY
dJp
dJp
@@ -165562,9 +165533,9 @@ dGS
cDe
aaa
aaa
-ece
-ecf
-ecg
+dJp
+edg
+dJp
aaa
aaa
dJp
@@ -168866,8 +168837,8 @@ cEq
cGb
cHs
cvP
-cCg
eci
+cCg
cNS
cxw
cvP
diff --git a/code/__DEFINES/clockcult.dm b/code/__DEFINES/clockcult.dm
index d97dbc6cf5..8b140cb8b7 100644
--- a/code/__DEFINES/clockcult.dm
+++ b/code/__DEFINES/clockcult.dm
@@ -87,9 +87,9 @@ var/global/list/all_scripture = list() //a list containing scripture instances;
#define CLOCKCULT_ESCAPE "escape"
-#define CLOCKCULT_SILICONS "silicons"
-
//misc clockcult stuff
#define MARAUDER_EMERGE_THRESHOLD 65 //marauders cannot emerge unless host is at this% or less health
#define SIGIL_ACCESS_RANGE 2 //range at which transmission sigils can access power
+
+#define PROSELYTIZER_REPAIR_PER_TICK 4 //how much a proselytizer repairs each tick, and also how many deciseconds each tick is
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 4424f05436..d4acb7f4b4 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -408,4 +408,4 @@ var/global/list/ghost_others_options = list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define TURF_DECAL_PAINT "paint"
#define TURF_DECAL_DAMAGE "damage"
-#define TURF_DECAL_DIRT "dirt"
\ No newline at end of file
+#define TURF_DECAL_DIRT "dirt"
diff --git a/code/__DEFINES/monkeys.dm b/code/__DEFINES/monkeys.dm
index 76f7ea850c..52ef4b5590 100644
--- a/code/__DEFINES/monkeys.dm
+++ b/code/__DEFINES/monkeys.dm
@@ -35,4 +35,4 @@
#define MONKEY_HUNT_FRUSTRATION_LIMIT 8 // Chase after an enemy before giving up
#define MONKEY_DISPOSE_FRUSTRATION_LIMIT 16 // Dispose of a body before giving up
-#define MONKEY_AGGRESSIVE_MVM_PROB 1 // If you mass edit monkies to be aggressive. there is a small chance of in-fighting
\ No newline at end of file
+#define MONKEY_AGGRESSIVE_MVM_PROB 0 // If you mass edit monkies to be aggressive. there is a small chance of in-fighting
\ No newline at end of file
diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm
index ae1f2b26ec..5e82a8ab26 100644
--- a/code/__HELPERS/lists.dm
+++ b/code/__HELPERS/lists.dm
@@ -465,3 +465,4 @@
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
#define LAZYLEN(L) length(L)
+#define LAZYCLEARLIST(L) if(L) L.Cut()
\ No newline at end of file
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index b301fab1c3..4036470cf7 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -38,6 +38,8 @@
var/turf_visible
if(pixel_turf)
turf_visible = cameranet.checkTurfVis(pixel_turf)
+ if(istype(loc, /obj/item/device/aicard) && (pixel_turf in view(client.view, loc)))
+ turf_visible = TRUE
if(!turf_visible)
log_admin("[key_name_admin(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([COORD(pixel_turf)])")
message_admins("[key_name_admin(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([ADMIN_COORDJMP(pixel_turf)]))")
@@ -184,4 +186,4 @@
//
/mob/living/silicon/ai/TurfAdjacent(var/turf/T)
- return (cameranet && cameranet.checkTurfVis(T))
+ return (cameranet && cameranet.checkTurfVis(T))
\ No newline at end of file
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 18fc45bb47..8a8faea5c4 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -20,8 +20,8 @@
var/name = "Configuration" // datum name
var/server_name = null // server name (the name of the game window)
+ var/server_sql_name = null // short form server name used for the DB
var/station_name = null // station name (the name of the station in-game)
- var/server_suffix = 0 // generate numeric suffix based on server port
var/lobby_countdown = 120 // In between round countdown.
var/round_end_countdown = 25 // Post round murder death kill countdown
var/hub = 0
@@ -78,8 +78,7 @@
var/forbid_singulo_possession = 0
var/useircbot = 0
- var/announce_watchlist = 0
- var/announce_adminhelps = 0
+
var/check_randomizer = 0
var/allow_panic_bunker_bounce = 0 //Send new players somewhere else
@@ -95,6 +94,11 @@
var/mentors_mobname_only = 0 // Only display mob name to mentors in mentorhelps
var/mentor_legacy_system = 0 // Whether to use the legacy mentor system (flat file) instead of SQL
+ // Discord crap.
+ var/discord_url = "hfdksjhfa.com"
+ var/discord_password
+ var/announce_watchlist = 0
+ var/announce_adminhelps = 0
var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt
var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt
@@ -242,10 +246,6 @@
var/list/gamemode_cache = null
- // Discord crap.
- var/discord_url = "hfdksjhfa.com"
- var/discord_password
-
var/minutetopiclimit
var/secondtopiclimit
@@ -359,10 +359,10 @@
config.respawn = 0
if("servername")
config.server_name = value
+ if("serversqlname")
+ config.server_sql_name = 1
if("stationname")
config.station_name = value
- if("serversuffix")
- config.server_suffix = 1
if("hostedby")
config.hostedby = value
if("server")
@@ -499,16 +499,16 @@
config.client_error_version = text2num(value)
if("client_error_message")
config.client_error_message = value
+ if("minute_topic_limit")
+ config.minutetopiclimit = text2num(value)
+ if("second_topic_limit")
+ config.secondtopiclimit = text2num(value)
if("announce_adminhelps")
config.announce_adminhelps = 1
if("discord_url")
config.discord_url = value
if("discord_password")
config.discord_password = value
- if("minute_topic_limit")
- config.minutetopiclimit = text2num(value)
- if("second_topic_limit")
- config.secondtopiclimit = text2num(value)
else
diary << "Unknown setting in configuration: '[name]'"
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 86d1a4672e..dd88760e5f 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -322,6 +322,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
SS_flags = SS.flags
if (SS_flags & SS_NO_FIRE)
subsystemstocheck -= SS
+ continue
if (!(SS_flags & SS_TICKER) && (SS_flags & SS_KEEP_TIMING) && SS.last_fire + (SS.wait * 0.75) > world.time)
continue
SS.enqueue()
diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm
index 5eb987f2f3..ab6cb29061 100644
--- a/code/controllers/subsystem/air.dm
+++ b/code/controllers/subsystem/air.dm
@@ -39,28 +39,34 @@ var/datum/subsystem/air/SSair
var/list/currentrun = list()
var/currentpart = SSAIR_PIPENETS
+ var/map_loading = TRUE
+ var/list/queued_for_activation
/datum/subsystem/air/New()
NEW_SS_GLOBAL(SSair)
/datum/subsystem/air/stat_entry(msg)
msg += "C:{"
- msg += "AT:[round(cost_turfs)]|"
- msg += "EG:[round(cost_groups)]|"
- msg += "HP:[round(cost_highpressure)]|"
- msg += "HS:[round(cost_hotspots)]|"
- msg += "SC:[round(cost_superconductivity)]|"
- msg += "PN:[round(cost_pipenets)]|"
- msg += "AM:[round(cost_atmos_machinery)]"
+ msg += "AT:[round(cost_turfs,1)]|"
+ msg += "EG:[round(cost_groups,1)]|"
+ msg += "HP:[round(cost_highpressure,1)]|"
+ msg += "HS:[round(cost_hotspots,1)]|"
+ msg += "SC:[round(cost_superconductivity,1)]|"
+ msg += "PN:[round(cost_pipenets,1)]|"
+ msg += "AM:[round(cost_atmos_machinery,1)]"
msg += "} "
- msg += "AT:[active_turfs.len]|"
- msg += "EG:[excited_groups.len]|"
- msg += "HS:[hotspots.len]|"
- msg += "AS:[active_super_conductivity.len]"
+ msg += "AT:[active_turfs.len]|"
+ msg += "EG:[excited_groups.len]|"
+ msg += "HS:[hotspots.len]|"
+ msg += "PN:[networks.len]|"
+ msg += "HP:[high_pressure_delta.len]|"
+ msg += "AS:[active_super_conductivity.len]|"
+ msg += "AT/MS:[round((cost ? active_turfs.len/cost : 0),0.1)]"
..(msg)
/datum/subsystem/air/Initialize(timeofday)
+ map_loading = FALSE
setup_allturfs()
setup_atmos_machinery()
setup_pipenets()
@@ -244,7 +250,6 @@ var/datum/subsystem/air/SSair
if(T.excited_group)
T.excited_group.garbage_collect()
-
/datum/subsystem/air/proc/add_to_active(turf/open/T, blockchanges = 1)
if(istype(T) && T.air)
T.excited = 1
@@ -253,10 +258,25 @@ var/datum/subsystem/air/SSair
currentrun |= T
if(blockchanges && T.excited_group)
T.excited_group.garbage_collect()
- else
+ else if(T.initialized)
for(var/turf/S in T.atmos_adjacent_turfs)
add_to_active(S)
+ else if(map_loading)
+ if(queued_for_activation)
+ queued_for_activation[T] = T
+ return
+ else
+ T.requires_activation = TRUE
+/datum/subsystem/air/proc/begin_map_load()
+ LAZYINITLIST(queued_for_activation)
+ map_loading = TRUE
+
+/datum/subsystem/air/proc/end_map_load()
+ map_loading = FALSE
+ for(var/T in queued_for_activation)
+ add_to_active(T)
+ queued_for_activation.Cut()
/datum/subsystem/air/proc/setup_allturfs()
var/list/turfs_to_init = block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz))
diff --git a/code/controllers/subsystem/processing/objects.dm b/code/controllers/subsystem/processing/objects.dm
index 01957e766f..6bbd0ffeb3 100644
--- a/code/controllers/subsystem/processing/objects.dm
+++ b/code/controllers/subsystem/processing/objects.dm
@@ -27,26 +27,52 @@ var/datum/subsystem/objects/SSobj
/datum/subsystem/objects/proc/InitializeAtoms(list/objects = null)
if(initialized == INITIALIZATION_INSSOBJ)
return
+
+ var/list/late_loaders
+
initialized = INITIALIZATION_INNEW_MAPLOAD
+
if(objects)
for(var/I in objects)
var/atom/A = I
if(!A.initialized) //this check is to make sure we don't call it twice on an object that was created in a previous Initialize call
var/start_tick = world.time
- A.Initialize(TRUE)
+ if(A.Initialize(TRUE))
+ LAZYADD(late_loaders, A)
if(start_tick != world.time)
WARNING("[A]: [A.type] slept during it's Initialize!")
CHECK_TICK
+ testing("Initialized [objects.len] atoms")
else
+ #ifdef TESTING
+ var/count = 0
+ #endif
for(var/atom/A in world)
if(!A.initialized) //this check is to make sure we don't call it twice on an object that was created in a previous Initialize call
var/start_tick = world.time
- A.Initialize(TRUE)
+ if(A.Initialize(TRUE))
+ LAZYADD(late_loaders, A)
+ #ifdef TESTING
+ else
+ ++count
+ #endif TESTING
if(start_tick != world.time)
WARNING("[A]: [A.type] slept during it's Initialize!")
CHECK_TICK
+ testing("Roundstart initialized [count] atoms")
+
initialized = INITIALIZATION_INNEW_REGULAR
+ if(late_loaders)
+ for(var/I in late_loaders)
+ var/atom/A = I
+ var/start_tick = world.time
+ A.Initialize(FALSE)
+ if(start_tick != world.time)
+ WARNING("[A]: [A.type] slept during it's Initialize!")
+ CHECK_TICK
+ testing("Late-initialized [late_loaders.len] atoms")
+
/datum/subsystem/objects/proc/map_loader_begin()
old_initialized = initialized
initialized = INITIALIZATION_INSSOBJ
diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm
index 56d887eb8b..2b23ac485a 100644
--- a/code/controllers/subsystem/throwing.dm
+++ b/code/controllers/subsystem/throwing.dm
@@ -66,11 +66,11 @@ var/datum/subsystem/throwing/SSthrowing
/datum/thrownthing/proc/tick()
var/atom/movable/AM = thrownthing
if (!isturf(AM.loc) || !AM.throwing)
- finialize()
+ finalize()
return
if (dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept
- finialize()
+ finalize()
return
var/atom/step
@@ -79,7 +79,7 @@ var/datum/subsystem/throwing/SSthrowing
var/tilestomove = round(min(((((world.time+world.tick_lag) - start_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
while (tilestomove-- > 0)
if ((dist_travelled >= maxrange || AM.loc == target_turf) && AM.has_gravity(AM.loc))
- finialize()
+ finalize()
return
if (dist_travelled <= max(dist_x, dist_y)) //if we haven't reached the target yet we home in on it, otherwise we use the initial direction
@@ -93,47 +93,52 @@ var/datum/subsystem/throwing/SSthrowing
diagonal_error += (diagonal_error < 0) ? dist_x/2 : -dist_y
if (!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
- finialize()
+ finalize()
return
AM.Move(step, get_dir(AM, step))
if (!AM.throwing) // we hit something during our move
- finialize(hit = TRUE)
+ finalize(hit = TRUE)
return
dist_travelled++
if (dist_travelled > MAX_THROWING_DIST)
- finialize()
+ finalize()
return
-/datum/thrownthing/proc/finialize(hit = FALSE)
+/datum/thrownthing/proc/finalize(hit = FALSE)
set waitfor = 0
SSthrowing.processing -= thrownthing
//done throwing, either because it hit something or it finished moving
- thrownthing.throwing = 0
+ thrownthing.throwing = null
if (!hit)
for (var/thing in get_turf(thrownthing)) //looking for our target on the turf we land on.
var/atom/A = thing
if (A == target)
hit = 1
- thrownthing.throw_impact(A)
+ thrownthing.throw_impact(A, src)
break
if (!hit)
- thrownthing.throw_impact(get_turf(thrownthing)) // we haven't hit something yet and we still must, let's hit the ground.
+ thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground.
thrownthing.newtonian_move(init_dir)
else
thrownthing.newtonian_move(init_dir)
if (callback)
callback.Invoke()
+/datum/thrownthing/proc/hit_atom(atom/A)
+ thrownthing.throw_impact(A, src)
+ thrownthing.newtonian_move(init_dir)
+ finalize(TRUE)
+
/datum/thrownthing/proc/hitcheck()
for (var/thing in get_turf(thrownthing))
var/atom/movable/AM = thing
if (AM == thrownthing)
continue
if (AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags & ON_BORDER))
- thrownthing.throwing = 0
- thrownthing.throw_impact(AM)
- return 1
+ thrownthing.throwing = null
+ thrownthing.throw_impact(AM, src)
+ return TRUE
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index e226aff2c8..08fd4f60c0 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -9,7 +9,10 @@ var/global/datum/getrev/revdata = new()
/datum/getrev/New()
var/head_file = return_file_text(".git/logs/HEAD")
if(SERVERTOOLS && fexists("..\\prtestjob.lk"))
- testmerge = file2list("..\\prtestjob.lk")
+ var/list/tmp = file2list("..\\prtestjob.lk")
+ for(var/I in tmp)
+ if(I)
+ testmerge |= I
var/testlen = max(testmerge.len - 1, 0)
var/regex/head_log = new("(\\w{40}) .+> (\\d{10}).+(?=(\n.*(\\w{40}).*){[testlen]}\n*\\Z)")
head_log.Find(head_file)
@@ -81,4 +84,4 @@ var/global/datum/getrev/revdata = new()
if(config.probabilities[ctag] > 0)
var/percentage = round(config.probabilities[ctag] / sum * 100, 0.1)
src << "[ctag] [percentage]%"
- return
\ No newline at end of file
+ return
diff --git a/code/datums/helper_datums/map_template.dm b/code/datums/helper_datums/map_template.dm
index 19f9c1ff0d..1912be6a27 100644
--- a/code/datums/helper_datums/map_template.dm
+++ b/code/datums/helper_datums/map_template.dm
@@ -31,6 +31,7 @@
for(var/L in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]),
locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
var/turf/B = L
+ atoms += B
for(var/A in B)
atoms += A
if(istype(A,/obj/structure/cable))
@@ -43,6 +44,7 @@
SSobj.InitializeAtoms(atoms)
SSmachine.setup_template_powernets(cables)
SSair.setup_template_machinery(atmos_machines)
+ SSair.end_map_load()
/datum/map_template/proc/load(turf/T, centered = FALSE)
if(centered)
@@ -54,8 +56,10 @@
if(T.y+height > world.maxy)
return
+ SSair.begin_map_load()
var/list/bounds = maploader.load_map(get_file(), T.x, T.y, T.z, cropMap=TRUE)
if(!bounds)
+ SSair.end_map_load()
return 0
//initialize things that are normally initialized after map load
diff --git a/code/datums/riding.dm b/code/datums/riding.dm
index 9695dbae12..27911b88df 100644
--- a/code/datums/riding.dm
+++ b/code/datums/riding.dm
@@ -297,3 +297,75 @@
handle_vehicle_offsets()
else
user << "You'll need something to guide the [ridden.name]."
+
+//CYBORGS. NO, THEY ARE NOT ANIMALS.
+/datum/riding/cyborg
+ keytype = null
+ vehicle_move_delay = 1
+
+/datum/riding/cyborg/proc/ride_check(mob/user)
+ if(user.incapacitated())
+ var/kick = TRUE
+ if(istype(ridden, /mob/living/silicon/robot))
+ var/mob/living/silicon/robot/R = ridden
+ if(R.module && R.module.ride_allow_incapacitated)
+ kick = FALSE
+ if(kick)
+ user << "You fall off of [ridden]!"
+ ridden.unbuckle_mob(user)
+ return
+ if(istype(user, /mob/living/carbon))
+ var/mob/living/carbon/carbonuser = user
+ if(!carbonuser.get_num_arms())
+ ridden.unbuckle_mob(user)
+ user << "You can't grab onto [ridden] with no hands!"
+ return
+
+/datum/riding/cyborg/handle_vehicle_layer()
+ if(ridden.dir == SOUTH)
+ ridden.layer = ABOVE_MOB_LAYER
+ else
+ ridden.layer = OBJ_LAYER
+ if(!ridden.buckled_mobs)
+ ridden.layer = MOB_LAYER
+
+/datum/riding/cyborg/handle_vehicle_offsets()
+ if(ridden.has_buckled_mobs())
+ for(var/mob/living/M in ridden.buckled_mobs)
+ M.setDir(ridden.dir)
+ if(iscyborg(ridden))
+ var/mob/living/silicon/robot/R = ridden
+ if(istype(R.module))
+ M.pixel_x = R.module.ride_offset_x[dir2text(ridden.dir)]
+ M.pixel_y = R.module.ride_offset_y[dir2text(ridden.dir)]
+ else
+ switch(ridden.dir)
+ if(NORTH)
+ M.pixel_x = 0
+ M.pixel_y = 4
+ if(SOUTH)
+ M.pixel_x = 0
+ M.pixel_y = 4
+ if(EAST)
+ M.pixel_x = -6
+ M.pixel_y = 3
+ if(WEST)
+ M.pixel_x = 6
+ M.pixel_y = 3
+
+/datum/riding/cyborg/proc/on_vehicle_move()
+ for(var/mob/living/M in ridden.buckled_mobs)
+ ride_check(M)
+ handle_vehicle_offsets()
+ handle_vehicle_layer()
+
+/datum/riding/cyborg/proc/force_dismount()
+ for(var/mob/living/M in ridden.buckled_mobs)
+ ridden.unbuckle_mob(M)
+ var/turf/target = get_edge_target_turf(ridden, ridden.dir)
+ var/turf/targetm = get_step(get_turf(ridden), ridden.dir)
+ M.Move(targetm)
+ M.visible_message("[M] is thrown clear of [ridden] by rapid spinning!")
+ M.throw_at(target, 14, 5, ridden)
+ M.Weaken(3)
+
diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm
index 911a37280a..aac65a7a44 100644
--- a/code/datums/shuttles.dm
+++ b/code/datums/shuttles.dm
@@ -73,6 +73,19 @@
admin_notes = "Due to the limited space for non paying crew, this shuttle may cause a riot."
credit_cost = 10000
+
+/datum/map_template/shuttle/emergency/arena
+ suffix = "arena"
+ name = "The Arena"
+ description = "The crew must pass through an otherworldy arena to board this shuttle. Expect massive casualties. The source of the Bloody Signal must be tracked down and eliminated to unlock this shuttle."
+ admin_notes = "RIP AND TEAR."
+ credit_cost = 10000
+
+/datum/map_template/shuttle/emergency/arena/prerequisites_met()
+ if("bubblegum" in SSshuttle.shuttle_purchase_requirements_met)
+ return TRUE
+ return FALSE
+
/datum/map_template/shuttle/emergency/birdboat
suffix = "birdboat"
name = "Birdboat Station Emergency Shuttle"
@@ -104,7 +117,6 @@
\n\
Contains contraband armory guns, maintenance loot, and abandoned crates!"
admin_notes = "Due to origin as a solo piloted secure vessel, has an active GPS onboard labeled STV5."
- credit_cost = -7500
/datum/map_template/shuttle/emergency/meta
suffix = "meta"
@@ -160,8 +172,8 @@
/datum/map_template/shuttle/emergency/goon
suffix = "goon"
name = "NES Port"
- description = "The Nanotrasen Emergency Shuttle Port(NES Port for short) is a shuttle used at other less known nanotrasen facilities and has a more open inside for larger crowds."
- credit_cost = 3000
+ description = "The Nanotrasen Emergency Shuttle Port(NES Port for short) is a shuttle used at other less known Nanotrasen facilities and has a more open inside for larger crowds, but fewer onboard shuttle facilities."
+ credit_cost = 500
/datum/map_template/shuttle/emergency/wabbajack
suffix = "wabbajack"
@@ -219,4 +231,4 @@
name = "Delta Station Emergency Shuttle"
description = "A large shuttle for a large station, this shuttle can comfortably fit all your overpopulation and crowding needs. Complete with all facilities plus additional equipment."
admin_notes = "Go big or go home."
- credit_cost = 7500
+ credit_cost = 7500
\ No newline at end of file
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index b7289f58b4..4df19f3201 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -41,11 +41,26 @@
if(luminosity)
light = new(src)
- var/initialized = SSobj.initialized
- if(initialized > INITIALIZATION_INSSOBJ)
- Initialize(initialized == INITIALIZATION_INNEW_MAPLOAD)
+ var/do_initialize = SSobj.initialized
+ if(do_initialize > INITIALIZATION_INSSOBJ)
+ Initialize(do_initialize == INITIALIZATION_INNEW_MAPLOAD)
//. = ..() //uncomment if you are dumb enough to add a /datum/New() proc
+//Called after New if the map is being loaded. mapload = TRUE
+//Called from base of New if the map is being loaded. mapload = FALSE
+//This base must be called or derivatives must set initialized to TRUE to prevent repeat calls
+//Derivatives must not sleep
+//Returning TRUE while mapload is TRUE will cause the object to be initialized again with mapload = FALSE when everything else is done
+//(Useful for things that requires turfs to have air). This base may only be called once, however
+
+//Note: the following functions don't call the base for optimization and must copypasta:
+// /turf/Initialize
+// /turf/open/space/Initialize
+/atom/proc/Initialize(mapload)
+ if(initialized)
+ stack_trace("Warning: [src]([type]) initialized multiple times!")
+ initialized = TRUE
+
/atom/Destroy()
if(alternate_appearances)
for(var/aakey in alternate_appearances)
@@ -435,17 +450,6 @@ var/list/blood_splatter_icons = list()
sleep(1)
stoplag()
-//Called after New if the world is not loaded with TRUE
-//Called from base of New if the world is loaded with FALSE
-//This base must be called or derivatives must set initialized to TRUE to prevent repeat calls
-//Derivatives must not sleep
-/atom/proc/Initialize(mapload)
-#ifdef TESTING
- if(initialized)
- stack_trace("Warning: [src]([type]) initialized multiple times!")
-#endif
- initialized = TRUE
-
//the vision impairment to give to the mob whose perspective is set to that atom (e.g. an unfocused camera giving you an impaired vision when looking through it)
/atom/proc/get_remote_view_fullscreens(mob/user)
return
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 7331123317..2984cb38d8 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -2,7 +2,7 @@
layer = OBJ_LAYER
var/last_move = null
var/anchored = 0
- var/throwing = 0
+ var/datum/thrownthing/throwing = null
var/throw_speed = 2 //How many tiles to move per ds when being thrown. Float values are fully supported
var/throw_range = 7
var/mob/pulledby = null
@@ -130,14 +130,12 @@
/atom/movable/Bump(atom/A, yes) //the "yes" arg is to differentiate our Bump proc from byond's, without it every Bump() call would become a double Bump().
if((A && yes))
if(throwing)
- throwing = 0
- throw_impact(A)
+ throwing.hit_atom(A)
. = 1
if(!A || QDELETED(A))
return
A.Bumped(src)
-
/atom/movable/proc/forceMove(atom/destination)
if(destination)
if(pulledby)
@@ -222,7 +220,7 @@
/atom/movable/proc/checkpass(passflag)
return pass_flags&passflag
-/atom/movable/proc/throw_impact(atom/hit_atom)
+/atom/movable/proc/throw_impact(atom/hit_atom, throwingdatum)
return hit_atom.hitby(src)
/atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked)
@@ -297,7 +295,7 @@
if(pulledby)
pulledby.stop_pulling()
- throwing = 1
+ throwing = TT
if(spin)
SpinAnimation(5, 1)
diff --git a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
index eb1f6626c0..b361e47d64 100644
--- a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
+++ b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
@@ -22,6 +22,7 @@
E.sight_flags -= SEE_MOBS
E.flash_protect = 2
user << "We adjust our eyes to protect them from bright lights."
+ user.update_sight()
else
user << "We can't adjust our eyes if we don't have any!"
diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm
index 1b3e59e518..e470a4eca9 100644
--- a/code/game/gamemodes/changeling/powers/mutations.dm
+++ b/code/game/gamemodes/changeling/powers/mutations.dm
@@ -150,7 +150,7 @@
icon = 'icons/obj/weapons.dmi'
icon_state = "arm_blade"
item_state = "arm_blade"
- flags = ABSTRACT | NODROP
+ flags = ABSTRACT | NODROP | DROPDEL
w_class = WEIGHT_CLASS_HUGE
force = 25
throwforce = 0 //Just to be on the safe side
@@ -203,7 +203,6 @@
..()
if(can_drop)
new /obj/item/weapon/melee/synthetic_arm_blade(get_turf(user))
- qdel(src)
/***************************************\
|***********COMBAT TENTACLES*************|
@@ -303,11 +302,10 @@
for(var/obj/item/I in H.held_items)
if(I.is_sharp())
C.visible_message("[H] impales [C] with [H.p_their()] [I.name]!", "[H] impales you with [H.p_their()] [I.name]!")
- C.apply_damage(I.force*2, BRUTE, "chest")
+ C.apply_damage(I.force, BRUTE, "chest")
H.do_item_attack_animation(C, used_item = I)
H.add_mob_blood(C)
playsound(get_turf(H),I.hitsound,75,1)
- C.Weaken(4)
return
/obj/item/projectile/tentacle/on_hit(atom/target, blocked = 0)
@@ -355,7 +353,6 @@
if(INTENT_HARM)
C.visible_message("[L] is thrown towards [H] by a tentacle!","A tentacle grabs you and throws you towards [H]!")
- C.Weaken(3)
C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(src, .proc/tentacle_stab, H, C))
return 1
else
diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm
index 693f74d871..5e70ce0a6f 100644
--- a/code/game/gamemodes/clock_cult/clock_cult.dm
+++ b/code/game/gamemodes/clock_cult/clock_cult.dm
@@ -84,8 +84,6 @@ Credit where due:
/datum/game_mode
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
- var/required_escapees = 0 //How many servants need to escape, if applicable
- var/required_silicon_converts = 0 //How many robotic lifeforms need to be converted, if applicable
var/clockwork_objective = CLOCKCULT_GATEWAY //The objective that the servants must fulfill
var/clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar." //The description of the current objective
@@ -141,20 +139,12 @@ Credit where due:
/datum/game_mode/clockwork_cult/proc/forge_clock_objectives() //Determine what objective that Ratvar's servants will fulfill
var/list/possible_objectives = list(CLOCKCULT_ESCAPE, CLOCKCULT_GATEWAY)
- var/silicons_possible = FALSE
- for(var/mob/living/silicon/ai/S in living_mob_list)
- silicons_possible = TRUE
- if(silicons_possible)
- possible_objectives += CLOCKCULT_SILICONS
clockwork_objective = pick(possible_objectives)
switch(clockwork_objective)
if(CLOCKCULT_ESCAPE)
- required_escapees = round(max(1, roundstart_player_count / 3)) //33% of the player count must be cultists
- clockwork_explanation = "Ensure that [required_escapees] servants of Ratvar escape from [station_name()]."
+ clockwork_explanation = "Construct a Gateway to the Celestial Derelict and proselytize the entire station."
if(CLOCKCULT_GATEWAY)
clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar."
- if(CLOCKCULT_SILICONS)
- clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar and Application scripture is unlocked."
return 1
/datum/game_mode/clockwork_cult/proc/greet_servant(mob/M) //Description of their role
@@ -199,27 +189,8 @@ Credit where due:
/datum/game_mode/clockwork_cult/proc/check_clockwork_victory()
switch(clockwork_objective)
if(CLOCKCULT_ESCAPE)
- var/surviving_servants = 0
- for(var/datum/mind/M in servants_of_ratvar)
- if(M.current && M.current.stat != DEAD && (M.current.onCentcom() || M.current.onSyndieBase()))
- surviving_servants++
- clockwork_explanation = "Ensure that [required_escapees] servant(s) of Ratvar escape from [station_name()].
[surviving_servants] managed to escape!"
- if(surviving_servants >= required_escapees)
- ticker.news_report = CULT_ESCAPE
- return TRUE
- if(CLOCKCULT_SILICONS)
- var/total_silicons = 0
- var/valid_silicons = 0
- for(var/mob/living/silicon/S in mob_list) //Only check robots and AIs
- if(isAI(S) || iscyborg(S))
- total_silicons++
- if(is_servant_of_ratvar(S) || S.stat == DEAD)
- valid_silicons++
- clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar and Application scripture is unlocked.
\
- [valid_silicons]/[total_silicons] silicons were killed or converted!"
- var/list/scripture_states = scripture_unlock_check()
- if(valid_silicons >= total_silicons && scripture_states[SCRIPTURE_APPLICATION])
- ticker.news_report = CLOCK_SILICONS
+ if(clockwork_gateway_activated)
+ ticker.news_report = CLOCK_PROSELYTIZATION
return TRUE
if(CLOCKCULT_GATEWAY)
if(ratvar_awakens)
@@ -241,18 +212,16 @@ Credit where due:
feedback_set_details("round_end_result", "win - servants completed their objective ([clockwork_objective])")
else
var/half_victory = FALSE
- if(clockwork_objective == CLOCKCULT_GATEWAY)
- var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = locate() in all_clockwork_objects
- if(G)
- half_victory = TRUE
+ var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = locate() in all_clockwork_objects
+ if(G)
+ half_victory = TRUE
if(half_victory)
- text += "The crew escaped before Ratvar could rise, but the gateway was successfully constructed!"
+ text += "The crew escaped before [clockwork_objective == CLOCKCULT_GATEWAY ? "Ratvar could rise":"the station could be proselytized"], but the gateway \
+ was successfully constructed!"
feedback_set_details("round_end_result", "halfwin - round ended before the gateway finished")
else
text += "Ratvar's servants have failed!"
feedback_set_details("round_end_result", "loss - servants failed their objective ([clockwork_objective])")
- if(clockwork_gateway_activated && clockwork_objective != CLOCKCULT_GATEWAY)
- ticker.news_report = CLOCK_PROSELYTIZATION
text += "
The servants' objective was:
[clockwork_explanation]"
text += "
Ratvar's servants had [clockwork_caches] Tinkerer's Caches."
text += "
Construction Value(CV) was: [clockwork_construction_value]"
diff --git a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
index 3822cc35a2..42c4a418c7 100644
--- a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
+++ b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm
@@ -159,11 +159,10 @@
/obj/effect/clockwork/sigil/submission/accession/post_channel(mob/living/L)
if(L.isloyal())
- var/mob/living/carbon/C = L
delete_on_finish = TRUE
- C.visible_message("[C] visibly trembles!", \
+ L.visible_message("[L] visibly trembles!", \
"[text2ratvar("You will be mine and his. This puny trinket will not stop me.")]")
- for(var/obj/item/weapon/implant/mindshield/M in C.implants)
+ for(var/obj/item/weapon/implant/mindshield/M in L.implants)
qdel(M)
diff --git a/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm b/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm
index a77580b2f9..6338f759a9 100644
--- a/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm
+++ b/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm
@@ -159,7 +159,7 @@
/obj/item/stack/tile/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(source)
return FALSE
- return list("operation_time" = amount, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_FLOOR), "spawn_dir" = SOUTH)
+ return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_FLOOR), "spawn_dir" = SOUTH)
//Airlock conversion
/obj/machinery/door/airlock/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
@@ -263,42 +263,18 @@
//Hitting a clockwork structure will try to repair it.
/obj/structure/destructible/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
. = TRUE
- if(!can_be_repaired)
- user << "[src] cannot be repaired!"
- return
- if(obj_integrity >= max_integrity)
- user << "[src] is at maximum integrity!"
- return
- var/amount_to_heal = max_integrity - obj_integrity
- var/healing_for_cycle = min(amount_to_heal, repair_amount)
- var/power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
- if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
- user << "You need at least [power_required]W power to start repairing [src], and at least \
- [round(amount_to_heal*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]W to fully repair it!"
+ var/list/repair_values = list()
+ if(!proselytizer.proselytizer_repair_checks(repair_values, src, user))
return
user.visible_message("[user]'s [proselytizer.name] starts covering [src] in glowing orange energy...", \
"You start repairing [src]...")
- //hugeass while because we need to re-check after the do_after
proselytizer.repairing = src
- while(proselytizer && user && src && obj_integrity < max_integrity)
- amount_to_heal = max_integrity - obj_integrity
- if(amount_to_heal <= 0)
+ while(proselytizer && user && src)
+ if(!do_after(user, repair_values["healing_for_cycle"] * proselytizer.speed_multiplier, target = src, \
+ extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytizer_repair_checks, repair_values, src, user, TRUE)))
break
- healing_for_cycle = min(amount_to_heal, repair_amount)
- power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
- if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)) || \
- !do_after(user, healing_for_cycle * proselytizer.speed_multiplier, target = src) || \
- !proselytizer || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
- break
- amount_to_heal = max_integrity - obj_integrity
- if(amount_to_heal <= 0)
- break
- healing_for_cycle = min(amount_to_heal, repair_amount)
- power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
- if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
- break
- obj_integrity = Clamp(obj_integrity + healing_for_cycle, 0, max_integrity)
- proselytizer.modify_stored_power(-power_required)
+ obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
+ proselytizer.modify_stored_power(-repair_values["power_required"])
playsound(src, 'sound/machines/click.ogg', 50, 1)
if(proselytizer)
@@ -309,42 +285,18 @@
//Proselytizer mob heal proc, to avoid as much copypaste as possible.
/mob/living/proc/proselytizer_heal(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
- if(!is_servant_of_ratvar(src))
- user << "[src] does not serve Ratvar!"
- return FALSE
- if(health >= maxHealth || (flags & GODMODE))
- user << "[src == user ? "You" : "[src]"] [src == user ? "are" : "is"] at maximum health!"
- return FALSE
- var/amount_to_heal = maxHealth - health
- var/healing_for_cycle = min(amount_to_heal, 4)
- var/power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
- if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
- user << "You need at least [power_required]W power to start repairing[src == user ? " yourself" : " [src]"], and at least \
- [round(amount_to_heal*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]W to fully repair [src == user ? "yourself" : "[p_them()]"]!"
- return FALSE
+ var/list/repair_values = list()
+ if(!proselytizer.proselytizer_repair_checks(repair_values, src, user))
+ return
user.visible_message("[user]'s [proselytizer.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...", \
"You start repairin[src == user ? "g yourself" : "g [src]"]...")
- //hugeass while because we need to re-check after the do_after
proselytizer.repairing = src
- while(proselytizer && user && src && health < maxHealth)
- amount_to_heal = maxHealth - health
- if(amount_to_heal <= 0)
+ while(proselytizer && user && src)
+ if(!do_after(user, repair_values["healing_for_cycle"] * proselytizer.speed_multiplier, target = src, \
+ extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytizer_repair_checks, repair_values, src, user, TRUE)))
break
- healing_for_cycle = min(amount_to_heal, 4)
- power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
- if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)) || \
- !do_after(user, healing_for_cycle * proselytizer.speed_multiplier, target = src) || \
- !proselytizer || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
- break
- amount_to_heal = maxHealth - health
- if(amount_to_heal <= 0)
- break
- healing_for_cycle = min(amount_to_heal, 4)
- power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
- if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)))
- break
- proselytizer_heal_tick(healing_for_cycle)
- proselytizer.modify_stored_power(-power_required)
+ proselytizer_heal_tick(repair_values["healing_for_cycle"])
+ proselytizer.modify_stored_power(-repair_values["power_required"])
playsound(src, 'sound/machines/click.ogg', 50, 1)
if(proselytizer)
@@ -382,14 +334,17 @@
if(health < maxHealth && !(flags & GODMODE))
user.visible_message("[user]'s [proselytizer.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...", \
"You start repairin[src == user ? "g yourself" : "g [src]"]...")
+ proselytizer.repairing = src
if(do_after(user,80*proselytizer.speed_multiplier, target=src))
adjustHealth(-maxHealth)
user.visible_message("[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.", \
"You finish repairin[src == user ? "g yourself" : "g [src]"].")
+ if(proselytizer)
+ proselytizer.repairing = null
else
user << "[src == user ? "You" : "[src]"] [src == user ? "are" : "is"] at maximum health!"
-//Convert shards and replicant alloy directly to power
+//Convert shards and gear bits directly to power
/obj/item/clockwork/alloy_shards/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -POWER_STANDARD, "spawn_dir" = SOUTH)
@@ -404,6 +359,3 @@
/obj/item/clockwork/alloy_shards/small/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.02), "spawn_dir" = SOUTH)
-
-/obj/item/clockwork/component/replicant_alloy/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
- return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -CLOCKCULT_POWER_UNIT, "spawn_dir" = SOUTH)
diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm
index f67e49802f..318b0c07a3 100644
--- a/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm
+++ b/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm
@@ -196,22 +196,17 @@
if(proselytize_values["power_cost"] > 0)
proselytize_values["power_cost"] *= 2
- if(!can_use_power(proselytize_values["power_cost"]))
- if(stored_power - proselytize_values["power_cost"] < 0)
- user << "You need [proselytize_values["power_cost"]]W power to proselytize [target]!"
- else if(stored_power - proselytize_values["power_cost"] > max_power)
- user << "Your [name] contains too much power to proselytize [target]!"
+ var/target_type = target.type
+
+ if(!proselytize_checks(proselytize_values, target, target_type, user))
return FALSE
proselytize_values["operation_time"] *= speed_multiplier
playsound(target, 'sound/machines/click.ogg', 50, 1)
if(proselytize_values["operation_time"])
- var/target_type = target.type
user.visible_message("[user]'s [name] begins tearing apart [target]!", "You begin proselytizing [target]...")
- if(!do_after(user, proselytize_values["operation_time"], target = target))
- return FALSE
- if(repairing || !can_use_power(proselytize_values["power_cost"]) || !target || target.type != target_type) //Check again to prevent bypassing via spamclick
+ if(!do_after(user, proselytize_values["operation_time"], target = target, extra_checks = CALLBACK(src, .proc/proselytize_checks, proselytize_values, target, target_type, user, TRUE)))
return FALSE
user.visible_message("[user]'s [name] covers [target] in golden energy!", "You proselytize [target].")
else
@@ -234,3 +229,64 @@
if(no_table_check)
return TRUE
return FALSE
+
+/obj/item/clockwork/clockwork_proselytizer/proc/proselytize_checks(list/proselytize_values, atom/target, expected_type, mob/user, silent) //checked constantly while proselytizing
+ if(!islist(proselytize_values) || !target || QDELETED(target) || !user)
+ return FALSE
+ if(repairing)
+ return FALSE
+ if(target.type != expected_type)
+ return FALSE
+ if(can_use_power(RATVAR_POWER_CHECK))
+ proselytize_values["power_cost"] = 0
+ if(!can_use_power(proselytize_values["power_cost"]))
+ if(stored_power - proselytize_values["power_cost"] < 0)
+ if(!silent)
+ user << "You need [proselytize_values["power_cost"]]W power to proselytize [target]!"
+ else if(stored_power - proselytize_values["power_cost"] > max_power)
+ if(!silent)
+ user << "Your [name] contains too much power to proselytize [target]!"
+ return FALSE
+ return TRUE
+
+//The repair check proc.
+//Is dark magic. Can probably kill you.
+/obj/item/clockwork/clockwork_proselytizer/proc/proselytizer_repair_checks(list/repair_values, atom/target, mob/user, silent) //Exists entirely to avoid an otherwise unreadable series of checks.
+ if(!islist(repair_values) || !target || QDELETED(target) || !user)
+ return FALSE
+ if(isliving(target))
+ var/mob/living/L = target
+ if(!is_servant_of_ratvar(L))
+ if(!silent)
+ user << "[L] does not serve Ratvar!"
+ return FALSE
+ if(L.health >= L.maxHealth || (L.flags & GODMODE))
+ if(!silent)
+ user << "[L == user ? "You are" : "[L] is"] at maximum health!"
+ return FALSE
+ repair_values["amount_to_heal"] = L.maxHealth - L.health
+ else if(isobj(target))
+ if(istype(target, /obj/structure/destructible/clockwork))
+ var/obj/structure/destructible/clockwork/C = target
+ if(!C.can_be_repaired)
+ if(!silent)
+ user << "[C] cannot be repaired!"
+ return FALSE
+ var/obj/O = target
+ if(O.obj_integrity >= O.max_integrity)
+ if(!silent)
+ user << "[O] is at maximum integrity!"
+ return FALSE
+ repair_values["amount_to_heal"] = O.max_integrity - O.obj_integrity
+ else
+ return FALSE
+ if(repair_values["amount_to_heal"] <= 0)
+ return FALSE
+ repair_values["healing_for_cycle"] = min(repair_values["amount_to_heal"], PROSELYTIZER_REPAIR_PER_TICK)
+ repair_values["power_required"] = round(repair_values["healing_for_cycle"]*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)
+ if(!can_use_power(RATVAR_POWER_CHECK) && !can_use_power(repair_values["power_required"]))
+ if(!silent)
+ user << "You need at least [repair_values["power_required"]]W power to start repairin[target == user ? "g yourself" : "g [target]"], and at least \
+ [round(repair_values["amount_to_heal"]*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]W to fully repair [target == user ? "yourself" : "[target.p_them()]"]!"
+ return FALSE
+ return TRUE
diff --git a/code/game/gamemodes/clock_cult/clock_scripture.dm b/code/game/gamemodes/clock_cult/clock_scripture.dm
index 579da88c8d..a0664aed72 100644
--- a/code/game/gamemodes/clock_cult/clock_scripture.dm
+++ b/code/game/gamemodes/clock_cult/clock_scripture.dm
@@ -179,7 +179,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
if(!channel_time)
return TRUE
for(var/invocation in invocations)
- if(!check_special_requirements() || !do_after(invoker, channel_time / invocations.len, target = invoker) || !check_special_requirements())
+ if(!do_after(invoker, channel_time / invocations.len, target = invoker, extra_checks = CALLBACK(src, .proc/check_special_requirements)))
slab.busy = null
return FALSE
if(multiple_invokers_used)
@@ -206,9 +206,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
/datum/clockwork_scripture/channeled/scripture_effects()
for(var/i in 1 to chant_amount)
- if(!can_recite())
- break
- if(!do_after(invoker, chant_interval, target = invoker))
+ if(!do_after(invoker, chant_interval, target = invoker, extra_checks = CALLBACK(src, .proc/can_recite)))
break
clockwork_say(invoker, text2ratvar(pick(chant_invocations)), whispered)
if(!chant_effects(i))
diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm
index 96ee1d61a8..3fa1143222 100644
--- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm
+++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm
@@ -3,7 +3,7 @@
///////////////
//Ark of the Clockwork Justiciar: Creates a Gateway to the Celestial Derelict, either summoning ratvar or proselytizing everything.
-/datum/clockwork_scripture/ark_of_the_clockwork_justiciar
+/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar
descname = "Structure, Win Condition"
name = "Ark of the Clockwork Justiciar"
desc = "Tears apart a rift in spacetime to Reebe, the Celestial Derelict.\n\
@@ -15,19 +15,21 @@
consumed_components = list(BELLIGERENT_EYE = 10, VANGUARD_COGWHEEL = 10, GEIS_CAPACITOR = 10, REPLICANT_ALLOY = 10, HIEROPHANT_ANSIBLE = 10)
invokers_required = 5
multiple_invokers_used = TRUE
+ object_path = /obj/structure/destructible/clockwork/massive/celestial_gateway
+ creator_message = null
usage_tip = "The gateway is completely vulnerable to attack during its five-minute duration. It will periodically give indication of its general position to everyone on the station \
as well as being loud enough to be heard throughout the entire sector. Defend it with your life!"
tier = SCRIPTURE_JUDGEMENT
sort_priority = 1
-/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/New()
+/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar/New()
if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY)
invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! I CALL UPON YOU!!", \
"THIS STATION WILL BE A BEACON OF HOPE IN THE DARKNESS OF SPACE!!", \
"HELP US MAKE THIS SHOW ENGINE'S GLORY!!")
..()
-/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/check_special_requirements()
+/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar/check_special_requirements()
if(!slab.no_cost)
if(ratvar_awakens)
invoker << "\"I am already here, idiot.\""
@@ -47,11 +49,4 @@
else
invoker << "Ratvar's recent banishment renders him too weak to be wrung forth from Reebe!"
return FALSE
- return TRUE
-
-/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/scripture_effects()
- var/turf/T = get_turf(invoker)
- if(T)
- new/obj/structure/destructible/clockwork/massive/celestial_gateway(T)
- return TRUE
- return FALSE
+ return ..()
diff --git a/code/game/gamemodes/clock_cult/clock_structure.dm b/code/game/gamemodes/clock_cult/clock_structure.dm
index 0cd51b624e..2aa3377b15 100644
--- a/code/game/gamemodes/clock_cult/clock_structure.dm
+++ b/code/game/gamemodes/clock_cult/clock_structure.dm
@@ -9,8 +9,7 @@
anchored = 1
density = 1
resistance_flags = FIRE_PROOF | ACID_PROOF
- var/repair_amount = 4 //how much a proselytizer can repair each cycle
- var/can_be_repaired = TRUE //if a proselytizer can repair it at all
+ var/can_be_repaired = TRUE //if a proselytizer can repair it
break_message = "The frog isn't a meme after all!" //The message shown when a structure breaks
break_sound = 'sound/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks
debris = list(/obj/item/clockwork/alloy_shards/large = 1, \
@@ -72,9 +71,10 @@
. *= min(max_integrity/max(obj_integrity, 1), 4)
. = round(., 0.01)
-/obj/structure/destructible/clockwork/can_be_unfasten_wrench(mob/user)
+/obj/structure/destructible/clockwork/can_be_unfasten_wrench(mob/user, silent)
if(anchored && obj_integrity <= round(max_integrity * 0.25, 1))
- user << "[src] is too damaged to unsecure!"
+ if(!silent)
+ user << "[src] is too damaged to unsecure!"
return FAILED_UNFASTEN
return ..()
@@ -158,9 +158,10 @@
var/powered = total_accessable_power()
return powered == PROCESS_KILL ? 25 : powered //make sure we don't accidentally return the arbitrary PROCESS_KILL define
-/obj/structure/destructible/clockwork/powered/can_be_unfasten_wrench(mob/user)
+/obj/structure/destructible/clockwork/powered/can_be_unfasten_wrench(mob/user, silent)
if(active)
- user << "[src] needs to be disabled before it can be unsecured!"
+ if(!silent)
+ user << "[src] needs to be disabled before it can be unsecured!"
return FAILED_UNFASTEN
return ..()
diff --git a/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
index f123579e34..9ca1606d10 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
@@ -74,8 +74,6 @@
hierophant_message("A gateway to the Celestial Derelict has been created in [gate_area.map_name]!", FALSE, src)
if(!objective_is_gateway)
ratvar_portal = FALSE
- hierophant_message("This newly constructed gateway will not free Ratvar, \
- and will instead simply proselytize and convert everything and everyone on the station.", TRUE)
SSshuttle.registerHostileEnvironment(src)
START_PROCESSING(SSprocessing, src)
@@ -210,13 +208,14 @@
animate(glow, transform = matrix() * 3, alpha = 0, time = 5)
var/turf/startpoint = get_turf(src)
QDEL_IN(src, 3)
- clockwork_gateway_activated = TRUE
if(ratvar_portal)
sleep(3)
+ clockwork_gateway_activated = TRUE
new/obj/structure/destructible/clockwork/massive/ratvar(startpoint)
else
INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency.proc/request, null, 0) //call the shuttle immediately
sleep(3)
+ clockwork_gateway_activated = TRUE
send_to_playing_players("\"[text2ratvar("Behold")]!\"\n\"[text2ratvar("See Engine's mercy")]!\"\n\
\"[text2ratvar("Observe Engine's design skills")]!\"\n\"[text2ratvar("Behold Engine's light")]!!\"\n\
\"[text2ratvar("Gaze upon Engine's power")]!\"")
@@ -234,13 +233,8 @@
dist = FALSE
T.ratvar_act(dist)
CHECK_TICK
- for(var/mob/living/silicon/robot/R in silicon_mobs)
- if(R && R.stat != DEAD && !is_servant_of_ratvar(R))
- add_servant_of_ratvar(R)
- for(var/i in ai_list)
- var/mob/living/silicon/ai/A = i
- if(A && A.stat != DEAD && !is_servant_of_ratvar(A))
- add_servant_of_ratvar(A)
+ for(var/mob/living/L in living_mob_list)
+ L.ratvar_act()
for(var/I in all_clockwork_mobs)
var/mob/M = I
if(M.stat == CONSCIOUS)
diff --git a/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm b/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm
index caae687cd4..a52cf68ebf 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm
@@ -25,9 +25,10 @@
if(is_servant_of_ratvar(user) || isobserver(user))
user << "It requires [hierophant_cost]W to broadcast over the Hierophant Network, and [gateway_cost]W to open a Spatial Gateway."
-/obj/structure/destructible/clockwork/powered/clockwork_obelisk/can_be_unfasten_wrench(mob/user)
+/obj/structure/destructible/clockwork/powered/clockwork_obelisk/can_be_unfasten_wrench(mob/user, silent)
if(active)
- user << "[src] is currently sustaining a gateway!"
+ if(!silent)
+ user << "[src] is currently sustaining a gateway!"
return FAILED_UNFASTEN
return ..()
diff --git a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
index 665ef9c2fc..f2768588c6 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm
@@ -32,14 +32,16 @@
/obj/structure/destructible/clockwork/ocular_warden/hulk_damage()
return 25
-/obj/structure/destructible/clockwork/ocular_warden/can_be_unfasten_wrench(mob/user)
+/obj/structure/destructible/clockwork/ocular_warden/can_be_unfasten_wrench(mob/user, silent)
if(anchored)
if(obj_integrity <= max_integrity * 0.25)
- user << "[src] is too damaged to unsecure!"
+ if(!silent)
+ user << "[src] is too damaged to unsecure!"
return FAILED_UNFASTEN
else
for(var/obj/structure/destructible/clockwork/ocular_warden/W in orange(3, src))
- user << "You sense another ocular warden too near this location. Activating this one this close would cause them to fight."
+ if(!silent)
+ user << "You sense another ocular warden too near this location. Activating this one this close would cause them to fight."
return FAILED_UNFASTEN
return SUCCESSFUL_UNFASTEN
diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm
index 5eb2379d2a..d03f2759a0 100644
--- a/code/game/gamemodes/cult/runes.dm
+++ b/code/game/gamemodes/cult/runes.dm
@@ -498,9 +498,9 @@ var/list/teleport_runes = list()
sleep(40)
if(src)
color = "#FF0000"
- new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed
if(cult_mode)
cult_mode.eldergod = 0
+ new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
if((istype(I, /obj/item/weapon/tome) && iscultist(user)))
diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
index b5abae7489..2a86b4766f 100644
--- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
+++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
@@ -196,9 +196,32 @@
/obj/item/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
return S.Integrate(src)
+/obj/item/proc/IntegrateAmount() //returns the amount of resources gained when eating this item
+ if(materials[MAT_METAL] || materials[MAT_GLASS])
+ return 1
+ return 0
+
/obj/item/weapon/gun/swarmer_act()//Stops you from eating the entire armory
return FALSE
+/obj/item/clockwork/alloy_shards/IntegrateAmount()
+ return 10
+
+/obj/item/stack/tile/brass/IntegrateAmount()
+ return 5
+
+/obj/item/clockwork/alloy_shards/medium/gear_bit/large/IntegrateAmount()
+ return 4
+
+/obj/item/clockwork/alloy_shards/large/IntegrateAmount()
+ return 3
+
+/obj/item/clockwork/alloy_shards/medium/IntegrateAmount()
+ return 2
+
+/obj/item/clockwork/alloy_shards/small/IntegrateAmount()
+ return 1
+
/turf/open/floor/swarmer_act()//ex_act() on turf calls it on its contents, this is to prevent attacking mobs by DisIntegrate()'ing the floor
return FALSE
@@ -316,6 +339,10 @@
S << "This communications relay should be preserved, it will be a useful resource to our masters in the future. Aborting."
return FALSE
+/obj/machinery/deepfryer/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "This kitchen appliance should be preserved, it will make delicious unhealthy snacks for our masters in the future. Aborting."
+ return FALSE
+
/obj/machinery/power/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
S << "Disrupting the power grid would bring no benefit to us. Aborting."
return FALSE
@@ -362,6 +389,10 @@
S << "This object is receiving unactivated swarmer shells to help us. Aborting."
return FALSE
+/obj/structure/destructible/clockwork/massive/celestial_gateway/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ S << "This object is multiplying existing resources. Aborting."
+ return FALSE
+
/obj/structure/lattice/catwalk/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
. = ..()
var/turf/here = get_turf(src)
@@ -373,13 +404,12 @@
/obj/item/device/unactivated_swarmer/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
- if(S.resources + 50 > S.max_resources)
- S << "We have too many resources to reconsume this shell. Aborting."
- else
- ..()
- S.resources += 49 //refund the whole thing
+ ..()
return FALSE //would logically be TRUE, but we don't want AI swarmers eating player spawn chances.
+/obj/item/device/unactivated_swarmer/IntegrateAmount()
+ return 50
+
/obj/machinery/hydroponics/soil/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
S << "This object does not contain enough materials to work with."
return FALSE
@@ -396,13 +426,13 @@
return 0
return new fabrication_object(loc)
-
/mob/living/simple_animal/hostile/swarmer/proc/Integrate(obj/item/target)
- if(resources >= max_resources)
+ var/resource_gain = target.IntegrateAmount()
+ if(resources + resource_gain > max_resources)
src << "We cannot hold more materials!"
return TRUE
- if((target.materials[MAT_METAL]) || (target.materials[MAT_GLASS]))
- resources++
+ if(resource_gain)
+ resources += resource_gain
do_attack_animation(target)
changeNext_move(CLICK_CD_MELEE)
var/obj/effect/overlay/temp/swarmer/integrate/I = new /obj/effect/overlay/temp/swarmer/integrate(get_turf(target))
diff --git a/code/game/gamemodes/nuclear/nuclear_challenge.dm b/code/game/gamemodes/nuclear/nuclear_challenge.dm
index b343f2bdf6..941e469d28 100644
--- a/code/game/gamemodes/nuclear/nuclear_challenge.dm
+++ b/code/game/gamemodes/nuclear/nuclear_challenge.dm
@@ -57,6 +57,7 @@
U.hidden_uplink.telecrystals = CHALLENGE_TELECRYSTALS
U.hidden_uplink.set_gamemode(/datum/game_mode/nuclear)
config.shuttle_refuel_delay = max(config.shuttle_refuel_delay, CHALLENGE_SHUTTLE_DELAY)
+ feedback_set("nuclear_challenge_mode",1)
qdel(src)
/obj/item/device/nuclear_challenge/proc/check_allowed(mob/living/user)
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index c222189cc8..b66caf4402 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -20,7 +20,7 @@ var/bomb_set
density = 1
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
- var/timer_set = 60
+ var/timer_set = 90
var/default_timer_set = 90
var/minimum_timer_set = 90
var/maximum_timer_set = 3600
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 630e989975..a4bb52ead6 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -72,6 +72,7 @@
/obj/machinery/door/firedoor/attack_hand(mob/user)
if(operating || !density)
return
+ user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("[user] bangs on \the [src].",
"You bang on \the [src].")
diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm
index c358a173e7..29fa0e2a67 100644
--- a/code/game/machinery/firealarm.dm
+++ b/code/game/machinery/firealarm.dm
@@ -96,7 +96,7 @@
return
var/area/A = get_area(src)
A.firealert(src)
- playsound(src.loc, 'sound/ambience/signal.ogg', 75, 0)
+ playsound(src.loc, 'goon/sound/machinery/FireAlarm.ogg', 75, 0)
/obj/machinery/firealarm/proc/alarm_in(time)
addtimer(CALLBACK(src, .proc/alarm), time)
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 8722bcc074..117a4e9e8e 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -356,13 +356,13 @@ Class Procs:
return 1
return 0
-/obj/proc/can_be_unfasten_wrench(mob/user)
+/obj/proc/can_be_unfasten_wrench(mob/user, silent) //if we can unwrench this object; returns SUCCESSFUL_UNFASTEN and FAILED_UNFASTEN, which are both TRUE, or CANT_UNFASTEN, which isn't.
if(!isfloorturf(loc) && !anchored)
user << "[src] needs to be on the floor to be secured!"
return FAILED_UNFASTEN
return SUCCESSFUL_UNFASTEN
-/obj/proc/default_unfasten_wrench(mob/user, obj/item/weapon/wrench/W, time = 20)
+/obj/proc/default_unfasten_wrench(mob/user, obj/item/weapon/wrench/W, time = 20) //try to unwrench an object in a WONDERFUL DYNAMIC WAY
if(istype(W) && !(flags & NODECONSTRUCT))
var/can_be_unfasten = can_be_unfasten_wrench(user)
if(!can_be_unfasten || can_be_unfasten == FAILED_UNFASTEN)
@@ -372,10 +372,7 @@ Class Procs:
playsound(loc, W.usesound, 50, 1)
var/prev_anchored = anchored
//as long as we're the same anchored state and we're either on a floor or are anchored, toggle our anchored state
- if(!time || (do_after(user, time*W.toolspeed, target = src) && anchored == prev_anchored))
- can_be_unfasten = can_be_unfasten_wrench(user)
- if(!can_be_unfasten || can_be_unfasten == FAILED_UNFASTEN)
- return can_be_unfasten
+ if(!time || do_after(user, time*W.toolspeed, target = src, extra_checks = CALLBACK(src, .proc/unfasten_wrench_check, prev_anchored, user)))
user << "You [anchored ? "un" : ""]secure [src]."
anchored = !anchored
playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1)
@@ -383,6 +380,13 @@ Class Procs:
return FAILED_UNFASTEN
return CANT_UNFASTEN
+/obj/proc/unfasten_wrench_check(prev_anchored, mob/user) //for the do_after, this checks if unfastening conditions are still valid
+ if(anchored != prev_anchored)
+ return FALSE
+ if(can_be_unfasten_wrench(user, TRUE) != SUCCESSFUL_UNFASTEN) //if we aren't explicitly successful, cancel the fuck out
+ return FALSE
+ return TRUE
+
/obj/machinery/proc/exchange_parts(mob/user, obj/item/weapon/storage/part_replacer/W)
if(!istype(W))
return
diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm
index 23f2b10ad8..f834a52e73 100644
--- a/code/game/machinery/status_display.dm
+++ b/code/game/machinery/status_display.dm
@@ -123,6 +123,8 @@
switch(mode)
if(1,2,4,5)
user << "The display says:
\t[message1]
\t[message2]"
+ if(mode == 1 && SSshuttle.emergency)
+ user << "Current Shuttle: [SSshuttle.emergency.name]"
/obj/machinery/status_display/proc/set_message(m1, m2)
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 12dd33e998..faa1f0d851 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -762,7 +762,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
/obj/machinery/vending/cigarette
name = "\improper ShadyCigs Deluxe"
- desc = "If you want to get cancer, might as well do it in style"
+ desc = "If you want to get cancer, might as well do it in style."
product_slogans = "Space cigs taste good like a cigarette should.;I'd rather toolbox than switch.;Smoke!;Don't believe the reports - smoke today!"
product_ads = "Probably not bad for you!;Don't believe the scientists!;It's good for you!;Don't quit, buy more!;Smoke!;Nicotine heaven.;Best cigarettes since 2150.;Award-winning cigs."
icon_state = "cigs"
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 3dd395d01f..b1945d7b74 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -358,8 +358,11 @@
occupant.throw_alert("mech damage", /obj/screen/alert/low_mech_integrity, 3)
else
occupant.clear_alert("mech damage")
-
- if(occupant.loc != src) //something went wrong
+ var/actual_loc = occupant.loc
+ if(istype(actual_loc, /obj/item/device/mmi))
+ var/obj/item/device/mmi/M = actual_loc
+ actual_loc = M.mecha
+ if(actual_loc != src) //something went wrong
occupant.clear_alert("charge")
occupant.clear_alert("mech damage")
RemoveActions(occupant, human_occupant=1)
@@ -859,57 +862,58 @@
else
return 0
-/obj/mecha/proc/mmi_move_inside(obj/item/device/mmi/mmi_as_oc,mob/user)
+/obj/mecha/proc/mmi_move_inside(obj/item/device/mmi/mmi_as_oc, mob/user)
if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client)
user << "Consciousness matrix not detected!"
- return 0
+ return FALSE
else if(mmi_as_oc.brainmob.stat)
user << "Beta-rhythm below acceptable level!"
- return 0
+ return FALSE
else if(occupant)
user << "Occupant detected!"
- return 0
- else if(dna_lock && (!mmi_as_oc.brainmob.stored_dna || dna_lock!=mmi_as_oc.brainmob.stored_dna.unique_enzymes))
+ return FALSE
+ else if(dna_lock && (!mmi_as_oc.brainmob.stored_dna || (dna_lock != mmi_as_oc.brainmob.stored_dna.unique_enzymes)))
user << "Access denied. [name] is secured with a DNA lock."
- return 0
+ return FALSE
visible_message("[user] starts to insert an MMI into [name].")
if(do_after(user, 40, target = src))
if(!occupant)
- return mmi_moved_inside(mmi_as_oc,user)
+ return mmi_moved_inside(mmi_as_oc, user)
else
user << "Occupant detected!"
else
user << "You stop inserting the MMI."
- return 0
+ return FALSE
-/obj/mecha/proc/mmi_moved_inside(obj/item/device/mmi/mmi_as_oc,mob/user)
- if(mmi_as_oc && user in range(1))
- if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client)
- user << "Consciousness matrix not detected!"
- return 0
- else if(mmi_as_oc.brainmob.stat)
- user << "Beta-rhythm below acceptable level!"
- return 0
- if(!user.transferItemToLoc(mmi_as_oc, src))
- user << "\the [mmi_as_oc] is stuck to your hand, you cannot put it in \the [src]!"
- return
- var/mob/brainmob = mmi_as_oc.brainmob
- occupant = brainmob
- brainmob.forceMove(src) //should allow relaymove
- brainmob.reset_perspective(src)
- brainmob.canmove = 1
- mmi_as_oc.mecha = src
- icon_state = initial(icon_state)
- setDir(dir_in)
- log_message("[mmi_as_oc] moved in as pilot.")
- if(!internal_damage)
- occupant << sound('sound/mecha/nominal.ogg',volume=50)
- GrantActions(brainmob)
- return 1
- else
- return 0
+/obj/mecha/proc/mmi_moved_inside(obj/item/device/mmi/mmi_as_oc, mob/user)
+ if(!(Adjacent(mmi_as_oc) && Adjacent(user)))
+ return FALSE
+ if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client)
+ user << "Consciousness matrix not detected!"
+ return FALSE
+ else if(mmi_as_oc.brainmob.stat)
+ user << "Beta-rhythm below acceptable level!"
+ return FALSE
+ if(!user.transferItemToLoc(mmi_as_oc, src))
+ user << "\the [mmi_as_oc] is stuck to your hand, you cannot put it in \the [src]!"
+ return FALSE
+ var/mob/brainmob = mmi_as_oc.brainmob
+ mmi_as_oc.mecha = src
+ occupant = brainmob
+ brainmob.forceMove(src) //should allow relaymove
+ brainmob.reset_perspective(src)
+ brainmob.remote_control = src
+ brainmob.update_canmove()
+ icon_state = initial(icon_state)
+ update_icon()
+ setDir(dir_in)
+ log_message("[mmi_as_oc] moved in as pilot.")
+ if(!internal_damage)
+ occupant << sound('sound/mecha/nominal.ogg',volume=50)
+ GrantActions(brainmob)
+ return TRUE
/obj/mecha/container_resist(mob/living/user)
go_out()
@@ -1046,4 +1050,4 @@ var/year_integer = text2num(year) // = 2013???
/obj/mecha/update_remote_sight(mob/living/user)
if(occupant_sight_flags)
if(user == occupant)
- user.sight |= occupant_sight_flags
+ user.sight |= occupant_sight_flags
\ No newline at end of file
diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm
index f8c4afd06b..e14c20ebf0 100644
--- a/code/game/mecha/working/ripley.dm
+++ b/code/game/mecha/working/ripley.dm
@@ -43,10 +43,6 @@
..()
update_icon()
-/obj/mecha/working/ripley/mmi_moved_inside(obj/item/device/mmi/mmi_as_oc,mob/user)
- ..()
- update_icon()
-
/obj/mecha/working/ripley/update_icon()
..()
if (hides)
@@ -178,4 +174,4 @@
cargo -= O
else
if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded.
- user << "You fail to push [O] out of [src]!"
+ user << "You fail to push [O] out of [src]!"
\ No newline at end of file
diff --git a/code/game/objects/effects/contraband.dm b/code/game/objects/effects/contraband.dm
index bf1ea9346e..13c2131517 100644
--- a/code/game/objects/effects/contraband.dm
+++ b/code/game/objects/effects/contraband.dm
@@ -104,9 +104,9 @@ list(name = "- Carbon Dioxide", desc = " This informational poster teaches the v
icon = 'icons/obj/contraband.dmi'
force = 0
resistance_flags = FLAMMABLE
- var/serial_number = 0
+ var/serial = 0
var/obj/structure/sign/poster/resulting_poster = null //The poster that will be created is initialised and stored through contraband/poster's constructor
- var/official = 0
+ var/rolled_official = 0
/obj/item/weapon/poster/contraband
@@ -118,20 +118,20 @@ list(name = "- Carbon Dioxide", desc = " This informational poster teaches the v
name = "motivational poster"
icon_state = "rolled_legit"
desc = "An official Nanotrasen-issued poster to foster a compliant and obedient workforce. It comes with state-of-the-art adhesive backing, for easy pinning to any vertical surface."
- official = 1
+ rolled_official = 1
/obj/item/weapon/poster/New(turf/loc, given_serial = 0)
if(given_serial == 0)
- if(!official)
- serial_number = rand(1, NUM_OF_POSTER_DESIGNS)
- resulting_poster = new(serial_number,official)
+ if(!rolled_official)
+ serial = rand(1, NUM_OF_POSTER_DESIGNS)
+ resulting_poster = new(serial,rolled_official)
else
- serial_number = rand(1, NUM_OF_POSTER_DESIGNS_LEGIT)
- resulting_poster = new(serial_number,official)
+ serial = rand(1, NUM_OF_POSTER_DESIGNS_LEGIT)
+ resulting_poster = new(serial,rolled_official)
else
- serial_number = given_serial
+ serial = given_serial
//We don't give it a resulting_poster because if we called it with a given_serial it means that we're rerolling an already used poster.
- name += " - No. [serial_number]"
+ name += " - No. [serial]"
..(loc)
@@ -182,8 +182,10 @@ list(name = "- Carbon Dioxide", desc = " This informational poster teaches the v
var/placespeed = 37 // don't change this, otherwise the animation will not sync to the progress bar
/obj/structure/sign/poster/New(serial,rolled_official)
- serial_number = serial
- official = rolled_official
+ if (!serial_number)
+ serial_number = serial
+ if(!official)
+ official = rolled_official
if(serial_number == loc)
if(!official)
serial_number = rand(1, NUM_OF_POSTER_DESIGNS) //This is for the mappers that want individual posters without having to use rolled posters.
@@ -259,7 +261,7 @@ list(name = "- Carbon Dioxide", desc = " This informational poster teaches the v
var/temp_loc = get_turf(user)
flick("poster_being_set",D)
D.loc = src
- D.official = P.official
+ D.official = P.rolled_official
qdel(P) //delete it now to cut down on sanity checks afterwards. Agouri's code supports rerolling it anyway
playsound(D.loc, 'sound/items/poster_being_created.ogg', 100, 1)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 8a26b20444..3efc7d82b2 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -234,7 +234,8 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s
var/obj/item/weapon/storage/S = loc
S.remove_from_storage(src, user.loc)
- throwing = 0
+ if(throwing)
+ throwing.finalize(FALSE)
if(loc == user)
if(!user.dropItemToGround(src))
return
@@ -255,7 +256,8 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s
var/obj/item/weapon/storage/S = loc
S.remove_from_storage(src, user.loc)
- throwing = 0
+ if(throwing)
+ throwing.finalize(FALSE)
if(loc == user)
if(!user.dropItemToGround(src))
return
diff --git a/code/game/objects/items/charter.dm b/code/game/objects/items/charter.dm
index bfe699ad33..ead1f9e820 100644
--- a/code/game/objects/items/charter.dm
+++ b/code/game/objects/items/charter.dm
@@ -1,3 +1,5 @@
+#define STATION_RENAME_TIME_LIMIT 3000
+
/obj/item/station_charter
name = "station charter"
icon = 'icons/obj/wizard.dmi'
@@ -33,7 +35,7 @@
if(used)
user << "This charter has already been used to name the station."
return
- if(!ignores_timeout && (world.time-round_start_time > CHALLENGE_TIME_LIMIT)) //5 minutes
+ if(!ignores_timeout && (world.time-round_start_time > STATION_RENAME_TIME_LIMIT)) //5 minutes
user << "The crew has already settled into the shift. \
It probably wouldn't be good to rename the station right now."
return
@@ -93,3 +95,5 @@
if(!unlimited_uses)
used = TRUE
+
+#undef STATION_RENAME_TIME_LIMIT
diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm
index 5cd509b69d..aa06cc380b 100644
--- a/code/game/objects/items/devices/radio/encryptionkey.dm
+++ b/code/game/objects/items/devices/radio/encryptionkey.dm
@@ -7,7 +7,6 @@
w_class = WEIGHT_CLASS_TINY
origin_tech = "engineering=2;bluespace=1"
var/translate_binary = 0
- var/translate_hive = 0
var/syndie = 0
var/centcom = 0
var/list/channels = list()
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index 0fabb5e70a..bdd0508aeb 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -273,9 +273,6 @@
if(keyslot2.translate_binary)
src.translate_binary = 1
- if(keyslot2.translate_hive)
- src.translate_hive = 1
-
if(keyslot2.syndie)
src.syndie = 1
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 4b90010de2..38c53ed8d6 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -17,7 +17,6 @@
var/broadcasting = 0
var/listening = 1
var/translate_binary = 0
- var/translate_hive = 0
var/freerange = 0 // 0 - Sanitize frequencies, 1 - Full range
var/list/channels = list() //see communications.dm for full list. First channes is a "default" for :h
var/obj/item/device/encryptionkey/keyslot //To allow the radio to accept encryption keys.
@@ -58,7 +57,6 @@
/obj/item/device/radio/proc/recalculateChannels()
channels = list()
translate_binary = 0
- translate_hive = 0
syndie = 0
centcom = 0
@@ -72,9 +70,6 @@
if(keyslot.translate_binary)
translate_binary = 1
- if(keyslot.translate_hive)
- translate_hive = 1
-
if(keyslot.syndie)
syndie = 1
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index dea7b94aa5..503ecba450 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -272,12 +272,17 @@
/obj/item/device/tape/attackby(obj/item/I, mob/user, params)
- if(ruined && istype(I, /obj/item/weapon/screwdriver))
- user << "You start winding the tape back in..."
- if(do_after(user, 120*I.toolspeed, target = src))
- user << "You wound the tape back in."
- fix()
-
+ if(ruined)
+ var/delay = -1
+ if (istype(I, /obj/item/weapon/screwdriver))
+ delay = 120*I.toolspeed
+ else if(istype(I, /obj/item/weapon/pen))
+ delay = 120*1.5
+ if (delay != -1)
+ user << "You start winding the tape back in..."
+ if(do_after(user, delay, target = src))
+ user << "You wound the tape back in."
+ fix()
//Random colour tapes
/obj/item/device/tape/random/New()
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 668e5ae7d3..763031cdd8 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -251,7 +251,7 @@
//get amount from user
var/min = 0
var/max = src.get_amount()
- var/stackmaterial = input(user,"How many sheets do you wish to take out of this stack? (Maximum [max]") as num
+ var/stackmaterial = round(input(user,"How many sheets do you wish to take out of this stack? (Maximum [max]") as num)
if(stackmaterial == null || stackmaterial <= min || stackmaterial >= src.get_amount())
return
else
diff --git a/code/game/objects/items/weapons/RPD.dm b/code/game/objects/items/weapons/RPD.dm
index 7f0b5671fd..baff623a2d 100644
--- a/code/game/objects/items/weapons/RPD.dm
+++ b/code/game/objects/items/weapons/RPD.dm
@@ -522,43 +522,39 @@ var/global/list/RPD_recipes=list(
if(!user.IsAdvancedToolUser() || istype(A,/turf/open/space/transit))
return ..()
+ //make sure what we're clicking is valid for the current mode
+ var/is_paintable = (p_class == PAINT_MODE && istype(A, /obj/machinery/atmospherics/pipe))
+ var/is_consumable = (p_class == EATING_MODE && (istype(A, /obj/item/pipe) || istype(A, /obj/item/pipe_meter) || istype(A, /obj/structure/disposalconstruct)))
+ var/can_make_pipe = ((p_class == ATMOS_MODE || p_class == METER_MODE || p_class == DISPOSALS_MODE) && isturf(A))
+
+ if(!is_paintable && !is_consumable && !can_make_pipe)
+ return ..()
+
//So that changing the menu settings doesn't affect the pipes already being built.
var/queued_p_type = p_type
var/queued_p_dir = p_dir
var/queued_p_flipped = p_flipped
. = FALSE
- switch(p_class)
- if(PAINT_MODE) // Paint pipes
- if(!istype(A,/obj/machinery/atmospherics/pipe))
- // Avoid spewing errors about invalid mode -2 when clicking on stuff that aren't pipes.
- user << "\The [src]'s error light flickers! Perhaps you need to only use it on pipes and pipe meters?"
- return
+ switch(p_class) //if we've gotten this var, the target is valid
+ if(PAINT_MODE) //Paint pipes
var/obj/machinery/atmospherics/pipe/P = A
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
P.add_atom_colour(paint_colors[paint_color], FIXED_COLOUR_PRIORITY)
P.pipe_color = paint_colors[paint_color]
user.visible_message("[user] paints \the [P] [paint_color].","You paint \the [P] [paint_color].")
- //P.update_icon()
P.update_node_icon()
return
- if(EATING_MODE) // Eating pipes
- // Must click on an actual pipe or meter.
- if(!(istype(A,/obj/item/pipe) || istype(A,/obj/item/pipe_meter) || istype(A,/obj/structure/disposalconstruct)))
- // Avoid spewing errors about invalid mode -1 when clicking on stuff that aren't pipes.
- user << "The [src]'s error light flickers! Perhaps you need to only use it on pipes and pipe meters?"
- return
- user << "You start destroying pipe..."
+
+ if(EATING_MODE) //Eating pipes
+ user << "You start destroying a pipe..."
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
if(do_after(user, 2, target = A))
activate()
qdel(A)
- if(ATMOS_MODE)
- if(!isturf(A))
- user << "The [src]'s error light flickers!"
- return
- user << "You start building pipes..."
+ if(ATMOS_MODE) //Making pipes
+ user << "You start building a pipe..."
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
if(do_after(user, 2, target = A))
activate()
@@ -567,21 +563,18 @@ var/global/list/RPD_recipes=list(
P.update()
P.add_fingerprint(usr)
- if(METER_MODE)
- if(!isturf(A))
- user << "The [src]'s error light flickers!"
- return 0
+ if(METER_MODE) //Making pipe meters
user << "You start building a meter..."
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
if(do_after(user, 2, target = A))
activate()
new /obj/item/pipe_meter(A)
- if(DISPOSALS_MODE)
- if(!isturf(A) || is_anchored_dense_turf(A))
- user << "The [src]'s error light flickers!"
+ if(DISPOSALS_MODE) //Making disposals pipes
+ if(!is_anchored_dense_turf(A))
+ user << "The [src]'s error light flickers; there's something in the way!"
return
- user << "You start building pipes..."
+ user << "You start building a disposals pipe..."
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
if(do_after(user, 20, target = A))
var/obj/structure/disposalconstruct/C = new (A, queued_p_type ,queued_p_dir)
diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm
index 5073aa33f9..d7207bd398 100644
--- a/code/game/objects/items/weapons/dice.dm
+++ b/code/game/objects/items/weapons/dice.dm
@@ -172,7 +172,7 @@
user.visible_message("[user] has thrown [src]. It lands on [result]. [comment]", \
"You throw [src]. It lands on [result]. [comment]", \
"You hear [src] rolling, it sounds like a [fake_result].")
- else if(src.throwing == 0) //Dice was thrown and is coming to rest
+ else if(!src.throwing) //Dice was thrown and is coming to rest
visible_message("[src] rolls to a stop, landing on [result]. [comment]")
/obj/item/weapon/dice/d4/Crossed(mob/living/carbon/human/H)
diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm
index 2c958efbd3..e91211f1b2 100644
--- a/code/game/objects/items/weapons/implants/implant.dm
+++ b/code/game/objects/items/weapons/implants/implant.dm
@@ -37,12 +37,11 @@
//What does the implant do upon injection?
//return 1 if the implant injects
-//return -1 if the implant fails to inject
-//return 0 if there is no room for implant
+//return 0 if there is no room for implant / it fails
/obj/item/weapon/implant/proc/implant(mob/living/target, mob/user, silent = 0)
LAZYINITLIST(target.implants)
if(!target.can_be_implanted() || !can_be_implanted_in(target))
- return -1
+ return 0
for(var/X in target.implants)
if(istype(X, type))
var/obj/item/weapon/implant/imp_e = X
diff --git a/code/game/objects/items/weapons/implants/implant_gang.dm b/code/game/objects/items/weapons/implants/implant_gang.dm
index 19d9adbe60..20a481171b 100644
--- a/code/game/objects/items/weapons/implants/implant_gang.dm
+++ b/code/game/objects/items/weapons/implants/implant_gang.dm
@@ -43,7 +43,7 @@
target.visible_message("[target] seems to resist the implant!", "You feel the influence of your enemies try to invade your mind!")
qdel(src)
- return -1
+ return 0
/obj/item/weapon/implanter/gang
name = "implanter (gang)"
diff --git a/code/game/objects/items/weapons/implants/implant_loyality.dm b/code/game/objects/items/weapons/implants/implant_loyality.dm
index daf085c6b8..619b19f1f7 100644
--- a/code/game/objects/items/weapons/implants/implant_loyality.dm
+++ b/code/game/objects/items/weapons/implants/implant_loyality.dm
@@ -24,14 +24,14 @@
target.visible_message("[target] seems to resist the implant!", "You feel something interfering with your mental conditioning, but you resist it!")
removed(target, 1)
qdel(src)
- return -1
+ return 0
if(target.mind in ticker.mode.get_gangsters())
ticker.mode.remove_gangster(target.mind)
if(!silent)
target.visible_message("[src] was destroyed in the process!", "You feel a sense of peace and security. You are now protected from brainwashing.")
removed(target, 1)
qdel(src)
- return -1
+ return 0
if(target.mind in ticker.mode.revolutionaries)
ticker.mode.remove_revolutionary(target.mind)
if(!silent)
diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm
index 4949d0d276..71216dcc3a 100644
--- a/code/game/objects/items/weapons/implants/implanter.dm
+++ b/code/game/objects/items/weapons/implants/implanter.dm
@@ -38,6 +38,8 @@
M.visible_message("[user] has implanted [M].", "[user] implants you.")
imp = null
update_icon()
+ else
+ user << "[src] fails to implant [M]."
/obj/item/weapon/implanter/attackby(obj/item/weapon/W, mob/user, params)
if(istype(W, /obj/item/weapon/pen))
diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm
index 0a929233c9..9bdcda7939 100644
--- a/code/game/objects/items/weapons/storage/boxes.dm
+++ b/code/game/objects/items/weapons/storage/boxes.dm
@@ -574,7 +574,6 @@
user.changeNext_move(CLICK_CD_MELEE)
playsound(loc, "rustle", 50, 1, -5)
user.visible_message("[user] hugs \the [src].","You hug \the [src].")
- return
/obj/item/weapon/storage/box/hug/medical/New()
..()
diff --git a/code/game/objects/items/weapons/storage/toolbox.dm b/code/game/objects/items/weapons/storage/toolbox.dm
index 4ee796006f..d97232ce79 100644
--- a/code/game/objects/items/weapons/storage/toolbox.dm
+++ b/code/game/objects/items/weapons/storage/toolbox.dm
@@ -34,6 +34,10 @@
new /obj/item/device/flashlight/flare(src)
new /obj/item/device/radio/off(src)
+/obj/item/weapon/storage/toolbox/emergency/old
+ name = "rusty red toolbox"
+ item_state = "toolbox_red_old"
+
/obj/item/weapon/storage/toolbox/mechanical
name = "mechanical toolbox"
icon_state = "blue"
@@ -48,6 +52,10 @@
new /obj/item/device/analyzer(src)
new /obj/item/weapon/wirecutters(src)
+/obj/item/weapon/storage/toolbox/mechanical/old
+ name = "rusty blue toolbox"
+ item_state = "toolbox_blue_old"
+
/obj/item/weapon/storage/toolbox/electrical
name = "electrical toolbox"
icon_state = "yellow"
diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm
index 1371818487..ea47fbb9df 100644
--- a/code/game/objects/items/weapons/storage/uplink_kits.dm
+++ b/code/game/objects/items/weapons/storage/uplink_kits.dm
@@ -306,3 +306,7 @@
..()
for(var/i in 1 to 3)
new/obj/item/weapon/grenade/chem_grenade/ez_clean(src)
+
+/obj/item/weapon/storage/box/hug/reverse_revolver/New()
+ ..()
+ new /obj/item/weapon/gun/ballistic/revolver/reverse(src)
diff --git a/code/game/objects/items/weapons/tanks/jetpack.dm b/code/game/objects/items/weapons/tanks/jetpack.dm
index 76a2df3f0c..8b6a1a946a 100644
--- a/code/game/objects/items/weapons/tanks/jetpack.dm
+++ b/code/game/objects/items/weapons/tanks/jetpack.dm
@@ -9,6 +9,7 @@
var/gas_type = "o2"
var/on = FALSE
var/stabilizers = FALSE
+ var/full_speed = TRUE // If the jetpack will have a speedboost in space/nograv or not
var/datum/effect_system/trail_follow/ion/ion_trail
/obj/item/weapon/tank/jetpack/New()
@@ -133,6 +134,7 @@
volume = 1
slot_flags = null
gas_type = null
+ full_speed = FALSE
var/datum/gas_mixture/temp_air_contents
var/obj/item/weapon/tank/internals/tank = null
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 37f5984f1f..ca48ec94bb 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -113,7 +113,7 @@
if(throwing) // you keep some momentum when getting out of a thrown closet
step(AM, dir)
if(throwing)
- throwing = 0
+ throwing.finalize(FALSE)
/obj/structure/closet/proc/take_contents()
var/turf/T = get_turf(src)
@@ -438,3 +438,7 @@
for(var/atom/A in contents)
A.ex_act(severity, target)
CHECK_TICK
+
+/obj/structure/closet/singularity_act()
+ dump_contents()
+ ..()
diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm
index 6ce6b6b63d..236043a3df 100644
--- a/code/game/objects/structures/musician.dm
+++ b/code/game/objects/structures/musician.dm
@@ -107,6 +107,15 @@
cur_acc[cur_note] = "#" // so shift is never required
else
cur_oct[cur_note] = text2num(ni)
+ if(user.dizziness > 0 && prob(user.dizziness / 2))
+ cur_note = Clamp(cur_note + rand(round(-user.dizziness / 10), round(user.dizziness / 10)), 1, 7)
+ if(user.dizziness > 0 && prob(user.dizziness / 5))
+ if(prob(30))
+ cur_acc[cur_note] = "#"
+ else if(prob(42))
+ cur_acc[cur_note] = "b"
+ else if(prob(75))
+ cur_acc[cur_note] = "n"
playnote(cur_note, cur_acc[cur_note], cur_oct[cur_note])
if(notes.len >= 2 && text2num(notes[2]))
sleep(sanitize_tempo(tempo / text2num(notes[2])))
diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm
index 5cd62b1381..2c8456f338 100644
--- a/code/game/turfs/closed.dm
+++ b/code/game/turfs/closed.dm
@@ -30,23 +30,20 @@
/turf/closed/indestructible/splashscreen
name = "Space Station 13"
icon = 'icons/misc/fullscreen.dmi'
- icon_state = "title1"
+ icon_state = "title"
layer = FLY_LAYER
+ var/titlescreen = TITLESCREEN
-/turf/closed/indestructible/splashscreen/New()
+/turf/closed/indestructible/splashscreen/Initialize()
..()
- icon_state = pick("title1","title2","title3","title4","title5")
+ if(titlescreen)
+ icon_state = titlescreen
/turf/closed/indestructible/riveted
icon = 'icons/turf/walls/riveted.dmi'
icon_state = "riveted"
smooth = SMOOTH_TRUE
-/turf/closed/indestructible/New()
- ..()
- if(smooth)
- queue_smooth(src)
-
/turf/closed/indestructible/riveted/uranium
icon = 'icons/turf/walls/uranium_wall.dmi'
icon_state = "uranium"
@@ -64,7 +61,7 @@
smooth = SMOOTH_TRUE
icon = 'icons/obj/smooth_structures/reinforced_window.dmi'
-/turf/closed/indestructible/fakeglass/New()
+/turf/closed/indestructible/fakeglass/Initialize()
..()
icon_state = null //set the icon state to null, so our base state isn't visible
var/image/I = image('icons/obj/structures.dmi', loc = src, icon_state = "grille")
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index df3b680b91..c30df6d1e0 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -29,22 +29,20 @@
baseturf = /turf/open/indestructible/necropolis
initial_gas_mix = "o2=14;n2=23;TEMP=300"
-/turf/open/indestructible/necropolis/New()
+/turf/open/indestructible/necropolis/Initialize()
..()
if(prob(12))
icon_state = "necro[rand(2,3)]"
+/turf/open/indestructible/necropolis/air
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
+
/turf/open/indestructible/hierophant
icon = 'icons/turf/floors/hierophant_floor.dmi'
initial_gas_mix = "o2=14;n2=23;TEMP=300"
baseturf = /turf/open/indestructible/hierophant
smooth = SMOOTH_TRUE
-/turf/open/indestructible/hierophant/New()
- ..()
- if(smooth)
- queue_smooth(src)
-
/turf/open/indestructible/hierophant/two
/turf/open/indestructible/paper
diff --git a/code/game/turfs/simulated/chasm.dm b/code/game/turfs/simulated/chasm.dm
index f1e71ff25d..2f478df8ba 100644
--- a/code/game/turfs/simulated/chasm.dm
+++ b/code/game/turfs/simulated/chasm.dm
@@ -69,7 +69,7 @@
L.adjustBruteLoss(30)
-/turf/open/chasm/straight_down/New()
+/turf/open/chasm/straight_down/Initialize()
..()
drop_x = x
drop_y = y
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index f478f1e27c..88d58314cb 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -33,7 +33,7 @@ var/list/icons_to_ignore_at_floor_init = list("damaged1","damaged2","damaged3","
var/list/broken_states
var/list/burnt_states
-/turf/open/floor/New()
+/turf/open/floor/Initialize(mapload)
if (!broken_states)
broken_states = list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5")
if (!burnt_states)
@@ -43,6 +43,8 @@ var/list/icons_to_ignore_at_floor_init = list("damaged1","damaged2","damaged3","
icon_regular_floor = "floor"
else
icon_regular_floor = icon_state
+ if(mapload)
+ MakeDirty()
/turf/open/floor/ex_act(severity, target)
var/shielded = is_shielded()
@@ -179,10 +181,5 @@ var/list/icons_to_ignore_at_floor_init = list("damaged1","damaged2","damaged3","
if(.)
ChangeTurf(/turf/open/floor/clockwork)
-/turf/open/floor/Initialize(mapload)
- ..()
- if(mapload)
- MakeDirty()
-
/turf/open/floor/acid_melt()
ChangeTurf(baseturf)
diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm
index 5b8482cc52..d303d8ac53 100644
--- a/code/game/turfs/simulated/floor/fancy_floor.dm
+++ b/code/game/turfs/simulated/floor/fancy_floor.dm
@@ -36,10 +36,9 @@
flags = NONE
var/ore_type = /obj/item/weapon/ore/glass
-/turf/open/floor/grass/New()
+/turf/open/floor/grass/Initialize()
..()
- spawn(1)
- update_icon()
+ update_icon()
/turf/open/floor/grass/attackby(obj/item/C, mob/user, params)
if(istype(C, /obj/item/weapon/shovel) && params)
@@ -76,7 +75,7 @@
initial_gas_mix = "o2=14;n2=23;TEMP=300"
slowdown = 0
-/turf/open/floor/grass/snow/basalt/New()
+/turf/open/floor/grass/snow/basalt/Initialize()
..()
if(prob(15))
icon_state = "basalt[rand(0, 12)]"
@@ -96,10 +95,9 @@
canSmoothWith = null
flags = NONE
-/turf/open/floor/carpet/New()
+/turf/open/floor/carpet/Initialize()
..()
- spawn(1)
- update_icon()
+ update_icon()
/turf/open/floor/carpet/update_icon()
if(!..())
@@ -131,6 +129,6 @@
broken_states = list("damaged")
plane = PLANE_SPACE
-/turf/open/floor/fakespace/New()
+/turf/open/floor/fakespace/Initialize()
..()
icon_state = "[rand(0,25)]"
diff --git a/code/game/turfs/simulated/floor/light_floor.dm b/code/game/turfs/simulated/floor/light_floor.dm
index 19a1357504..b078a220c4 100644
--- a/code/game/turfs/simulated/floor/light_floor.dm
+++ b/code/game/turfs/simulated/floor/light_floor.dm
@@ -12,7 +12,7 @@
var/can_modify_colour = TRUE
-/turf/open/floor/light/New()
+/turf/open/floor/light/Initialize()
..()
update_icon()
diff --git a/code/game/turfs/simulated/floor/mineral_floor.dm b/code/game/turfs/simulated/floor/mineral_floor.dm
index 73ffc696c8..64c6be6520 100644
--- a/code/game/turfs/simulated/floor/mineral_floor.dm
+++ b/code/game/turfs/simulated/floor/mineral_floor.dm
@@ -16,7 +16,7 @@
-/turf/open/floor/mineral/New()
+/turf/open/floor/mineral/Initialize()
broken_states = list("[initial(icon_state)]_dam")
..()
if (!icons)
@@ -221,7 +221,7 @@
floor_tile = /obj/item/stack/tile/mineral/abductor
icons = list("alienpod1", "alienpod2", "alienpod3", "alienpod4", "alienpod5", "alienpod6", "alienpod7", "alienpod8", "alienpod9")
-/turf/open/floor/mineral/abductor/New()
+/turf/open/floor/mineral/abductor/Initialize()
..()
icon_state = "alienpod[rand(1,9)]"
diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm
index 2d9cd76f4a..82eb9c7bd7 100644
--- a/code/game/turfs/simulated/floor/misc_floor.dm
+++ b/code/game/turfs/simulated/floor/misc_floor.dm
@@ -13,9 +13,9 @@
icon_state = "bcircuit"
floor_tile = /obj/item/stack/tile/plasteel
-/turf/open/floor/bluegrid/New()
- ..()
+/turf/open/floor/bluegrid/Initialize()
SSmapping.nuke_tiles += src
+ ..()
/turf/open/floor/bluegrid/Destroy()
SSmapping.nuke_tiles -= src
@@ -67,7 +67,7 @@
icon_state = "plating"
var/obj/effect/clockwork/overlay/floor/realappearence
-/turf/open/floor/clockwork/New()
+/turf/open/floor/clockwork/Initialize()
..()
new /obj/effect/overlay/temp/ratvar/floor(src)
new /obj/effect/overlay/temp/ratvar/beam(src)
diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm
index de9cabe70b..c65865786c 100644
--- a/code/game/turfs/simulated/floor/plating.dm
+++ b/code/game/turfs/simulated/floor/plating.dm
@@ -13,7 +13,7 @@
icon_state = "plating"
intact = 0
-/turf/open/floor/plating/New()
+/turf/open/floor/plating/Initialize()
if (!broken_states)
broken_states = list("platingdmg1", "platingdmg2", "platingdmg3")
if (!burnt_states)
diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm
index 272e3a68e1..9cc15172f9 100644
--- a/code/game/turfs/simulated/floor/plating/asteroid.dm
+++ b/code/game/turfs/simulated/floor/plating/asteroid.dm
@@ -15,7 +15,7 @@
var/sand_type = /obj/item/weapon/ore/glass
var/floor_variance = 20 //probability floor has a different icon state
-/turf/open/floor/plating/asteroid/New()
+/turf/open/floor/plating/asteroid/Initialize()
var/proper_name = name
..()
name = proper_name
@@ -117,7 +117,7 @@
/turf/open/floor/plating/asteroid/basalt/airless
initial_gas_mix = "TEMP=2.7"
-/turf/open/floor/plating/asteroid/basalt/New()
+/turf/open/floor/plating/asteroid/basalt/Initialize()
..()
switch(icon_state)
if("basalt1", "basalt2", "basalt3") //5 and 9 are too dark to glow and make the amount of glows in tunnels too high
@@ -176,7 +176,7 @@
/turf/open/floor/plating/asteroid/airless/cave/volcanic/has_data //subtype for producing a tunnel with given data
has_data = TRUE
-/turf/open/floor/plating/asteroid/airless/cave/New(loc)
+/turf/open/floor/plating/asteroid/airless/cave/Initialize()
if (!mob_spawn_list)
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/goldgrub = 1, /mob/living/simple_animal/hostile/asteroid/goliath = 5, /mob/living/simple_animal/hostile/asteroid/basilisk = 4, /mob/living/simple_animal/hostile/asteroid/hivelord = 3)
if (!megafauna_spawn_list)
@@ -186,7 +186,8 @@
if(!has_data)
produce_tunnel_from_data()
- ..()
+ else
+ ..() //do not continue after changeturfing or we will do a double initialize
/turf/open/floor/plating/asteroid/airless/cave/proc/get_cave_data(set_length, exclude_dir = -1)
// If set_length (arg1) isn't defined, get a random length; otherwise assign our length to the length arg.
diff --git a/code/game/turfs/simulated/floor/plating/lava.dm b/code/game/turfs/simulated/floor/plating/lava.dm
index 68aa66a1c3..4b52420394 100644
--- a/code/game/turfs/simulated/floor/plating/lava.dm
+++ b/code/game/turfs/simulated/floor/plating/lava.dm
@@ -7,12 +7,6 @@
baseturf = /turf/open/floor/plating/lava //lava all the way down
slowdown = 2
luminosity = 1
- var/static/list/safeties_typecache = list(/obj/structure/lattice/catwalk)
- //if anything matching this typecache is found in the lava, we don't burn things
-
-/turf/open/floor/plating/lava/New()
- ..()
- safeties_typecache = typecacheof(safeties_typecache)
/turf/open/floor/plating/lava/ex_act()
return
@@ -51,7 +45,9 @@
/turf/open/floor/plating/lava/proc/is_safe()
- var/list/found_safeties = typecache_filter_list(contents, safeties_typecache)
+ //if anything matching this typecache is found in the lava, we don't burn things
+ var/static/list/lava_safeties_typecache = typecacheof(list(/obj/structure/lattice/catwalk))
+ var/list/found_safeties = typecache_filter_list(contents, lava_safeties_typecache)
return LAZYLEN(found_safeties)
diff --git a/code/game/turfs/simulated/floor/plating/misc_plating.dm b/code/game/turfs/simulated/floor/plating/misc_plating.dm
index 730cc7b0ab..081b4becc6 100644
--- a/code/game/turfs/simulated/floor/plating/misc_plating.dm
+++ b/code/game/turfs/simulated/floor/plating/misc_plating.dm
@@ -7,7 +7,7 @@
name = "alien floor"
icon_state = "alienpod1"
-/turf/open/floor/plating/abductor/New()
+/turf/open/floor/plating/abductor/Initialize()
..()
icon_state = "alienpod[rand(1,9)]"
@@ -41,7 +41,7 @@
initial_gas_mix = "o2=14;n2=23;TEMP=300"
planetary_atmos = TRUE
-/turf/open/floor/plating/ashplanet/New()
+/turf/open/floor/plating/ashplanet/Initialize()
if(smooth)
pixel_y = -4
pixel_x = -4
@@ -72,7 +72,7 @@
icon_state = "wateryrock"
slowdown = 2
-/turf/open/floor/plating/ashplanet/wateryrock/New()
+/turf/open/floor/plating/ashplanet/wateryrock/Initialize()
icon_state = "[icon_state][rand(1, 9)]"
..()
@@ -113,7 +113,7 @@
name = "iron sand"
desc = "Like sand, but more metal."
-/turf/open/floor/plating/ironsand/New()
+/turf/open/floor/plating/ironsand/Initialize()
..()
icon_state = "ironsand[rand(1,15)]"
diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm
index 8ee346905d..ab01971446 100644
--- a/code/game/turfs/simulated/floor/reinf_floor.dm
+++ b/code/game/turfs/simulated/floor/reinf_floor.dm
@@ -106,7 +106,7 @@
icon_state = "plating"
var/obj/effect/clockwork/overlay/floor/bloodcult/realappearence
-/turf/open/floor/engine/cult/New()
+/turf/open/floor/engine/cult/Initialize()
..()
new /obj/effect/overlay/temp/cult/turf/floor(src)
realappearence = new /obj/effect/clockwork/overlay/floor/bloodcult(src)
diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm
index b15607f5b6..0883c19491 100644
--- a/code/game/turfs/simulated/minerals.dm
+++ b/code/game/turfs/simulated/minerals.dm
@@ -24,7 +24,7 @@
var/scan_state = null //Holder for the image we display when we're pinged by a mining scanner
var/defer_change = 0
-/turf/closed/mineral/New()
+/turf/closed/mineral/Initialize()
if (!canSmoothWith)
canSmoothWith = list(/turf/closed)
pixel_y = -4
@@ -139,7 +139,7 @@
var/mineralChance = 13
var/display_icon_state = "rock"
-/turf/closed/mineral/random/New()
+/turf/closed/mineral/random/Initialize()
if (!mineralSpawnChanceList)
mineralSpawnChanceList = list(
/turf/closed/mineral/uranium = 5, /turf/closed/mineral/diamond = 1, /turf/closed/mineral/gold = 10,
@@ -385,7 +385,7 @@
var/activated_name = null
var/activated_image = null
-/turf/closed/mineral/gibtonite/New()
+/turf/closed/mineral/gibtonite/Initialize()
det_time = rand(8,10) //So you don't know exactly when the hot potato will explode
..()
diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm
index ce0b8a6107..a2828271a9 100644
--- a/code/game/turfs/simulated/wall/misc_walls.dm
+++ b/code/game/turfs/simulated/wall/misc_walls.dm
@@ -8,7 +8,7 @@
sheet_amount = 1
girder_type = /obj/structure/girder/cult
-/turf/closed/wall/mineral/cult/New()
+/turf/closed/wall/mineral/cult/Initialize()
new /obj/effect/overlay/temp/cult/turf(src)
..()
@@ -50,7 +50,7 @@
var/obj/effect/clockwork/overlay/wall/realappearence
var/obj/structure/destructible/clockwork/cache/linkedcache
-/turf/closed/wall/clockwork/New()
+/turf/closed/wall/clockwork/Initialize()
..()
new /obj/effect/overlay/temp/ratvar/wall(src)
new /obj/effect/overlay/temp/ratvar/beam(src)
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index f922ba7dce..c0190a0fb2 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -15,15 +15,16 @@
var/global/datum/gas_mixture/space/space_gas = new
plane = PLANE_SPACE
-/turf/open/space/New()
+/turf/open/space/Initialize()
icon_state = SPACE_ICON_STATE
air = space_gas
+
+ if(initialized)
+ stack_trace("Warning: [src]([type]) initialized multiple times!")
+ initialized = TRUE
-/turf/open/space/Destroy(force)
- if(force)
- . = ..()
- else
- return QDEL_HINT_LETMELIVE
+ if(requires_activation)
+ SSair.add_to_active(src)
/turf/open/space/attack_ghost(mob/dead/observer/user)
if(destination_z)
diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm
index 11e66e1680..dd772aa1ac 100644
--- a/code/game/turfs/space/transit.dm
+++ b/code/game/turfs/space/transit.dm
@@ -61,14 +61,12 @@
/turf/open/space/transit/attackby()
return
-/turf/open/space/transit/New()
+/turf/open/space/transit/Initialize()
..()
update_icon()
for(var/atom/movable/AM in src)
throw_atom(AM)
-
-
/turf/open/space/transit/proc/update_icon()
var/p = 9
var/angle = 0
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 15c72dd107..640095ae48 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -23,14 +23,17 @@
var/explosion_id = 0
var/list/decals
+ var/requires_activation //add to air processing after initialize?
/turf/SDQL_update(const/var_name, new_value)
if(var_name == "x" || var_name == "y" || var_name == "z")
return FALSE
. = ..()
-/turf/New()
- ..()
+/turf/Initialize()
+ if(initialized)
+ stack_trace("Warning: [src]([type]) initialized multiple times!")
+ initialized = TRUE
levelupdate()
if(smooth)
@@ -40,11 +43,17 @@
for(var/atom/movable/AM in src)
Entered(AM)
+ if(requires_activation)
+ CalculateAdjacentTurfs()
+ SSair.add_to_active(src)
+
/turf/proc/Initalize_Atmos(times_fired)
CalculateAdjacentTurfs()
/turf/Destroy()
visibilityChanged()
+ initialized = FALSE
+ requires_activation = FALSE
..()
return QDEL_HINT_HARDDEL_NOW
@@ -454,4 +463,4 @@
/turf/proc/remove_decal(group)
LAZYINITLIST(decals)
overlays -= decals[group]
- decals[group] = null
\ No newline at end of file
+ decals[group] = null
diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm
index ee9b3f26c5..0405adb1cd 100644
--- a/code/modules/admin/fun_balloon.dm
+++ b/code/modules/admin/fun_balloon.dm
@@ -100,44 +100,6 @@
qdel(src)
-//Luxury Shuttle Blockers
-
-/obj/effect/forcefield/luxury_shuttle
- var/threshhold = 500
- var/list/approved_passengers = list()
-
-/obj/effect/forcefield/luxury_shuttle/CanPass(atom/movable/mover, turf/target, height=0)
- if(mover in approved_passengers)
- return 1
-
- if(!isliving(mover)) //No stowaways
- return 0
-
- var/total_cash = 0
- var/list/counted_money = list()
-
- for(var/obj/item/weapon/coin/C in mover)
- total_cash += C.value
- counted_money += C
- if(total_cash >= threshhold)
- break
- for(var/obj/item/stack/spacecash/S in mover)
- total_cash += S.value * S.amount
- counted_money += S
- if(total_cash >= threshhold)
- break
-
- if(total_cash >= threshhold)
- for(var/obj/I in counted_money)
- qdel(I)
-
- mover << "Thank you for your payment! Please enjoy your flight."
- approved_passengers += mover
- return 1
- else
- mover << "You don't have enough money to enter the main shuttle. You'll have to fly coach."
- return 0
-
//Shuttle Build
/obj/effect/shuttle_build
@@ -149,4 +111,69 @@
/obj/effect/shuttle_build/New()
SSshuttle.emergency.dock(SSshuttle.getDock("emergency_home"))
- qdel(src)
\ No newline at end of file
+ qdel(src)
+
+//Arena
+
+/obj/effect/forcefield/arena_shuttle
+ name = "portal"
+ var/list/warp_points = list()
+
+
+/obj/effect/forcefield/arena_shuttle/Bumped(mob/M as mob|obj)
+ if(!warp_points.len)
+ warp_points = get_area_turfs(/area/shuttle/escape)
+ for(var/turf/T in warp_points)
+ for(var/atom/movable/AM in T)
+ if(AM.density && AM.anchored)
+ warp_points -= T
+ break
+ if(!isliving(M))
+ return
+ else
+ var/mob/living/L = M
+ if(L.pulling && istype(L.pulling, /obj/item/bodypart/head))
+ L << "Your offering is accepted. You may pass."
+ qdel(L.pulling)
+ var/turf/LA = pick(warp_points)
+ L.forceMove(LA)
+ L.hallucination = 0
+ L << "The battle is won. Your bloodlust subsides."
+ for(var/obj/item/weapon/twohanded/required/chainsaw/doomslayer/chainsaw in L)
+ qdel(chainsaw)
+ else
+ L << "You are not yet worthy of passing. Drag a severed head to the barrier to be allowed entry to the hall of champions."
+
+/obj/effect/landmark/shuttle_arena_safe
+ name = "hall of champions"
+ desc = "For the winners."
+
+/obj/effect/landmark/shuttle_arena_entrance
+ name = "the arena"
+ desc = "A lava filled battlefield."
+
+
+/obj/effect/forcefield/arena_shuttle_entrance
+ name = "portal"
+ var/list/warp_points = list()
+
+/obj/effect/forcefield/arena_shuttle_entrance/Bumped(mob/M as mob|obj)
+ if(!warp_points.len)
+ for(var/obj/effect/landmark/shuttle_arena_entrance/S in landmarks_list)
+ warp_points |= S
+ if(!isliving(M))
+ return
+
+ var/obj/effect/landmark/LA = pick(warp_points)
+
+ M.forceMove(get_turf(LA))
+ M << "You're trapped in a deadly arena! To escape, you'll need to drag a severed head to the escape portals."
+ spawn()
+ var/obj/effect/mine/pickup/bloodbath/B = new(M)
+ B.mineEffect(M)
+
+
+/area/shuttle_arena
+ name = "arena"
+ has_gravity = 1
+ requires_power = 0
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index 4320efd9b9..d987c30728 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -337,10 +337,40 @@
dat += "Time limit: [config.midround_antag_time_check] minutes into round
"
dat += "Living crew limit: [config.midround_antag_life_check * 100]% of crew alive
"
dat += "If limits past: [ticker.mode.round_ends_with_antag_death ? "End The Round" : "Continue As Extended"]
"
-
- dat += "
"
dat += "End Round Now
"
- dat += "[ticker.delay_end ? "End Round Normally" : "Delay Round End"]
"
+ dat += "[ticker.delay_end ? "End Round Normally" : "Delay Round End"]"
+ var/connected_players = clients.len
+ var/lobby_players = 0
+ var/observers = 0
+ var/observers_connected = 0
+ var/living_players = 0
+ var/living_players_connected = 0
+ var/living_players_antagonist = 0
+ var/other_players = 0
+ for(var/mob/M in mob_list)
+ if(M.ckey)
+ if(isnewplayer(M))
+ lobby_players++
+ continue
+ else if(M.stat != DEAD && M.mind && !isbrain(M))
+ living_players++
+ if(M.mind.special_role)
+ living_players_antagonist++
+ if(M.client)
+ living_players_connected++
+ else if((M.stat == DEAD )||(isobserver(M)))
+ observers++
+ if(M.client)
+ observers_connected++
+ else
+ other_players++
+ dat += "
Players:|[connected_players - lobby_players] ingame|[connected_players] connected|[lobby_players] lobby|"
+ dat += "
Living Players:|[living_players_connected] active|[living_players - living_players_connected] disconnected|[living_players_antagonist] antagonists|"
+ dat += "
Dead/Observing players:|[observers_connected] active|[observers - observers_connected] disconnected|"
+ if(other_players)
+ dat += "
[other_players] players in invalid state or the statistics code is bugged!"
+ dat += "
"
+
if(ticker.mode.syndicates.len)
dat += "
| Syndicates | |
"
for(var/datum/mind/N in ticker.mode.syndicates)
diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm
index 15732e6218..aa71596b10 100644
--- a/code/modules/admin/sql_message_system.dm
+++ b/code/modules/admin/sql_message_system.dm
@@ -35,8 +35,8 @@
if(!timestamp)
timestamp = SQLtime()
if(!server)
- if (config && config.server_name)
- server = config.server_name
+ if (config && config.server_sql_name)
+ server = config.server_sql_name
server = sanitizeSQL(server)
if(isnull(secret))
switch(alert("Hide note from being viewed by players?", "Secret note?","Yes","No","Cancel"))
@@ -332,7 +332,7 @@ proc/get_message_output(type, target_ckey)
return
if("watchlist entry")
message_admins("Notice: [key_name_admin(target_ckey)] is on the watchlist and has just connected - Reason: [text]")
- // send2irc_adminless_only("Watchlist", "[key_name(target_ckey)] is on the watchlist and has just connected - Reason: [text]")
+ send2irc_adminless_only("Watchlist", "[key_name(target_ckey)] is on the watchlist and has just connected - Reason: [text]")
if("memo")
output += "Memo by [admin_ckey] on [timestamp]"
if(editor_ckey)
@@ -352,8 +352,8 @@ proc/get_message_output(type, target_ckey)
var/notetext
notesfile >> notetext
var/server
- if(config && config.server_name)
- server = config.server_name
+ if(config && config.server_sql_name)
+ server = config.server_sql_name
var/regex/note = new("^(\\d{2}-\\w{3}-\\d{4}) \\| (.+) ~(\\w+)$", "i")
note.Find(notetext)
var/timestamp = note.group[1]
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index 1ebe4e4fd1..9717beb688 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -1,4 +1,4 @@
-/proc/keywords_lookup(msg)
+/proc/keywords_lookup(msg,irc)
//This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE!
var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as", "i")
@@ -10,9 +10,11 @@
var/list/surnames = list()
var/list/forenames = list()
var/list/ckeys = list()
+ var/founds = ""
for(var/mob/M in mob_list)
var/list/indexing = list(M.real_name, M.name)
- if(M.mind) indexing += M.mind.name
+ if(M.mind)
+ indexing += M.mind.name
for(var/string in indexing)
var/list/L = splittext(string, " ")
@@ -52,9 +54,19 @@
mobs_found += found
if(!ai_found && isAI(found))
ai_found = 1
- msg += "[original_word](?|F) "
+ var/is_antag = 0
+ if(found.mind && found.mind.special_role)
+ is_antag = 1
+ founds += "Name: [found.name]([found.real_name]) Ckey: [found.ckey] [is_antag ? "(Antag)" : null] "
+ msg += "[original_word](?|F) "
continue
msg += "[original_word] "
+ if(irc)
+ if(founds == "")
+ return "Search Failed"
+ else
+ return founds
+
return msg
@@ -78,7 +90,20 @@
return
if(src.handle_spam_prevention(msg,MUTE_ADMINHELP))
return
- var/ref_mob = "\ref[mob]"
+
+
+ //clean the input msg
+ if(!msg)
+ return
+ msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
+ if(!msg) return
+ var/original_msg = msg
+
+ msg = keywords_lookup(msg)
+
+ if(!mob)
+ return //this doesn't happen
+
var/ref_client = "\ref[src]"
for(var/datum/adminticket/T in admintickets)
if(T.permckey == src.ckey && T.resolved == "No")
@@ -87,7 +112,7 @@
if(T.admin == "N/A")
usr << "Due to the fact your Adminhelp had no assigned admin, admins have been pinged."
message_admins("[src.ckey] has bumped their adminhelp #[T.ID], still no assigned admin!")
- msg = "HELP: [key_name(src)] [ADMIN_QUE(mob)] [ADMIN_PP(mob)] [ADMIN_VV(mob)] [ADMIN_SM(mob)] [ADMIN_FLW(mob)] [ADMIN_TP(mob)] (REJT) (IC) (R): [msg]"
+ msg = "HELP: [key_name(src)] [ADMIN_QUE(mob)] [ADMIN_PP(mob)] [ADMIN_VV(mob)] [ADMIN_SM(mob)] [ADMIN_FLW(mob)] [ADMIN_TP(mob)] (REJT) (IC) (R): [msg]"
for(var/client/X in admins)
if(X.prefs.toggles & SOUND_ADMINHELP)
X << 'sound/effects/adminhelp.ogg'
@@ -104,27 +129,10 @@
src.verbs -= /client/verb/adminhelp
adminhelptimerid = addtimer(CALLBACK(src, .proc/giveadminhelpverb), 1200, TIMER_STOPPABLE)
- //clean the input msg
- if(!msg) return
- msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
- if(!msg) return
- var/original_msg = msg
-
- msg = keywords_lookup(msg)
-
- if(!mob) return //this doesn't happen
+ for(var/datum/adminticket/T in admintickets)
+ msg = "HELP: [key_name(src)] [ADMIN_QUE(mob)] [ADMIN_PP(mob)] [ADMIN_VV(mob)] [ADMIN_SM(mob)] [ADMIN_FLW(mob)] [ADMIN_TP(mob)] (REJT) (IC) (R): [msg]"
createticket(src, msg, src.ckey, mob)
-
- var/datum/adminticket/ticket
-
- for(var/datum/adminticket/T in admintickets)
- if(T.permckey == src.ckey)
- ticket = T
-
- msg = "ADMINHELP: [key_name(src)] (?) (PP) (VV) (SM) (TP) (FLW) (R): [msg]"
-
-
//send this msg to all admins
for(var/client/X in admins)
@@ -138,88 +146,72 @@
src << "PM to-Admins: [original_msg]"
//send it to irc if nobody is on and tell us how many were on
- var/admin_number_present = send2irc_admin_notice_handler("adminhelp", ckey, original_msg)
- log_admin("ADMINHELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins who have +BAN.")
+ var/admin_number_present = send2admindiscord(ckey,original_msg)
+ log_admin("HELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins who have +BAN.")
+ if(admin_number_present <= 0)
+ src << "No active admins are online, your adminhelp was sent to the admin irc."
feedback_add_details("admin_verb","AH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return
-/proc/calculate_admins(type, requiredflags = R_BAN)
- var/admin_number_total = 0 //Total number of admins
- var/admin_number_afk = 0 //Holds the number of admins who are afk
- var/admin_number_ignored = 0 //Holds the number of admins without +BAN (so admins who are not really admins)
- var/admin_number_decrease = 0 //Holds the number of admins with are afk, ignored or both
+/proc/get_admin_counts(requiredflags = R_BAN)
+ . = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list())
for(var/client/X in admins)
- admin_number_total++;
- var/invalid = 0
+ .["total"] += X
if(requiredflags != 0 && !check_rights_for(X, requiredflags))
- admin_number_ignored++
- invalid = 1
- if(X.is_afk())
- admin_number_afk++
- invalid = 1
- if(X.holder.fakekey)
- admin_number_ignored++
- invalid = 1
- if(invalid)
- admin_number_decrease++
- switch(type)
- if("ignored")
- return admin_number_ignored
- if("total")
- return admin_number_total
- if("away")
- return admin_number_afk
- if("present")
- return admin_number_total - admin_number_decrease
- return 0
+ .["noflags"] += X
+ else if(X.is_afk())
+ .["afk"] += X
+ else if(X.holder.fakekey)
+ .["stealth"] += X
+ else
+ .["present"] += X
+/proc/send2irc_adminless_only(source, msg, requiredflags = R_BAN)
+ var/list/adm = get_admin_counts(requiredflags)
+ var/list/activemins = adm["present"]
+ . = activemins.len
+ if(. <= 0)
+ var/final = ""
+ var/list/afkmins = adm["afk"]
+ var/list/stealthmins = adm["stealth"]
+ var/list/powerlessmins = adm["noflags"]
+ var/list/allmins = adm["total"]
+ if(!afkmins.len && !stealthmins.len && !powerlessmins.len)
+ final = "[msg] - No admins online"
+ else
+ final = "[msg] - All admins stealthed\[[english_list(stealthmins)]\], AFK\[[english_list(afkmins)]\], or lacks +BAN\[[english_list(powerlessmins)]\]! Total: [allmins.len] "
+ send2irc(source,final)
+ send2admindiscord(source,final)
-/proc/send2irc_admin_notice_handler(type, source, msg)
- var/afk_admins = calculate_admins("away")
- var/total_admins = calculate_admins("total")
- var/ignored_admins = calculate_admins("ignored")
- var/admin_number_present = calculate_admins("present") //Number of admins who are neither afk nor invalid
- var/irc_message_afk = "[msg] - All admins AFK ([afk_admins]/[total_admins]) or skipped ([ignored_admins]/[total_admins])"
- var/irc_message_normal = "[msg] - heard by [admin_number_present] non-AFK admins who have +BAN."
- var/irc_message_adminless = "[msg] - No admins online"
-
- switch(type)
- if("adminhelp")
- if(config.announce_adminhelps)
- send2irc(source, irc_message_normal)
- else
- if(admin_number_present <= 0)
- if(!afk_admins && !ignored_admins)
- send2admindiscord(source, irc_message_adminless)
- else if(afk_admins >= 1)
- send2admindiscord(source, irc_message_afk)
- else
- send2admindiscord(source, irc_message_normal)
- if("watchlist")
- if(config.announce_watchlist)
- send2irc(source, irc_message_normal)
- else
- if(admin_number_present <= 0)
- if(!afk_admins && !ignored_admins)
- send2admindiscord(source, irc_message_adminless)
- else if(afk_admins >= 1)
- send2admindiscord(source, irc_message_afk)
- else
- send2admindiscord(source, irc_message_normal)
- if("new_player")
- if(config.irc_first_connection_alert)
- send2irc(source, irc_message_normal)
- else
- if(admin_number_present <= 0)
- if(!afk_admins && !ignored_admins)
- send2admindiscord(source, irc_message_adminless)
- else if(afk_admins >= 1)
- send2admindiscord(source, irc_message_afk)
- else
- send2admindiscord(source, irc_message_normal)
- return admin_number_present
/proc/send2irc(msg,msg2)
if(config.useircbot)
- shell("python nudge.py [msg] \"[msg2]\"")
- return
\ No newline at end of file
+ shell("python nudge.py [msg] [msg2]")
+ return
+
+/proc/send2otherserver(source,msg,type = "Ahelp")
+ if(global.cross_allowed)
+ var/list/message = list()
+ message["message_sender"] = source
+ message["message"] = msg
+ message["source"] = "([config.cross_name])"
+ message["key"] = global.comms_key
+ message["crossmessage"] = type
+
+ world.Export("[global.cross_address]?[list2params(message)]")
+
+
+/proc/ircadminwho()
+ var/list/message = list("Admins: ")
+ var/list/admin_keys = list()
+ for(var/adm in admins)
+ var/client/C = adm
+ admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]"
+
+ for(var/admin in admin_keys)
+ if(LAZYLEN(admin_keys) > 1)
+ message += ", [admin]"
+ else
+ message += "[admin]"
+
+ return jointext(message, "")
\ No newline at end of file
diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm
index 2e845e9c16..e6134d0c83 100644
--- a/code/modules/admin/verbs/adminpm.dm
+++ b/code/modules/admin/verbs/adminpm.dm
@@ -1,3 +1,5 @@
+#define IRCREPLYCOUNT 2
+
//allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm
/client/proc/cmd_admin_pm_context(mob/M in mob_list)
set category = null
@@ -5,7 +7,8 @@
if(!holder)
src << "Error: Admin-PM-Context: Only administrators may use this command."
return
- if( !ismob(M) || !M.client ) return
+ if( !ismob(M) || !M.client )
+ return
cmd_admin_pm(M.client,null)
feedback_add_details("admin_verb","APMM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -19,16 +22,15 @@
var/list/client/targets[0]
for(var/client/T)
if(T.mob)
- if(istype(T.mob, /mob/new_player))
+ if(isnewplayer(T.mob))
targets["(New Player) - [T]"] = T
- else if(istype(T.mob, /mob/dead/observer))
+ else if(isobserver(T.mob))
targets["[T.mob.name](Ghost) - [T]"] = T
else
targets["[T.mob.real_name](as [T.mob.name]) - [T]"] = T
else
targets["(No Mob) - [T]"] = T
- var/list/sorted = sortList(targets)
- var/target = input(src,"To whom shall we send a message?","Admin PM",null) in sorted|null
+ var/target = input(src,"To whom shall we send a message?","Admin PM",null) as null|anything in sortList(targets)
cmd_admin_pm(targets[target],null)
feedback_add_details("admin_verb","APM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -44,7 +46,8 @@
else if(istype(whom,/client))
C = whom
if(!C)
- if(holder) src << "Error: Admin-PM: Client not found."
+ if(holder)
+ src << "Error: Admin-PM: Client not found."
return
var/datum/adminticket/ticket
@@ -205,4 +208,51 @@
//we don't use message_admins here because the sender/receiver might get it too
for(var/client/X in admins)
if(X.key!=key && X.key!=C.key) //check client/X is an admin and isn't the sender or recipient
- X << "PM: [key_name(src, X, 0)]->[key_name(C, X, 0)]: \blue [keywordparsedmsg]" //inform X
\ No newline at end of file
+ X << "PM: [key_name(src, X, 0)]->[key_name(C, X, 0)]: \blue [keywordparsedmsg]" //inform X
+
+/proc/IrcPm(target,msg,sender)
+
+ var/client/C = directory[target]
+
+ var/static/stealthkey
+ var/adminname = config.showircname ? "[sender](IRC)" : "Administrator"
+
+ if(!C)
+ return "No client"
+
+ if(!stealthkey)
+ stealthkey = GenIrcStealthKey()
+
+ msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
+ if(!msg)
+ return "No message"
+
+ message_admins("IRC message from [sender] to [key_name_admin(C)] : [msg]")
+ log_admin("IRC PM: [sender] -> [key_name(C)] : [msg]")
+ msg = emoji_parse(msg)
+
+ C << "-- Administrator private message --"
+ C << "Admin PM from-[adminname]: [msg]"
+ C << "Click on the administrator's name to reply."
+ window_flash(C)
+ //always play non-admin recipients the adminhelp sound
+ C << 'sound/effects/adminhelp.ogg'
+
+ C.ircreplyamount = IRCREPLYCOUNT
+
+ return "Message Successful"
+
+/proc/GenIrcStealthKey()
+ var/num = (rand(0,1000))
+ var/i = 0
+ while(i == 0)
+ i = 1
+ for(var/P in stealthminID)
+ if(num == stealthminID[P])
+ num++
+ i = 0
+ var/stealth = "@[num2text(num)]"
+ stealthminID["IRCKEY"] = stealth
+ return stealth
+
+#undef IRCREPLYCOUNT
\ No newline at end of file
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index cfe320c407..b767248455 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -118,16 +118,19 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
if(isnull(argnum))
return
- var/list/lst = list()
-
+ . = list()
+ var/list/named_args = list()
while(argnum--)
+ var/named_arg = input("Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument") as text|null
var/value = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
if (!value["class"])
return
- lst += value["value"]
-
- return lst
-
+ if(named_arg)
+ named_args[named_arg] = value["value"]
+ else
+ . += value["value"]
+ if(LAZYLEN(named_args))
+ . += named_args
/client/proc/get_callproc_returnval(returnval,procname)
. = ""
diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
index dadb31ba61..47fa529912 100644
--- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
+++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
@@ -35,11 +35,11 @@
var/list/atmos_overlay_types //gas IDs of current active gas overlays
-/turf/open/New()
- ..()
+/turf/open/Initialize()
if(!blocks_air)
air = new
air.copy_from_turf(src)
+ ..()
/turf/open/Destroy()
if(active_hotspot)
@@ -113,11 +113,12 @@
/turf/open/proc/tile_graphic()
. = new /list
- var/list/gases = air.gases
- for(var/id in gases)
- var/gas = gases[id]
- if(gas[GAS_META][META_GAS_OVERLAY] && gas[MOLES] > gas[GAS_META][META_GAS_MOLES_VISIBLE])
- . += gas[GAS_META][META_GAS_OVERLAY]
+ if(air)
+ var/list/gases = air.gases
+ for(var/id in gases)
+ var/gas = gases[id]
+ if(gas[GAS_META][META_GAS_OVERLAY] && gas[MOLES] > gas[GAS_META][META_GAS_MOLES_VISIBLE])
+ . += gas[GAS_META][META_GAS_OVERLAY]
/////////////////////////////SIMULATION///////////////////////////////////
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index d691cbb631..1c7277638e 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -99,26 +99,28 @@
flags_cover = MASKCOVERSEYES
resistance_flags = FLAMMABLE
actions_types = list(/datum/action/item_action/adjust)
+
-/obj/item/clothing/mask/gas/mime/attack_self(mob/user)
- cycle_mask(user)
+/obj/item/clothing/mask/gas/mime/ui_action_click(mob/user)
+ if(!istype(user) || user.incapacitated())
+ return
-/obj/item/clothing/mask/gas/mime/proc/cycle_mask(mob/user)
- switch(icon_state)
- if("mime")
- icon_state = "sadmime"
- if("sadmime")
- icon_state = "scaredmime"
- if("scaredmime")
- icon_state = "sexymime"
- if("sexymime")
- icon_state = "mime"
- user.update_inv_wear_mask()
- for(var/X in actions)
- var/datum/action/A = X
- A.UpdateButtonIcon()
- user << "You adjust your mask to portray a different emotion."
- return 1
+ var/list/options = list()
+ options["Blanc"] = "mime"
+ options["Triste"] = "sadmime"
+ options["Effrayé"] = "scaredmime"
+ options["Excité"] ="sexymime"
+
+ var/choice = input(user,"To what form do you wish to Morph this mask?","Morph Mask") in options
+
+ if(src && choice && !user.incapacitated() && in_range(user,src))
+ icon_state = options[choice]
+ user.update_inv_wear_mask()
+ for(var/X in actions)
+ var/datum/action/A = X
+ A.UpdateButtonIcon()
+ user << "Your Mime Mask has now morphed into [choice]!"
+ return 1
/obj/item/clothing/mask/gas/monkeymask
name = "monkey mask"
@@ -170,6 +172,7 @@
resistance_flags = FLAMMABLE
obj_integrity = 100
max_integrity = 100
+ actions_types = list(/datum/action/item_action/adjust)
dog_fashion = null
@@ -186,7 +189,6 @@ obj/item/clothing/mask/gas/tiki_mask/ui_action_click(mob/user)
if(src && choice && !M.stat && in_range(M,src))
icon_state = options[choice]
- item_state = options[choice]
user.update_inv_wear_mask()
for(var/X in actions)
var/datum/action/A = X
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index afe9d3d6da..8e44d2df01 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -268,6 +268,11 @@
/obj/item/clothing/suit/armor/reactive/tesla
name = "reactive tesla armor"
desc = "An experimental suit of armor with sensitive detectors hooked up to a huge capacitor grid, with emitters strutting out of it. Zap."
+ siemens_coefficient = -1
+ var/tesla_power = 25000
+ var/tesla_range = 20
+ var/tesla_boom = FALSE
+ var/tesla_stun = FALSE
/obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, attack_text)
if(!active)
@@ -277,15 +282,10 @@
var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread
sparks.set_up(1, 1, src)
sparks.start()
- owner.visible_message("The tesla capacitors on [owner]'s reactive telsa armor are still recharging! The armor merely emits some sparks.")
+ owner.visible_message("The tesla capacitors on [owner]'s reactive tesla armor are still recharging! The armor merely emits some sparks.")
return
owner.visible_message("The [src] blocks the [attack_text], sending out arcs of lightning!")
- for(var/mob/living/M in view(6, owner))
- if(M == owner)
- continue
- owner.Beam(M,icon_state="lightning[rand(1, 12)]",time=5)
- M.adjustFireLoss(25)
- playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
+ tesla_zap(owner,tesla_range,tesla_power,tesla_boom, tesla_stun)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
diff --git a/code/modules/events/sentience.dm b/code/modules/events/sentience.dm
index f82b266175..8036f6d8f9 100644
--- a/code/modules/events/sentience.dm
+++ b/code/modules/events/sentience.dm
@@ -3,9 +3,12 @@
typepath = /datum/round_event/ghost_role/sentience
weight = 10
+
/datum/round_event/ghost_role/sentience
minimum_required = 1
role_name = "random animal"
+ var/animals = 1
+ var/one = "one"
/datum/round_event/ghost_role/sentience/start()
var/sentience_report = "[command_name()] Medium-Priority Update"
@@ -14,7 +17,7 @@
var/pets = pick("animals/bots", "bots/animals", "pets", "simple animals", "lesser lifeforms", "\[REDACTED\]")
var/strength = pick("human", "moderate", "lizard", "security", "command", "clown", "low", "very low", "\[REDACTED\]")
- sentience_report += "
Based on [data], we believe that one of the station's [pets] has developed [strength] level intelligence, and the ability to communicate."
+ sentience_report += "
Based on [data], we believe that [one] of the station's [pets] has developed [strength] level intelligence, and the ability to communicate."
print_command_report(sentience_report, "Classified [command_name()] Update")
priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg')
@@ -36,25 +39,40 @@
if(!potential.len)
return WAITING_FOR_SOMETHING
- var/mob/living/simple_animal/SA = pick(potential)
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
- var/mob/dead/observer/SG = pick(candidates)
- SA.key = SG.key
- SA.languages_spoken |= HUMAN
- SA.languages_understood |= HUMAN
- SA.sentience_act()
+ var/spawned_animals = 0
+ while(spawned_animals < animals && candidates.len && potential.len)
+ var/mob/living/simple_animal/SA = pick_n_take(potential)
+ var/mob/dead/observer/SG = pick_n_take(candidates)
- SA.maxHealth = max(SA.maxHealth, 200)
- SA.health = SA.maxHealth
- SA.del_on_death = FALSE
+ spawned_animals++
- spawned_mobs += SA
+ SA.key = SG.key
+ SA.languages_spoken |= HUMAN
+ SA.languages_understood |= HUMAN
+ SA.sentience_act()
- SA << "Hello world!"
- SA << "Due to freak radiation and/or chemicals \
- and/or lucky chance, you have gained human level intelligence \
- and the ability to speak and understand human language!"
+ SA.maxHealth = max(SA.maxHealth, 200)
+ SA.health = SA.maxHealth
+ SA.del_on_death = FALSE
+
+ spawned_mobs += SA
+
+ SA << "Hello world!"
+ SA << "Due to freak radiation and/or chemicals \
+ and/or lucky chance, you have gained human level intelligence \
+ and the ability to speak and understand human language!"
return SUCCESSFUL_SPAWN
+
+/datum/round_event_control/sentience/all
+ name = "Station-wide Human-level Intelligence"
+ typepath = /datum/round_event/ghost_role/sentience/all
+ weight = 0
+
+/datum/round_event/ghost_role/sentience/all
+ one = "all"
+ animals = INFINITY // as many as there are ghosts and animals
+ // cockroach pride, station wide
diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm
index dc0225c70b..f353cb4ff2 100644
--- a/code/modules/food_and_drinks/food/condiment.dm
+++ b/code/modules/food_and_drinks/food/condiment.dm
@@ -124,6 +124,12 @@
list_reagents = list("sodiumchloride" = 20)
possible_states = list()
+/obj/item/weapon/reagent_containers/food/condiment/saltshaker/on_reagent_change()
+ if(reagents.reagent_list.len == 0)
+ icon_state = "emptyshaker"
+ else
+ icon_state = "saltshakersmall"
+
/obj/item/weapon/reagent_containers/food/condiment/saltshaker/suicide_act(mob/user)
user.visible_message("[user] begins to swap forms with the salt shaker! It looks like [user.p_theyre()] trying to commit suicide!")
var/newname = "[name]"
@@ -156,6 +162,12 @@
list_reagents = list("blackpepper" = 20)
possible_states = list()
+/obj/item/weapon/reagent_containers/food/condiment/peppermill/on_reagent_change()
+ if(reagents.reagent_list.len == 0)
+ icon_state = "emptyshaker"
+ else
+ icon_state = "peppermillsmall"
+
/obj/item/weapon/reagent_containers/food/condiment/milk
name = "space milk"
desc = "It's milk. White and nutritious goodness!"
diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
index 56b1c12fee..e87a530ed2 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
@@ -18,6 +18,15 @@ insert ascii eagle on american flag background here
container_type = OPENCONTAINER
var/obj/item/frying = null //What's being fried RIGHT NOW?
var/cook_time = 0
+ var/static/list/blacklisted_items = typecacheof(list(
+ /obj/item/weapon/screwdriver,
+ /obj/item/weapon/crowbar,
+ /obj/item/weapon/wrench,
+ /obj/item/weapon/wirecutters,
+ /obj/item/device/multitool,
+ /obj/item/weapon/weldingtool,
+ /obj/item/weapon/reagent_containers/glass,
+ /obj/item/weapon/storage/part_replacer))
/obj/item/weapon/circuitboard/machine/deep_fryer
name = "circuit board (Deep Fryer)"
@@ -46,8 +55,16 @@ insert ascii eagle on american flag background here
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/deepfryholder))
user << "Your cooking skills are not up to the legendary Doublefry technique."
return
+ if(default_unfasten_wrench(user, I))
+ return
+ else if(exchange_parts(user, I))
+ return
+ else if(default_deconstruction_screwdriver(user, "fryer_off", "fryer_off" ,I)) //where's the open maint panel icon?!
+ return
else
- if(user.drop_item() && !frying)
+ if(is_type_in_typecache(I, blacklisted_items))
+ . = ..()
+ else if(user.drop_item() && !frying)
user << "You put [I] into [src]."
frying = I
frying.forceMove(src)
@@ -78,6 +95,7 @@ insert ascii eagle on american flag background here
S.overlays = frying.overlays
S.icon_state = frying.icon_state
S.desc = frying.desc
+ S.w_class = frying.w_class
reagents.trans_to(S, 2*(cook_time/15))
switch(cook_time)
if(0 to 15)
diff --git a/code/modules/holodeck/area_copy.dm b/code/modules/holodeck/area_copy.dm
index a3c3e6c2b3..a8e0bebf20 100644
--- a/code/modules/holodeck/area_copy.dm
+++ b/code/modules/holodeck/area_copy.dm
@@ -110,7 +110,7 @@
if(V == "air")
var/turf/open/O1 = B
var/turf/open/O2 = T
- O1.air.copy_from(O2.air)
+ O1.air.copy_from(O2.return_air())
continue
B.vars[V] = T.vars[V]
toupdate += B
diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm
index de43b317af..e177894651 100644
--- a/code/modules/holodeck/computer.dm
+++ b/code/modules/holodeck/computer.dm
@@ -64,25 +64,25 @@
..()
/obj/machinery/computer/holodeck/Initialize(mapload)
- ..()
- if(!mapload && ticker.current_state < GAME_STATE_PLAYING)
- return
- program_cache = list()
- emag_programs = list()
- for(var/typekey in subtypesof(program_type))
- var/area/holodeck/A = locate(typekey)
- if(!A || A == offline_program) continue
- if(A.contents.len == 0) continue // not loaded
- if(A.restricted)
- emag_programs += A
- else
- program_cache += A
- if(typekey == init_program)
- load_program(A,force=1)
- if(random_program && program_cache.len && init_program == null)
- load_program(pick(program_cache),force=1)
- else if(!program)
- load_program(offline_program)
+ . = mapload //late-initialize, area_copy need turfs to have air
+ if(!mapload)
+ ..()
+ program_cache = list()
+ emag_programs = list()
+ for(var/typekey in subtypesof(program_type))
+ var/area/holodeck/A = locate(typekey)
+ if(!A || A == offline_program) continue
+ if(A.contents.len == 0) continue // not loaded
+ if(A.restricted)
+ emag_programs += A
+ else
+ program_cache += A
+ if(typekey == init_program)
+ load_program(A,force=1)
+ if(random_program && program_cache.len && init_program == null)
+ load_program(pick(program_cache),force=1)
+ else if(!program)
+ load_program(offline_program)
/obj/machinery/computer/holodeck/power_change()
..()
diff --git a/code/modules/holodeck/turfs.dm b/code/modules/holodeck/turfs.dm
index e62fb393fe..b853f6d336 100644
--- a/code/modules/holodeck/turfs.dm
+++ b/code/modules/holodeck/turfs.dm
@@ -42,7 +42,7 @@
name = "asteroid"
icon_state = "asteroid0"
-/turf/open/floor/holofloor/asteroid/New()
+/turf/open/floor/holofloor/asteroid/Initialize()
icon_state = "asteroid[pick(0,1,2,3,4,5,6,7,8,9,10,11,12)]"
..()
@@ -50,7 +50,7 @@
name = "basalt"
icon_state = "basalt0"
-/turf/open/floor/holofloor/basalt/New()
+/turf/open/floor/holofloor/basalt/Initialize()
icon_state = "basalt[pick(0,1,2,3,4,5,6,7,8,9,10,11,12)]"
..()
@@ -59,7 +59,7 @@
icon = 'icons/turf/space.dmi'
icon_state = "0"
-/turf/open/floor/holofloor/space/New()
+/turf/open/floor/holofloor/space/Initialize()
icon_state = SPACE_ICON_STATE // so realistic
..()
@@ -68,11 +68,11 @@
icon = 'icons/turf/space.dmi'
icon_state = "speedspace_ns_1"
-/turf/open/floor/holofloor/hyperspace/New()
+/turf/open/floor/holofloor/hyperspace/Initialize()
icon_state = "speedspace_ns_[(x + 5*y + (y%2+1)*7)%15+1]"
..()
-/turf/open/floor/holofloor/hyperspace/ns/New()
+/turf/open/floor/holofloor/hyperspace/ns/Initialize()
..()
icon_state = "speedspace_ns_[(x + 5*y + (y%2+1)*7)%15+1]"
@@ -86,7 +86,7 @@
smooth = SMOOTH_TRUE
canSmoothWith = null
-/turf/open/floor/holofloor/carpet/New()
+/turf/open/floor/holofloor/carpet/Initialize()
..()
addtimer(CALLBACK(src, .proc/update_icon), 1)
diff --git a/code/modules/library/soapstone.dm b/code/modules/library/soapstone.dm
index a313d6aa0f..a512f12125 100644
--- a/code/modules/library/soapstone.dm
+++ b/code/modules/library/soapstone.dm
@@ -1,40 +1,22 @@
-#define SOAPSTONE_PREFIX_FILE "strings/soapstone_prefixes.txt"
-#define SOAPSTONE_SUFFIX_FILE "soapstone_suffixes.json"
-//Vocabulary lists; soapstones use a prefix and a suffix. Optionally, they can have a prefix and suffix, then a conjunction that links another set.
-var/global/list/soapstone_prefixes = list() //Read from "strings/soapstone_prefixes.txt"; if you're adding your own, put **** where the subject should be!
-var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffixes.json"
/obj/item/soapstone
name = "chisel"
- desc = "Leave \"informative\" messages for the crew, including the crew of future shifts!\n\
- (Not suitable for engraving on shuttles, off station or on cats. Side effects may include beatings, bannings and orbital bombardment.)"
+ desc = "Leave informative messages for the crew, including the crew of future shifts!\nEven if out of uses, it can still be used to remove messages.\n(Not suitable for engraving on shuttles, off station or on cats. Side effects may include beatings, bannings and orbital bombardment.)"
icon = 'icons/obj/items.dmi'
icon_state = "soapstone"
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_TINY
+ var/tool_speed = 50
var/remaining_uses = 3
var/non_dull_name
+ var/w_engrave = "engrave"
+ var/w_engraving = "engraving"
+ var/w_chipping = "chipping"
var/w_dull = "dull"
/obj/item/soapstone/New()
. = ..()
- if(!soapstone_prefixes.len)
- soapstone_prefixes = file2list(SOAPSTONE_PREFIX_FILE, "\n")
- if(!soapstone_suffixes.len)
- soapstone_suffixes = list(\
- "Characters" = strings(SOAPSTONE_SUFFIX_FILE, "Characters"), \
- "Careers" = strings(SOAPSTONE_SUFFIX_FILE, "Careers"), \
- "Antagonists" = strings(SOAPSTONE_SUFFIX_FILE, "Antagonists"), \
- "Objects" = strings(SOAPSTONE_SUFFIX_FILE, "Objects"), \
- "Techniques" = strings(SOAPSTONE_SUFFIX_FILE, "Techniques"), \
- "Actions" = strings(SOAPSTONE_SUFFIX_FILE, "Actions"), \
- "Geography" = strings(SOAPSTONE_SUFFIX_FILE, "Geography"), \
- "Orientation" = strings(SOAPSTONE_SUFFIX_FILE, "Orientation"), \
- "Body parts" = strings(SOAPSTONE_SUFFIX_FILE, "Body parts"), \
- "Concepts" = strings(SOAPSTONE_SUFFIX_FILE, "Concepts"), \
- "Musings" = strings(SOAPSTONE_SUFFIX_FILE, "Musings"), \
- )
random_name()
check_name() // could start empty
@@ -43,6 +25,9 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
non_dull_name = name
if(name == "chalk" || name == "magic marker")
desc = replacetext(desc, "engraving", "scribbling")
+ w_engrave = "scribble"
+ w_engraving = "scribbling"
+ w_chipping = "sketching"
if(name == "chalk")
w_dull = "used"
if(name == "magic marker")
@@ -50,6 +35,9 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
if(name == "soapstone" || name == "chisel")
desc = replacetext(desc, "scribbling", "engraving")
+ w_engrave = initial(w_engrave)
+ w_engraving = initial(w_engraving)
+ w_chipping = initial(w_chipping)
w_dull = "dull"
/obj/item/soapstone/examine(mob/user)
@@ -60,48 +48,59 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
user << "It looks like it can be used an unlimited number of times."
/obj/item/soapstone/afterattack(atom/target, mob/user, proximity)
- if(!remaining_uses)
- user << "[src] is [w_dull] and can't be used anymore!"
- return
var/turf/T = get_turf(target)
if(!proximity)
return
- var/obj/structure/chisel_message/msg = locate() in T
- if(msg)
- if(msg.creator_key != user.ckey)
- user << "There's already a message there!"
- return
- else
- if(alert(user, "Erase this message?", name, "Yes", "No") == "Yes")
- user.visible_message("[user] erases [msg].", "You permanently erase [msg].")
- playsound(T, 'sound/items/gavel.ogg', 50, 1)
- refund_use()
- msg.persists = 0
- qdel(msg)
- return
- return
+
+
+ var/obj/structure/chisel_message/already_message = locate(/obj/structure/chisel_message) in T
+
+ var/our_message = FALSE
+ if(already_message)
+ our_message = already_message.creator_key == user.ckey
+
+ if(!remaining_uses && !already_message)
+ // The dull chisel is dull.
+ user << "[src] is [w_dull]."
+ return
+
if(!good_chisel_message_location(T))
- user << "You can't write there!"
+ user << "It's not appropriate to [w_engrave] on [T]."
return
- var/prefix = input(user, "Choose a prefix for your message.", name) as null|anything in soapstone_prefixes
- if(!prefix)
+
+ if(already_message)
+ user.visible_message("[user] starts erasing [already_message].", "You start erasing [already_message].", "You hear a [w_chipping] sound.")
+ playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
+
+ // Removing our own messages refunds a charge
+
+ if(do_after(user, tool_speed, target=target))
+ user.visible_message("[user] has erased [already_message].", "You erased [already_message].")
+ already_message.persists = FALSE
+ qdel(already_message)
+ playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
+ if(our_message)
+ refund_use()
return
- var/suffix_category_string = input(user, "Choose a suffix category.", "[prefix]...") as null|anything in soapstone_suffixes
- var/list/suffix_category = soapstone_suffixes[suffix_category_string]
- if(!suffix_category || !suffix_category.len)
+
+ var/message = stripped_input(user, "What would you like to [w_engrave]?", "[name] Message")
+ if(!message)
+ user << "You decide not to [w_engrave] anything."
return
- var/suffix = input(user, "Choose a suffix.", "[prefix]...") as null|anything in suffix_category
- if(!suffix)
+
+ if(!target.Adjacent(user) && locate(/obj/structure/chisel_message) in T)
+ user << "You decide not to [w_engrave] anything."
return
- var/processed_message = replacetext(prefix, "****", suffix)
- if(!user.Adjacent(T) || !good_chisel_message_location(T) || locate(/obj/structure/chisel_message) in T)
- return
- user.visible_message("[user] writes a message onto [T]!", "You write a message onto [T].")
- playsound(T, 'sound/items/gavel.ogg', 50, 1)
- var/obj/structure/chisel_message/M = new(T)
- M.register(user, processed_message)
- remove_use()
- return 1
+
+ playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
+ user.visible_message("[user] starts [w_engraving] a message into [T].", "You start [w_engraving] a message into [T].", "You hear a [w_chipping] sound.")
+ if(can_use() && do_after(user, tool_speed, target=T) && can_use())
+ if(!locate(/obj/structure/chisel_message in T))
+ user << "You [w_engrave] a message into [T]."
+ playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
+ var/obj/structure/chisel_message/M = new(T)
+ M.register(user, message)
+ remove_use()
/obj/item/soapstone/proc/can_use()
if(remaining_uses == -1 || remaining_uses >= 0)
@@ -172,34 +171,6 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
var/map
var/persists = TRUE
- var/positive_ratings = 0
- var/negative_ratings = 0
-
- var/list/raters = list() //Ckeys who have rated this message
-
-/obj/structure/chisel_message/attack_hand(mob/user)
- if(user.ckey == creator_key)
- user << "You can't rate your own messages!"
- return
- if(raters[user.ckey])
- user << "You've already rated this message!"
- return
- switch(alert(user, "How would you like to rate this message?", "Message Rating", "Positive", "Negative", "Cancel"))
- if("Positive")
- for(var/client/C in clients)
- if(C.ckey == creator_key)
- C.mob << "One of your messages was rated as positive!"
- user << "You rated this message as positive."
- positive_ratings++
- raters[user.ckey] = "positive"
- if("Negative")
- for(var/client/C in clients)
- if(C.ckey == creator_key)
- C.mob << "One of your messages was rated as negative!"
- user << "You rated this message as negative."
- negative_ratings++
- raters[user.ckey] = "negative"
-
/obj/structure/chisel_message/New(newloc)
..()
SSpersistence.chisel_messages += src
@@ -219,6 +190,12 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
map = MAP_NAME
update_icon()
+/obj/structure/chisel_message/update_icon()
+ ..()
+ var/hash = md5(hidden_message)
+ var/newcolor = copytext(hash, 1, 7)
+ add_atom_colour("#[newcolor]", FIXED_COLOUR_PRIORITY)
+
/obj/structure/chisel_message/proc/pack()
var/list/data = list()
data["hidden_message"] = hidden_message
@@ -229,9 +206,6 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
var/turf/T = get_turf(src)
data["x"] = T.x
data["y"] = T.y
- data["pos_ratings"] = positive_ratings
- data["neg_ratings"] = positive_ratings
- data["raters"] = raters
return data
/obj/structure/chisel_message/proc/unpack(list/data)
@@ -239,9 +213,6 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
creator_name = data["creator_name"]
creator_key = data["creator_key"]
realdate = data["realdate"]
- positive_ratings = data["pos_ratings"]
- negative_ratings = data["neg_ratings"]
- raters = data["raters"]
var/x = data["x"]
var/y = data["y"]
@@ -251,10 +222,7 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
/obj/structure/chisel_message/examine(mob/user)
..()
- user << "[hidden_message]"
- user << "Ratings: [positive_ratings] [negative_ratings]"
- if(raters[user.ckey])
- user << "You rated this message as [raters[user.ckey]]."
+ user << "[hidden_message]"
/obj/structure/chisel_message/Destroy()
if(persists)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index fba1682828..6b9f4226c0 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -91,20 +91,29 @@
return 1
return ..()
-/mob/living/carbon/throw_impact(atom/hit_atom)
+/mob/living/carbon/throw_impact(atom/hit_atom, throwingdatum)
. = ..()
+ var/hurt = TRUE
+ if(istype(throwingdatum, /datum/thrownthing))
+ var/datum/thrownthing/D = throwingdatum
+ if(iscyborg(D.thrower))
+ var/mob/living/silicon/robot/R = D.thrower
+ if(!R.emagged)
+ hurt = FALSE
if(hit_atom.density && isturf(hit_atom))
- Weaken(1)
- take_bodypart_damage(10)
+ if(hurt)
+ Weaken(1)
+ take_bodypart_damage(10)
if(iscarbon(hit_atom) && hit_atom != src)
var/mob/living/carbon/victim = hit_atom
if(victim.movement_type & FLYING)
return
- victim.Weaken(1)
- Weaken(1)
- victim.take_bodypart_damage(10)
- take_bodypart_damage(10)
- visible_message("[src] crashes into [victim], knocking them both over!", "You violently crash into [victim]!")
+ if(hurt)
+ victim.take_bodypart_damage(10)
+ take_bodypart_damage(10)
+ victim.Weaken(1)
+ Weaken(1)
+ visible_message("[src] crashes into [victim], knocking them both over!", "You violently crash into [victim]!")
playsound(src,'sound/weapons/punch1.ogg',50,1)
@@ -231,23 +240,6 @@
/mob/living/carbon/is_muzzled()
return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle))
-/mob/living/carbon/proc/spin(spintime, speed)
- set waitfor = 0
- var/D = dir
- while(spintime >= speed)
- sleep(speed)
- switch(D)
- if(NORTH)
- D = EAST
- if(SOUTH)
- D = WEST
- if(EAST)
- D = SOUTH
- if(WEST)
- D = NORTH
- setDir(D)
- spintime -= speed
-
/mob/living/carbon/resist_buckle()
if(restrained())
changeNext_move(CLICK_CD_BREAKOUT)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 70592e6c62..3403bd86bb 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -168,7 +168,7 @@
O.emp_act(severity)
..()
-/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0)
+/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
if(tesla_shock && tesla_ignore)
return FALSE
shock_damage *= siemens_coeff
@@ -190,11 +190,11 @@
jitteriness += 1000 //High numbers for violent convulsions
do_jitter_animation(jitteriness)
stuttering += 2
- if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5))
+ if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
Stun(2)
spawn(20)
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
- if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5))
+ if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
Stun(3)
Weaken(3)
if(override)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 5b7e2e28c6..93e4e67302 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -436,7 +436,7 @@
//Added a safety check in case you want to shock a human mob directly through electrocute_act.
-/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0)
+/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
if(tesla_shock)
var/total_coeff = 1
if(gloves)
@@ -447,6 +447,8 @@
var/obj/item/clothing/suit/S = wear_suit
if(S.siemens_coefficient <= 0)
total_coeff -= 0.95
+ else if(S.siemens_coefficient == (-1))
+ total_coeff -= 1
siemens_coeff = total_coeff
if(tesla_ignore)
siemens_coeff = 0
@@ -461,7 +463,7 @@
heart_attack = 0
if(stat == CONSCIOUS)
src << "You feel your heart beating again!"
- . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion)
+ . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun)
if(.)
electrocution_animation(40)
@@ -754,4 +756,4 @@
torn_items += leg_clothes
for(var/obj/item/I in torn_items)
- I.take_damage(damage_amount, damage_type, damage_flag, 0)
\ No newline at end of file
+ I.take_damage(damage_amount, damage_type, damage_flag, 0)
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 6b97157507..443fb6e3fb 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1015,7 +1015,7 @@
var/obj/item/organ/cyberimp/chest/thrusters/T = H.getorganslot("thrusters")
if(!istype(J) && istype(C))
J = C.jetpack
- if(istype(J) && J.allow_thrust(0.01, H)) //Prevents stacking
+ if(istype(J) && J.full_speed && J.allow_thrust(0.01, H)) //Prevents stacking
. -= 2
else if(istype(T) && T.allow_thrust(0.01, H))
. -= 2
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index a4628812ea..9bf97266d8 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -150,4 +150,14 @@
return 1
/mob/living/carbon/monkey/can_use_guns(var/obj/item/weapon/gun/G)
- return 1
\ No newline at end of file
+ return 1
+
+/mob/living/carbon/monkey/angry
+ aggressive = TRUE
+
+/mob/living/carbon/monkey/angry/Initialize()
+ ..()
+ if(prob(10))
+ var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src)
+ equip_to_slot_or_del(helmet,slot_head)
+ helmet.attack_self(src) // todo encapsulate toggle
\ No newline at end of file
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index ac631e8095..97105c3994 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -93,6 +93,7 @@
if(istype(S) && S.deathmessage)
message_simple = S.deathmessage
. = ..()
+ message_simple = initial(message_simple)
if(. && isalienadult(user))
playsound(user.loc, 'sound/voice/hiss6.ogg', 80, 1, 1)
@@ -451,3 +452,15 @@
message = "beeps."
message_param = "beeps at %t."
sound = 'sound/machines/twobeep.ogg'
+
+/datum/emote/living/spin
+ key = "spin"
+ key_third_person = "spins"
+ message = "spins around dizzily!"
+
+/datum/emote/living/spin/run_emote(mob/user)
+ user.spin(20, 1)
+ if(istype(user, /mob/living/silicon/robot))
+ var/mob/living/silicon/robot/R = user
+ R.riding_datum.force_dismount()
+ ..()
\ No newline at end of file
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 8486f85145..0d10db0cd6 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -274,8 +274,7 @@
take_bodypart_damage(acidpwr * min(1, acid_volume * 0.1))
return 1
-
-/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0)
+/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
if(tesla_shock && tesla_ignore)
return FALSE
if(shock_damage > 0)
@@ -325,13 +324,16 @@
/mob/living/ratvar_act()
- if(stat != DEAD && !is_servant_of_ratvar(src) && !add_servant_of_ratvar(src))
- src << "A blinding light boils you alive! Run!"
- adjustFireLoss(35)
- if(src)
- adjust_fire_stacks(1)
- IgniteMob()
- return FALSE
+ if(stat != DEAD && !is_servant_of_ratvar(src))
+ for(var/obj/item/weapon/implant/mindshield/M in implants)
+ qdel(M)
+ if(!add_servant_of_ratvar(src))
+ src << "A blinding light boils you alive! Run!"
+ adjustFireLoss(35)
+ if(src)
+ adjust_fire_stacks(1)
+ IgniteMob()
+ return FALSE
return TRUE
diff --git a/code/modules/mob/living/silicon/pai/examine.dm b/code/modules/mob/living/silicon/pai/examine.dm
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 1cadb8ec40..f1c0d9566b 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -57,11 +57,11 @@
var/chassis = "repairbot"
var/list/possible_chassis = list("cat", "mouse", "monkey", "corgi", "fox", "repairbot", "rabbit")
- var/emitterhealth = 50
- var/emittermaxhealth = 50
- var/emitterregen = 0.5
- var/emittercd = 20
- var/emitteroverloadcd = 50
+ var/emitterhealth = 20
+ var/emittermaxhealth = 20
+ var/emitterregen = 0.25
+ var/emittercd = 50
+ var/emitteroverloadcd = 100
var/emittersemicd = FALSE
var/overload_ventcrawl = 0
@@ -235,4 +235,4 @@
/mob/living/silicon/pai/process()
emitterhealth = Clamp((emitterhealth + emitterregen), -50, emittermaxhealth)
- hit_slowdown = Clamp((hit_slowdown - 1), 0, 100)
+ hit_slowdown = Clamp((hit_slowdown - 1), 0, 100)
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm
index d03aeada87..3e531eaaa0 100644
--- a/code/modules/mob/living/silicon/robot/death.dm
+++ b/code/modules/mob/living/silicon/robot/death.dm
@@ -30,4 +30,6 @@
update_icons()
- sql_report_death(src)
\ No newline at end of file
+ unbuckle_all_mobs(TRUE)
+
+ sql_report_death(src)
diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm
index f4639706b9..04228c06c9 100644
--- a/code/modules/mob/living/silicon/robot/emote.dm
+++ b/code/modules/mob/living/silicon/robot/emote.dm
@@ -69,4 +69,4 @@
"You announce you are operating in low power mode.")
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
else
- src << "You can only use this emote when you're out of charge."
\ No newline at end of file
+ src << "You can only use this emote when you're out of charge."
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 84471f1870..cddc2f3db9 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -89,7 +89,9 @@
/obj/item/clothing/head/sombrero,
/obj/item/clothing/head/witchunter_hat)
-
+ can_buckle = TRUE
+ buckle_lying = FALSE
+ var/datum/riding/cyborg/riding_datum = null
/mob/living/silicon/robot/New(loc)
spark_system = new /datum/effect_system/spark_spread()
@@ -995,3 +997,90 @@
hat = new_hat
new_hat.forceMove(src)
update_icons()
+
+/mob/living/silicon/robot/MouseDrop_T(mob/living/M, mob/living/user)
+ . = ..()
+ if(!(M in buckled_mobs))
+ buckle_mob(M)
+
+/mob/living/silicon/robot/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
+ if(!riding_datum)
+ riding_datum = new /datum/riding/cyborg
+ riding_datum.ridden = src
+ if(buckled_mobs)
+ if(buckled_mobs.len >= max_buckled_mobs)
+ return
+ if(M in buckled_mobs)
+ return
+ if(stat)
+ return
+ if(incapacitated())
+ return
+ if(M.restrained())
+ return
+ if(iscyborg(M))
+ M.visible_message("[M] really can't seem to mount the [src]...")
+ return
+ if(isbot(M))
+ M.visible_message("No. Just... no.")
+ return
+ if(module)
+ if(!module.allow_riding)
+ M.visible_message("Unfortunately, [M] just can't seem to hold onto [src]!")
+ return
+ if(iscarbon(M))
+ if(!equip_buckle_inhands(M)) //MAKE SURE THIS IS LAST!
+ M.visible_message("[M] can't climb onto [src] because his hands are full!")
+ return
+ . = ..(M, force, check_loc)
+ riding_datum.handle_vehicle_offsets()
+
+/mob/living/silicon/robot/unbuckle_mob(mob/user)
+ if(iscarbon(user))
+ unequip_buckle_inhands(user)
+ . = ..(user)
+ riding_datum.restore_position(user)
+
+/mob/living/silicon/robot/proc/unequip_buckle_inhands(mob/living/carbon/user)
+ for(var/obj/item/cyborgride_offhand/O in user.contents)
+ if(O.ridden != src)
+ CRASH("RIDING OFFHAND ON WRONG MOB")
+ continue
+ if(O.selfdeleting)
+ continue
+ else
+ qdel(O)
+ return TRUE
+
+/mob/living/silicon/robot/proc/equip_buckle_inhands(mob/living/carbon/user)
+ var/obj/item/cyborgride_offhand/inhand = new /obj/item/cyborgride_offhand(user)
+ inhand.rider = user
+ inhand.ridden = src
+ return user.put_in_hands(inhand, TRUE)
+
+/obj/item/cyborgride_offhand
+ name = "offhand"
+ icon = 'icons/obj/weapons.dmi'
+ icon_state = "offhand"
+ w_class = WEIGHT_CLASS_HUGE
+ flags = ABSTRACT | DROPDEL | NOBLUDGEON
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ var/mob/living/carbon/rider
+ var/mob/living/silicon/robot/ridden
+ var/selfdeleting = FALSE
+
+/obj/item/cyborgride_offhand/dropped()
+ selfdeleting = TRUE
+ . = ..()
+
+/obj/item/cyborgride_offhand/equipped()
+ if(loc != rider)
+ selfdeleting = TRUE
+ qdel(src)
+ . = ..()
+
+/obj/item/cyborgride_offhand/Destroy()
+ if(selfdeleting)
+ if(rider in ridden.buckled_mobs)
+ ridden.unbuckle_mob(rider)
+ . = ..()
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 6b04e762bf..ff9f623b37 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -26,6 +26,11 @@
var/hat_offset = -3
+ var/list/ride_offset_x = list("north" = 0, "south" = 0, "east" = -6, "west" = 6)
+ var/list/ride_offset_y = list("north" = 4, "south" = 4, "east" = 3, "west" = 3)
+ var/ride_allow_incapacitated = FALSE
+ var/allow_riding = TRUE
+
/obj/item/weapon/robot_module/New()
..()
for(var/i in basic_modules)
diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm
index cbfed648cf..4f1396e010 100644
--- a/code/modules/mob/living/silicon/robot/robot_movement.dm
+++ b/code/modules/mob/living/silicon/robot/robot_movement.dm
@@ -17,3 +17,8 @@
/mob/living/silicon/robot/experience_pressure_difference(pressure_difference, direction)
if(!magpulse)
return ..()
+
+/mob/living/silicon/robot/Moved()
+ . = ..()
+ if(riding_datum)
+ riding_datum.on_vehicle_move()
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index b9d27aebb6..06114cf1bf 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -26,6 +26,11 @@
/mob/living/silicon/attack_animal(mob/living/simple_animal/M)
if(..())
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
+ if(prob(damage))
+ for(var/mob/living/N in buckled_mobs)
+ N.Weaken(1)
+ unbuckle_mob(N)
+ N.visible_message("[N] is knocked off of [src] by [M]!")
switch(M.melee_damage_type)
if(BRUTE)
adjustBruteLoss(damage)
@@ -73,6 +78,10 @@
return 0
/mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0)
+ if(buckled_mobs)
+ for(var/mob/living/M in buckled_mobs)
+ unbuckle_mob(M)
+ M.electrocute_act(shock_damage/100, source, siemens_coeff, safety, tesla_shock, illusion) //Hard metal shell conducts!
return 0 //So borgs they don't die trying to fix wiring
/mob/living/silicon/emp_act(severity)
@@ -83,12 +92,26 @@
src.take_bodypart_damage(10)
src << "*BZZZT*"
src << "Warning: Electromagnetic pulse detected."
+ for(var/mob/living/M in buckled_mobs)
+ if(prob(severity*50))
+ unbuckle_mob(M)
+ M.Weaken(2)
+ M.visible_message("[M] is thrown off of [src]!")
flash_act(affect_silicon = 1)
..()
/mob/living/silicon/bullet_act(obj/item/projectile/Proj)
if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
adjustBruteLoss(Proj.damage)
+ if(prob(Proj.damage*1.5))
+ for(var/mob/living/M in buckled_mobs)
+ M.visible_message("[M] is knocked off of [src]!")
+ unbuckle_mob(M)
+ M.Weaken(2)
+ if(Proj.stun || Proj.weaken)
+ for(var/mob/living/M in buckled_mobs)
+ unbuckle_mob(M)
+ M.visible_message("[M] is knocked off of [src] by the [Proj]!")
Proj.on_hit(src)
return 2
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index afef74db8c..cc0062775c 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -145,8 +145,9 @@ Auto Patrol: []"},
mode = BOT_HUNT
/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
- if(H.a_intent == INTENT_HARM)
+ if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
retaliate(H)
+
return ..()
/mob/living/simple_animal/bot/secbot/attackby(obj/item/weapon/W, mob/user, params)
@@ -409,4 +410,4 @@ Auto Patrol: []"},
..()
/obj/machinery/bot_core/secbot
- req_access = list(access_security)
+ req_access = list(access_security)
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index 6623271f95..253968d20a 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -98,7 +98,7 @@ Difficulty: Hard
INVOKE_ASYNC(src, .proc/charge)
else
if(prob(70) || warped)
- INVOKE_ASYNC(src, .proc/triple_charge)
+ INVOKE_ASYNC(src, .proc/charge, 2)
else
INVOKE_ASYNC(src, .proc/warp_charge)
@@ -141,12 +141,7 @@ Difficulty: Hard
blood_warp()
charge()
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
- charge()
- charge()
- charge()
-
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge()
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge(bonus_charges)
var/turf/T = get_turf(target)
if(!T || T == loc)
return
@@ -156,14 +151,18 @@ Difficulty: Hard
walk(src, 0)
setDir(get_dir(src, T))
var/obj/effect/overlay/temp/decoy/D = new /obj/effect/overlay/temp/decoy(loc,src)
- animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 5)
- sleep(5)
- throw_at(T, get_dist(src, T), 1, src, 0, callback = CALLBACK(src, .charge_end))
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge_end()
+ animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 3)
+ sleep(3)
+ throw_at(T, get_dist(src, T), 0.5, src, 0, callback = CALLBACK(src, .charge_end, bonus_charges))
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge_end(bonus_charges)
charging = 0
try_bloodattack()
if(target)
- Goto(target, move_to_delay, minimum_distance)
+ if(bonus_charges)
+ charge(bonus_charges--)
+ else
+ Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
@@ -312,8 +311,8 @@ Difficulty: Hard
DA.color = "#FF0000"
var/oldtransform = DA.transform
DA.transform = matrix()*2
- animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 5)
- sleep(5)
+ animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 3)
+ sleep(3)
qdel(DA)
var/obj/effect/decal/cleanable/blood/found_bloodpool
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 8770fa79a1..3ed5f93c81 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -299,21 +299,20 @@
if(!gibbed)
if(death_sound)
playsound(get_turf(src),death_sound, 200, 1)
- if(deathmessage && !del_on_death)
+ if(deathmessage || !del_on_death)
emote("deathgasp")
if(del_on_death)
- ghostize()
+ ..()
//Prevent infinite loops if the mob Destroy() is overriden in such
//a manner as to cause a call to death() again
del_on_death = FALSE
qdel(src)
- return
else
health = 0
icon_state = icon_dead
density = 0
lying = 1
- ..()
+ ..()
/mob/living/simple_animal/proc/CanAttack(atom/the_target)
if(see_invisible < the_target.invisibility)
@@ -551,4 +550,4 @@
/mob/living/simple_animal/buckle_mob(mob/living/buckled_mob, force = 0, check_loc = 1)
. = ..()
- riding_datum = new/datum/riding/animal
+ riding_datum = new/datum/riding/animal
\ No newline at end of file
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 3dba061fd9..e97286b7e9 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1,6 +1,5 @@
/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game.
mob_list -= src
- SSmob.currentrun -= src
dead_mob_list -= src
living_mob_list -= src
all_clockwork_mobs -= src
@@ -28,8 +27,8 @@ var/next_mob_id = 0
dead_mob_list += src
else
living_mob_list += src
- prepare_huds()
hook_vr("mob_new",list(src))
+ prepare_huds()
..()
/atom/proc/prepare_huds()
@@ -112,7 +111,7 @@ var/next_mob_id = 0
if(self_message)
msg = self_message
else
- if(M.see_invisible= speed)
+ sleep(speed)
+ switch(D)
+ if(NORTH)
+ D = EAST
+ if(SOUTH)
+ D = WEST
+ if(EAST)
+ D = SOUTH
+ if(WEST)
+ D = NORTH
+ setDir(D)
+ spintime -= speed
+
/mob/verb/stop_pulling()
set name = "Stop Pulling"
set category = "IC"
@@ -452,30 +456,7 @@ proc/get_top_level_mob(var/mob/S)
// M.Login() //wat
return
-/mob/proc/update_flavor_text()
- set src in usr
- if(usr != src)
- usr << "No."
- var/msg = input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavor Text",html_decode(flavor_text)) as message|null
- if(msg != null)
- msg = copytext(msg, 1, MAX_MESSAGE_LEN)
- msg = html_encode(msg)
-
- flavor_text = msg
-
-/mob/proc/warn_flavor_changed()
- if(flavor_text && flavor_text != "") // don't spam people that don't use it!
- src << "OOC Warning:
"
- src << "Your flavor text is likely out of date! Change"
-
-/mob/proc/print_flavor_text()
- if(flavor_text && flavor_text != "")
- var/msg = replacetext(flavor_text, "\n", " ")
- if(lentext(msg) <= 40)
- return "\blue [msg]"
- else
- return "\blue [copytext(msg, 1, 37)]... More..."
/mob/verb/cancel_camera()
set name = "Cancel Camera View"
@@ -571,7 +552,6 @@ proc/get_top_level_mob(var/mob/S)
stat(null, "Next Map: [nextmap.friendlyname]")
stat(null, "Server Time: [time2text(world.realtime, "YYYY-MM-DD hh:mm")]")
if(SSshuttle.emergency)
- stat(null, "Current Shuttle: [SSshuttle.emergency.name]")
var/ETA = SSshuttle.emergency.getModeStr()
if(ETA)
stat(null, "[ETA] [SSshuttle.emergency.getTimerStr()]")
@@ -967,5 +947,4 @@ proc/get_top_level_mob(var/mob/S)
switch(var_name)
if ("attack_log")
return debug_variable(var_name, attack_log, 0, src, FALSE)
-
. = ..()
\ No newline at end of file
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index e19ea6f8df..3e6cb63df3 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -175,7 +175,8 @@
moving = 0
if(mob && .)
- mob.throwing = 0
+ if(mob.throwing)
+ mob.throwing.finalize(FALSE)
for(var/obj/O in mob)
O.on_mob_move(direct, src)
@@ -424,7 +425,7 @@
/client/verb/toggle_walk_run()
set name = "toggle-walk-run"
set hidden = TRUE
- set instant = TRUE
+ set instant = TRUE
if(mob)
mob.toggle_move_intent()
diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm
index 2cb4634758..c867b6e719 100644
--- a/code/modules/mob/say_vr.dm
+++ b/code/modules/mob/say_vr.dm
@@ -69,4 +69,41 @@
/mob/proc/emote_vr(var/act, var/type, var/message) //This would normally go in say.dm
if(act == "me")
- return custom_emote_vr(type, message)
\ No newline at end of file
+ return custom_emote_vr(type, message)
+
+/mob/proc/update_flavor_text()
+ set src in usr
+ if(usr != src)
+ usr << "No."
+ var/msg = input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavor Text",html_decode(flavor_text)) as message|null
+
+ if(msg != null)
+ msg = copytext(msg, 1, MAX_MESSAGE_LEN)
+ msg = html_encode(msg)
+
+ flavor_text = msg
+
+/mob/proc/warn_flavor_changed()
+ if(flavor_text && flavor_text != "") // don't spam people that don't use it!
+ src << "OOC Warning:
"
+ src << "Your flavor text is likely out of date! Change"
+
+/mob/proc/print_flavor_text()
+ if(flavor_text && flavor_text != "")
+ var/msg = replacetext(flavor_text, "\n", " ")
+ if(lentext(msg) <= 40)
+ return "\blue [msg]"
+ else
+ return "\blue [copytext(msg, 1, 37)]... More..."
+
+/mob/proc/get_top_level_mob()
+ if(istype(src.loc,/mob)&&src.loc!=src)
+ var/mob/M=src.loc
+ return M.get_top_level_mob()
+ return src
+
+proc/get_top_level_mob(var/mob/S)
+ if(istype(S.loc,/mob)&&S.loc!=S)
+ var/mob/M=S.loc
+ return M.get_top_level_mob()
+ return S
\ No newline at end of file
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 7f83bba8ab..615a6c5157 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -29,6 +29,18 @@
var/list/stamped
var/rigged = 0
var/spam_flag = 0
+ var/contact_poison // Reagent ID to transfer on contact
+ var/contact_poison_volume = 0
+
+
+/obj/item/weapon/paper/pickup(user)
+ if(contact_poison && ishuman(user))
+ var/mob/living/carbon/human/H = user
+ var/obj/item/clothing/gloves/G = H.gloves
+ if(!istype(G) || G.transfer_prints)
+ H.reagents.add_reagent(contact_poison,contact_poison_volume)
+ contact_poison = null
+ ..()
/obj/item/weapon/paper/New()
@@ -166,7 +178,7 @@
/obj/item/weapon/paper/proc/clearpaper()
info = null
stamps = null
- stamped = list()
+ LAZYCLEARLIST(stamped)
cut_overlays()
updateinfolinks()
update_icon()
@@ -289,7 +301,7 @@
else
info += t // Oh, he wants to edit to the end of the file, let him.
updateinfolinks()
-
+ i.on_write(src,usr)
usr << browse("[name][info_links]
[stamps]", "window=[name]") // Update the window
update_icon()
@@ -326,9 +338,7 @@
stampoverlay.icon_state = "paper_[P.icon_state]"
- if(!stamped)
- stamped = new
- stamped += P.icon_state
+ LAZYADD(stamped, P.icon_state)
add_overlay(stampoverlay)
user << "You stamp the paper with your rubber stamp."
diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm
index a272617396..01f07b6e14 100644
--- a/code/modules/paperwork/paperplane.dm
+++ b/code/modules/paperwork/paperplane.dm
@@ -12,7 +12,6 @@
max_integrity = 50
var/obj/item/weapon/paper/internalPaper
- var/list/stamped = list()
/obj/item/weapon/paperplane/New(loc, obj/item/weapon/paper/newPaper)
..()
@@ -20,13 +19,18 @@
pixel_x = rand(-9, 9)
if(newPaper)
internalPaper = newPaper
- src.flags = newPaper.flags
- stamped = internalPaper.stamped
+ flags = newPaper.flags
newPaper.forceMove(src)
else
internalPaper = new /obj/item/weapon/paper(src)
update_icon()
+/obj/item/weapon/paperplane/Destroy()
+ if(internalPaper)
+ qdel(internalPaper)
+ internalPaper = null
+ return ..()
+
/obj/item/weapon/paperplane/suicide_act(mob/user)
user.Stun(10)
user.visible_message("[user] jams the [src] in [user.p_their()] nose. It looks like [user.p_theyre()] trying to commit suicide!")
@@ -37,18 +41,18 @@
/obj/item/weapon/paperplane/update_icon()
cut_overlays()
- if(!stamped)
- stamped = new
- else if(stamped)
+ var/list/stamped = internalPaper.stamped
+ if(stamped)
for(var/S in stamped)
- var/obj/item/weapon/stamp/stamp = S
- var/image/stampoverlay = image('icons/obj/bureaucracy.dmi', "paperplane_[initial(stamp.icon_state)]")
+ var/image/stampoverlay = image('icons/obj/bureaucracy.dmi', "paperplane_[stamped]")
add_overlay(stampoverlay)
/obj/item/weapon/paperplane/attack_self(mob/user)
user << "You unfold [src]."
+ var/internal_paper_tmp = internalPaper
+ internalPaper = null
qdel(src)
- user.put_in_hands(internalPaper)
+ user.put_in_hands(internal_paper_tmp)
/obj/item/weapon/paperplane/attackby(obj/item/weapon/P, mob/living/carbon/human/user, params)
..()
@@ -57,15 +61,7 @@
return
else if(istype(P, /obj/item/weapon/stamp)) //we don't randomize stamps on a paperplane
-
- if (!stamped)
- stamped = new
-
- stamped += P.type
- internalPaper.stamps += "
" //stamps the paper inside!
- internalPaper.stamped = stamped
- internalPaper.attackby(P) //spoofed attack to update internal paper.
- user << "You stamp [src] with your rubber stamp."
+ internalPaper.attackby(P, user) //spoofed attack to update internal paper.
update_icon()
else if(P.is_hot())
@@ -108,7 +104,7 @@
return
user << "You fold [src] into the shape of a plane!"
user.temporarilyRemoveItemFromInventory(src)
- I = new /obj/item/weapon/paperplane(loc, src)
+ I = new /obj/item/weapon/paperplane(user, src)
user.put_in_hands(I)
else
user << " You lack the dexterity to fold \the [src]. "
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index 08a03aae29..2d3bdf0281 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -162,3 +162,12 @@
else
icon_state = initial(icon_state) //looks like a normal pen when off.
item_state = initial(item_state)
+
+//Crayons path disambiguity sigh.
+/obj/item/proc/on_write(obj/item/weapon/paper/P, mob/user)
+ return
+
+/obj/item/weapon/pen/poison/on_write(obj/item/weapon/paper/P, mob/user)
+ P.contact_poison = "delayed_toxin"
+ P.contact_poison_volume = 10
+ add_logs(user,P,"used poison pen on")
\ No newline at end of file
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index 7cc01ba0ba..17ac046a03 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -53,9 +53,10 @@ var/global/list/rad_collectors = list()
return
..()
-/obj/machinery/power/rad_collector/can_be_unfasten_wrench(mob/user)
+/obj/machinery/power/rad_collector/can_be_unfasten_wrench(mob/user, silent)
if(loaded_tank)
- user << "Remove the plasma tank first!"
+ if(!silent)
+ user << "Remove the plasma tank first!"
return FAILED_UNFASTEN
return ..()
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index eef1a5a799..886932cc34 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -128,7 +128,7 @@
return 1
/obj/machinery/power/emitter/attack_animal(mob/living/simple_animal/M)
- if(ismegafauna(M))
+ if(ismegafauna(M) && anchored)
state = 0
anchored = FALSE
M.visible_message("[M] rips [src] free from its moorings!")
@@ -217,9 +217,10 @@
A.starting = loc
A.fire()
-/obj/machinery/power/emitter/can_be_unfasten_wrench(mob/user)
+/obj/machinery/power/emitter/can_be_unfasten_wrench(mob/user, silent)
if(state == EM_WELDED)
- user << "[src] is welded to the floor!"
+ if(!silent)
+ user << "[src] is welded to the floor!"
return FAILED_UNFASTEN
return ..()
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index d3c6d0104c..d444d7d8ca 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -77,9 +77,10 @@ field_generator power level display
else
user << "The [src] needs to be firmly secured to the floor first!"
-/obj/machinery/field/generator/can_be_unfasten_wrench(mob/user)
+/obj/machinery/field/generator/can_be_unfasten_wrench(mob/user, silent)
if(state == FG_WELDED)
- user << "[src] is welded to the floor!"
+ if(!silent)
+ user << "[src] is welded to the floor!"
return FAILED_UNFASTEN
return ..()
diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm
index 8092b59d90..a0a49ea6d5 100644
--- a/code/modules/power/tesla/energy_ball.dm
+++ b/code/modules/power/tesla/energy_ball.dm
@@ -160,7 +160,7 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
var/mob/living/carbon/C = A
C.dust()
-/proc/tesla_zap(atom/source, zap_range = 3, power, explosive = FALSE)
+/proc/tesla_zap(atom/source, zap_range = 3, power, explosive = FALSE, stun_mobs = TRUE)
. = source.dir
if(power < 1000)
return
@@ -251,26 +251,27 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
//per type stuff:
if(closest_tesla_coil)
- closest_tesla_coil.tesla_act(power, explosive)
+ closest_tesla_coil.tesla_act(power, explosive, stun_mobs)
else if(closest_grounding_rod)
- closest_grounding_rod.tesla_act(power, explosive)
+ closest_grounding_rod.tesla_act(power, explosive, stun_mobs)
else if(closest_mob)
var/shock_damage = Clamp(round(power/400), 10, 90) + rand(-5, 5)
- closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1)
+ closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1, stun = stun_mobs)
if(issilicon(closest_mob))
var/mob/living/silicon/S = closest_mob
- S.emp_act(2)
- tesla_zap(S, 7, power / 1.5) // metallic folks bounce it further
+ if(stun_mobs)
+ S.emp_act(2)
+ tesla_zap(S, 7, power / 1.5, stun_mobs) // metallic folks bounce it further
else
- tesla_zap(closest_mob, 5, power / 1.5)
+ tesla_zap(closest_mob, 5, power / 1.5, stun_mobs)
else if(closest_machine)
- closest_machine.tesla_act(power, explosive)
+ closest_machine.tesla_act(power, explosive, stun_mobs)
else if(closest_blob)
- closest_blob.tesla_act(power, explosive)
+ closest_blob.tesla_act(power, explosive, stun_mobs)
else if(closest_structure)
- closest_structure.tesla_act(power, explosive)
+ closest_structure.tesla_act(power, explosive, stun_mobs)
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index f133b08a79..48d50750a5 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -355,4 +355,3 @@
user.emote("scream")
user.drop_item()
user.Weaken(4)
- return
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index f80f2676cc..e2ba1aaa6d 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -165,6 +165,9 @@
/obj/item/weapon/gun/ballistic/shotgun/boltaction/enchanted/arcane_barrage/discard_gun(mob/user)
return
+/obj/item/weapon/gun/ballistic/shotgun/boltaction/enchanted/attack_self()
+ return
+
/obj/item/weapon/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
..()
if(guns_left)
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index df867c4444..ba4798b5d7 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -376,28 +376,32 @@
/obj/item/borg/upgrade/modkit/chassis_mod
name = "super chassis"
desc = "Makes your KA yellow. All the fun of having a more powerful KA without actually having a more powerful KA."
- cost = 10
+ cost = 0
denied_type = /obj/item/borg/upgrade/modkit/chassis_mod
var/chassis_icon = "kineticgun_u"
+ var/chassis_name = "super-kinetic accelerator"
/obj/item/borg/upgrade/modkit/chassis_mod/install(obj/item/weapon/gun/energy/kinetic_accelerator/KA, mob/user)
. = ..()
if(.)
KA.icon_state = chassis_icon
+ KA.name = chassis_name
/obj/item/borg/upgrade/modkit/chassis_mod/uninstall(obj/item/weapon/gun/energy/kinetic_accelerator/KA)
KA.icon_state = initial(KA.icon_state)
+ KA.name = initial(KA.name)
..()
/obj/item/borg/upgrade/modkit/chassis_mod/orange
name = "hyper chassis"
desc = "Makes your KA orange. All the fun of having explosive blasts without actually having explosive blasts."
chassis_icon = "kineticgun_h"
+ chassis_name = "hyper-kinetic accelerator"
/obj/item/borg/upgrade/modkit/tracer
name = "white tracer bolts"
desc = "Causes kinetic accelerator bolts to have a white tracer trail and explosion."
- cost = 4
+ cost = 0
denied_type = /obj/item/borg/upgrade/modkit/tracer
var/bolt_color = "#FFFFFF"
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 8d12c8b27e..fc79232e8f 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -814,3 +814,23 @@
if(prob(30))
M << "You should sit down and take a rest..."
..()
+
+/datum/reagent/toxin/delayed
+ name = "Toxin Microcapsules"
+ id = "delayed_toxin"
+ description = "Causes heavy toxin damage after a brief time of inactivity."
+ reagent_state = LIQUID
+ metabolization_rate = 0 //stays in the system until active.
+ var/actual_metaboliztion_rate = REAGENTS_METABOLISM
+ toxpwr = 0
+ var/actual_toxpwr = 5
+ var/delay = 30
+
+/datum/reagent/toxin/delayed/on_mob_life(mob/living/M)
+ if(current_cycle > delay)
+ holder.remove_reagent(id, actual_metaboliztion_rate * M.metabolism_efficiency)
+ M.adjustToxLoss(actual_toxpwr*REM, 0)
+ if(prob(10))
+ M.Weaken(1, 0)
+ . = 1
+ ..()
\ No newline at end of file
diff --git a/code/modules/recycling/disposal-unit.dm b/code/modules/recycling/disposal-unit.dm
index 3423673612..80c123397d 100644
--- a/code/modules/recycling/disposal-unit.dm
+++ b/code/modules/recycling/disposal-unit.dm
@@ -62,16 +62,17 @@
deconstruct()
/obj/machinery/disposal/Initialize(mapload)
- ..()
- if(!mapload)
- return
- //this will get a copy of the air turf and take a SEND PRESSURE amount of air from it
- var/atom/L = loc
- var/datum/gas_mixture/env = new
- env.copy_from(L.return_air())
- var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1)
- air_contents.merge(removed)
- trunk_check()
+ . = mapload //late-initialize, we need turfs to have air
+ if(initialized) //will only be run on late mapload initialization
+ //this will get a copy of the air turf and take a SEND PRESSURE amount of air from it
+ var/atom/L = loc
+ var/datum/gas_mixture/env = new
+ env.copy_from(L.return_air())
+ var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1)
+ air_contents.merge(removed)
+ trunk_check()
+ else
+ ..()
/obj/machinery/disposal/attackby(obj/item/I, mob/user, params)
add_fingerprint(user)
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index af4cd2063b..76839102a8 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -389,7 +389,9 @@
launch_status = UNLAUNCHED
/obj/docking_port/mobile/pod/request()
- if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA)
+ var/obj/machinery/computer/shuttle/S = getControlConsole()
+
+ if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA || (S && S.emagged))
if(launch_status == UNLAUNCHED)
launch_status = EARLY_LAUNCHED
return ..()
@@ -418,6 +420,11 @@
/obj/machinery/computer/shuttle/pod/update_icon()
return
+/obj/machinery/computer/shuttle/pod/emag_act(mob/user)
+ if(!emagged)
+ emagged = TRUE
+ user << "You fry the pod's alert level checking system."
+
/obj/docking_port/stationary/random
name = "escape pod"
id = "pod"
@@ -469,6 +476,7 @@
density = 0
icon = 'icons/obj/storage.dmi'
icon_state = "safe"
+ var/unlocked = FALSE
/obj/item/weapon/storage/pod/New()
..()
@@ -488,13 +496,18 @@
return
/obj/item/weapon/storage/pod/MouseDrop(over_object, src_location, over_location)
- if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA)
+ if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA || unlocked)
. = ..()
else
usr << "The storage unit will only unlock during a Red or Delta security alert."
/obj/item/weapon/storage/pod/attack_hand(mob/user)
- return
+ return MouseDrop(user)
+
+/obj/item/weapon/storage/pod/onShuttleMove()
+ unlocked = TRUE
+ // If the pod was launched, the storage will always open.
+ return ..()
/obj/docking_port/mobile/emergency/backup
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index 153a5badd3..37f2aa7abd 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -699,4 +699,13 @@
else
dst = destination
. += " towards [dst ? dst.name : "unknown location"] ([timeLeft(600)] minutes)"
+
+
+// attempts to locate /obj/machinery/computer/shuttle with matching ID inside the shuttle
+/obj/docking_port/mobile/proc/getControlConsole()
+ for(var/obj/machinery/computer/shuttle/S in areaInstance)
+ if(S.shuttleId == id)
+ return S
+ return null
+
#undef DOCKING_PORT_HIGHLIGHT
diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm
index fd82fb7032..c724fbb35c 100644
--- a/code/modules/shuttle/special.dm
+++ b/code/modules/shuttle/special.dm
@@ -216,3 +216,42 @@
var/obj/item/weapon/card/id/ID = user.get_idcard()
if(ID && (access_cent_bar in ID.access))
return TRUE
+
+//Luxury Shuttle Blockers
+
+/obj/effect/forcefield/luxury_shuttle
+ var/threshhold = 500
+ var/static/list/approved_passengers = list()
+
+/obj/effect/forcefield/luxury_shuttle/CanPass(atom/movable/mover, turf/target, height=0)
+ if(mover in approved_passengers)
+ return 1
+
+ if(!isliving(mover)) //No stowaways
+ return 0
+
+ var/total_cash = 0
+ var/list/counted_money = list()
+
+ for(var/obj/item/weapon/coin/C in mover.GetAllContents())
+ total_cash += C.value
+ counted_money += C
+ if(total_cash >= threshhold)
+ break
+ for(var/obj/item/stack/spacecash/S in mover.GetAllContents())
+ total_cash += S.value * S.amount
+ counted_money += S
+ if(total_cash >= threshhold)
+ break
+
+ if(total_cash >= threshhold)
+ for(var/obj/I in counted_money)
+ qdel(I)
+
+ mover << "Thank you for your payment! Please enjoy your flight."
+ approved_passengers += mover
+ return 1
+ else
+ mover << "You don't have enough money to enter the main shuttle. You'll have to fly coach."
+ return 0
+
diff --git a/code/modules/spells/spell_types/aimed.dm b/code/modules/spells/spell_types/aimed.dm
index 111094d5d7..f95e0f2c9b 100644
--- a/code/modules/spells/spell_types/aimed.dm
+++ b/code/modules/spells/spell_types/aimed.dm
@@ -6,6 +6,7 @@
var/active_msg = "You charge your projectile!"
var/base_icon_state = "projectile"
var/active_icon_state = "projectile"
+ var/projectile_damage_override = -1
/obj/effect/proc_holder/spell/aimed/Click()
var/mob/living/user = usr
@@ -54,6 +55,11 @@
var/obj/item/projectile/P = new projectile_type(user.loc)
P.current = get_turf(user)
P.preparePixelProjectile(target, get_turf(target), user)
+ if(projectile_damage_override != -1)
+ P.damage = projectile_damage_override
+ P.nodamage = TRUE
+ if(P.damage)
+ P.nodamage = FALSE
P.fire()
return TRUE
@@ -80,6 +86,11 @@
var/obj/item/projectile/magic/aoe/lightning/P = new /obj/item/projectile/magic/aoe/lightning(user.loc)
P.current = get_turf(user)
P.preparePixelProjectile(target, get_turf(target), user)
+ if(projectile_damage_override != -1)
+ P.damage = projectile_damage_override
+ P.nodamage = TRUE
+ if(P.damage)
+ P.nodamage = FALSE
P.tesla_power = tesla_power
P.tesla_range = tesla_range
P.tesla_boom = tesla_boom
diff --git a/code/modules/uplink/uplink_item.dm b/code/modules/uplink/uplink_item.dm
index 56300c2545..786b2b0a9e 100644
--- a/code/modules/uplink/uplink_item.dm
+++ b/code/modules/uplink/uplink_item.dm
@@ -618,6 +618,13 @@ var/list/uplink_items = list() // Global list so we only initialize this once.
cost = 4
exclude_modes = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
+/datum/uplink_item/stealthy_weapons/poison_pen
+ name = "Poison Pen"
+ desc = "Cutting edge of deadly writing implements technology, this gadget will infuse any piece of paper with delayed contact poison."
+ item = /obj/item/weapon/pen/poison
+ cost = 2
+ exclude_modes = list(/datum/game_mode/nuclear)
+
/datum/uplink_item/stealthy_weapons/soap
name = "Syndicate Soap"
desc = "A sinister-looking surfactant used to clean blood stains to hide murders and prevent DNA analysis. \
@@ -1166,13 +1173,14 @@ var/list/uplink_items = list() // Global list so we only initialize this once.
/datum/uplink_item/role_restricted
category = "Role-Restricted"
exclude_modes = list(/datum/game_mode/nuclear)
+ surplus = 0
/datum/uplink_item/role_restricted/reverse_revolver
name = "Reverse Revolver"
desc = "A revolver that always fires at its user. \"Accidentally\" drop your weapon, then watch as the greedy corporate pigs blow their own brains all over the wall. \
- The revolver itself is actually real. Only clumsy people, and clowns, can fire it normally. Honk."
+ The revolver itself is actually real. Only clumsy people, and clowns, can fire it normally. Comes in a box of hugs. Honk."
cost = 14
- item = /obj/item/weapon/gun/ballistic/revolver/reverse
+ item = /obj/item/weapon/storage/box/hug/reverse_revolver
restricted_roles = list("Clown")
/datum/uplink_item/role_restricted/ez_clean_bundle
diff --git a/code/world.dm b/code/world.dm
index 78b309c259..ad41f6781e 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -9,7 +9,6 @@
name = "/tg/ Station 13"
fps = 20
visibility = 0
-
#ifdef GC_FAILURE_HARD_LOOKUP
loop_checks = FALSE
#endif
@@ -17,8 +16,8 @@
var/list/map_transition_config = MAP_TRANSITION_CONFIG
/world/New()
+ world.log << "World loaded at [world.timeofday]"
map_ready = 1
- world.log << "Map is ready."
#if (PRELOAD_RSC == 0)
external_rsc_urls = file2list("config/external_rsc_urls.txt","\n")
@@ -49,9 +48,6 @@ var/list/map_transition_config = MAP_TRANSITION_CONFIG
LoadBans()
investigate_reset()
- if(config && config.server_name != null && config.server_suffix && world.port > 0)
- config.server_name += " #[(world.port % 1000) / 100]"
-
timezoneOffset = text2num(time2text(0,"hh")) * 36000
if(config.sql_enabled)
@@ -74,7 +70,6 @@ var/list/map_transition_config = MAP_TRANSITION_CONFIG
Master.Setup(10, FALSE)
-
#define IRC_STATUS_THROTTLE 50
var/last_irc_status = 0
@@ -101,12 +96,13 @@ var/last_irc_status = 0
else if("ircstatus" in input)
if(world.time - last_irc_status < IRC_STATUS_THROTTLE)
return
-// var/list/adm = get_admin_counts()
-// var/status = "Admins: [adm["total"]] (Active: [adm["present"]] AFK: [adm["afk"]] Stealth: [adm["stealth"]] Skipped: [adm["noflags"]]). "
+ var/list/adm = get_admin_counts()
+ var/list/allmins = adm["total"]
+ var/status = "Admins: [allmins.len] (Active: [english_list(adm["present"])] AFK: [english_list(adm["afk"])] Stealth: [english_list(adm["stealth"])] Skipped: [english_list(adm["noflags"])]). "
status += "Players: [clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [ticker.mode.name]."
send2irc("Status", status)
last_irc_status = world.time
- send2maindiscord("**Server starting up** on `[config.server? "byond://[config.server]" : "byond://[world.address]:[world.port]"]`. Map is **Probably Box Station**")
+ send2maindiscord("**Server starting up**. [clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [ticker.mode.name].`. Map is **Probably Box Station**")
else if("status" in input)
var/list/s = list()
@@ -121,21 +117,17 @@ var/last_irc_status = 0
s["players"] = clients.len
s["revision"] = revdata.commit
s["revision_date"] = revdata.date
-
- var/admins = 0
var/mentors = 0
for(var/client/C in clients)
var/mentor = mentor_datums[C.ckey]
if(mentor)
mentors++
- if(C.holder)
- if(C.holder.fakekey)
- continue //so stealthmins aren't revealed by the hub
- admins++
-
- s["gamestate"] = 1
- s["admins"] = admins
s["mentors"] = mentors
+ var/list/adm = get_admin_counts()
+ var/list/presentmins = adm["present"]
+ var/list/afkmins = adm["afk"]
+ s["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho
+ s["gamestate"] = 1
if(ticker)
s["gamestate"] = ticker.current_state
@@ -183,30 +175,30 @@ var/last_irc_status = 0
else if("adminmsg" in input)
if(!key_valid)
return "Bad Key"
-// else
-// return IrcPm(input["adminmsg"],input["msg"],input["sender"])
+ else
+ return IrcPm(input["adminmsg"],input["msg"],input["sender"])
else if("namecheck" in input)
if(!key_valid)
return "Bad Key"
-// else
-// log_admin("IRC Name Check: [input["sender"]] on [input["namecheck"]]")
-// message_admins("IRC name checking on [input["namecheck"]] from [input["sender"]]")
-// return keywords_lookup(input["namecheck"],1)
+ else
+ log_admin("IRC Name Check: [input["sender"]] on [input["namecheck"]]")
+ message_admins("IRC name checking on [input["namecheck"]] from [input["sender"]]")
+ return keywords_lookup(input["namecheck"],1)
else if("adminwho" in input)
if(!key_valid)
return "Bad Key"
-// else
-// return ircadminwho()
-
+ else
+ return ircadminwho()
+#define WORLD_REBOOT(X) world.log << "World rebooted at [world.timeofday]"; ..(X)
/world/Reboot(var/reason, var/feedback_c, var/feedback_r, var/time)
if (reason == 1) //special reboot, do none of the normal stuff
if (usr)
log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools")
message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools")
world << "Rebooting World immediately due to host request"
- return ..(1)
+ WORLD_REBOOT(1)
var/delay
if(time)
delay = time
@@ -215,7 +207,7 @@ var/last_irc_status = 0
if(ticker.delay_end)
world << "An admin has delayed the round end."
return
- world << "Rebooting World in [delay/10] [delay > 10 ? "seconds" : "second"]. [reason]"
+ world << "Rebooting World in [delay/10] [(delay >= 10 && delay < 20) ? "second" : "seconds"]. [reason]"
var/round_end_sound_sent = FALSE
if(ticker.round_end_sound)
round_end_sound_sent = TRUE
@@ -237,12 +229,12 @@ var/last_irc_status = 0
Reboot("Map change timed out", time = 10)
return
OnReboot(reason, feedback_c, feedback_r, round_end_sound_sent)
- ..(0)
+ WORLD_REBOOT(0)
+#undef WORLD_REBOOT
/world/proc/OnReboot(reason, feedback_c, feedback_r, round_end_sound_sent)
feedback_set_details("[feedback_c]","[feedback_r]")
log_game("Rebooting World. [reason]")
- kick_clients_in_lobby("The round came to an end with you in the lobby.", 1) //second parameter ensures only afk clients are kicked
#ifdef dellogging
var/log = file("data/logs/del.log")
log << time2text(world.realtime)
@@ -251,30 +243,40 @@ var/last_irc_status = 0
if(count > 10)
log << "#[count]\t[index]"
#endif
- var/soundwait = 0
- if (ticker.round_end_sound && !round_end_sound_sent)
- soundwait = 10
- for(var/thing in clients)
- var/client/C = thing
- if (!C)
- continue
- C.Export("##action=load_rsc", ticker.round_end_sound)
- spawn(soundwait/2)
- if(ticker && ticker.round_end_sound)
- world << sound(ticker.round_end_sound)
- else
- world << sound(pick('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg','sound/misc/leavingtg.ogg', 'sound/misc/its_only_game.ogg', 'sound/misc/yeehaw.ogg', 'sound/misc/disappointed.ogg')) // random end sounds!! - LastyBatsy
if(blackbox)
blackbox.save_all_data_to_sql()
- sleep(soundwait)
Master.Shutdown() //run SS shutdowns
+ RoundEndSound(round_end_sound_sent)
+ kick_clients_in_lobby("The round came to an end with you in the lobby.", 1) //second parameter ensures only afk clients are kicked
+ world << "Rebooting world. Loading next map..."
for(var/thing in clients)
var/client/C = thing
- if (!C)
- continue
- if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
+ if(C && config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
C << link("byond://[config.server]")
+/world/proc/RoundEndSound(round_end_sound_sent)
+ set waitfor = FALSE
+ var/round_end_sound
+ if(!ticker && ticker.round_end_sound)
+ round_end_sound = ticker.round_end_sound
+ if (!round_end_sound_sent)
+ for(var/thing in clients)
+ var/client/C = thing
+ if (!C)
+ continue
+ C.Export("##action=load_rsc", round_end_sound)
+ else
+ round_end_sound = pick(\
+ 'sound/roundend/newroundsexy.ogg',
+ 'sound/roundend/apcdestroyed.ogg',
+ 'sound/roundend/bangindonk.ogg',
+ 'sound/roundend/leavingtg.ogg',
+ 'sound/roundend/its_only_game.ogg',
+ 'sound/roundend/yeehaw.ogg',
+ 'sound/roundend/disappointed.ogg'\
+ )
+ world << sound(round_end_sound)
+
var/inerror = 0
/world/Error(var/exception/e)
//runtime while processing runtimes
diff --git a/goon/sound/machinery/FireAlarm.ogg b/goon/sound/machinery/FireAlarm.ogg
new file mode 100644
index 0000000000..a19fd01ea6
Binary files /dev/null and b/goon/sound/machinery/FireAlarm.ogg differ
diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi
index 9aa9735d55..86530d4608 100644
Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ
diff --git a/icons/mob/belt.dmi b/icons/mob/belt.dmi
index 31a6983b86..c16a14b1ab 100644
Binary files a/icons/mob/belt.dmi and b/icons/mob/belt.dmi differ
diff --git a/icons/mob/belt_mirror.dmi b/icons/mob/belt_mirror.dmi
index 70875774ad..807c684ed9 100644
Binary files a/icons/mob/belt_mirror.dmi and b/icons/mob/belt_mirror.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index dac5dfd819..e53258905e 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 352adcab43..ca33570374 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/obj/food/containers.dmi b/icons/obj/food/containers.dmi
index 0c04e2546d..2672732597 100644
Binary files a/icons/obj/food/containers.dmi and b/icons/obj/food/containers.dmi differ
diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi
index 0eb3441812..1b3f2eecd8 100644
Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ
diff --git a/icons/obj/tank.dmi b/icons/obj/tank.dmi
index 7087814bb8..1c91ecd270 100644
Binary files a/icons/obj/tank.dmi and b/icons/obj/tank.dmi differ
diff --git a/sound/misc/apcdestroyed.ogg b/sound/roundend/apcdestroyed.ogg
similarity index 100%
rename from sound/misc/apcdestroyed.ogg
rename to sound/roundend/apcdestroyed.ogg
diff --git a/sound/misc/bangindonk.ogg b/sound/roundend/bangindonk.ogg
similarity index 100%
rename from sound/misc/bangindonk.ogg
rename to sound/roundend/bangindonk.ogg
diff --git a/sound/misc/disappointed.ogg b/sound/roundend/disappointed.ogg
similarity index 100%
rename from sound/misc/disappointed.ogg
rename to sound/roundend/disappointed.ogg
diff --git a/sound/misc/its_only_game.ogg b/sound/roundend/its_only_game.ogg
similarity index 100%
rename from sound/misc/its_only_game.ogg
rename to sound/roundend/its_only_game.ogg
diff --git a/sound/misc/leavingtg.ogg b/sound/roundend/leavingtg.ogg
similarity index 100%
rename from sound/misc/leavingtg.ogg
rename to sound/roundend/leavingtg.ogg
diff --git a/sound/roundend/newroundsexy.ogg b/sound/roundend/newroundsexy.ogg
new file mode 100644
index 0000000000..afe5630f04
Binary files /dev/null and b/sound/roundend/newroundsexy.ogg differ
diff --git a/sound/misc/yeehaw.ogg b/sound/roundend/yeehaw.ogg
similarity index 100%
rename from sound/misc/yeehaw.ogg
rename to sound/roundend/yeehaw.ogg
diff --git a/strings/soapstone_prefixes.txt b/strings/soapstone_prefixes.txt
deleted file mode 100644
index 728e073983..0000000000
--- a/strings/soapstone_prefixes.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-****
-****?
-****!
-try ****
-**** ahead
-be wary of ****
-need ****
-imminent ****
-weakness: ****
-huh, it's a ****...
-visions of ****....
-could this be a ****?
-time for ****
-praise the ****!
\ No newline at end of file
diff --git a/strings/soapstone_suffixes.json b/strings/soapstone_suffixes.json
deleted file mode 100644
index 2b2ab81a48..0000000000
--- a/strings/soapstone_suffixes.json
+++ /dev/null
@@ -1,234 +0,0 @@
-{
- "Characters": [
- "human",
- "lizard",
- "monkey",
- "xeno",
- "slimeperson",
- "snowflake",
- "enemy",
- "tough enemy",
- "Nanotrasen",
- "Syndicate",
- "skeleton",
- "flier",
- "statue",
- "monster",
- "strange creature",
- "demon",
- "boss",
- "dark spirit",
- "saint",
- "wretch",
- "charmer",
- "miscreant",
- "liar",
- "fatty",
- "beanpole",
- "merchant",
- "prisoner"
- ],
-
- "Careers": [
- "assistant",
- "captain",
- "head of personnel",
- "head of security",
- "warden",
- "security officer",
- "detective",
- "chief engineer",
- "engineer",
- "atmos tech",
- "research director",
- "scientist",
- "robotics",
- "chief medical officer",
- "doctor",
- "chemist",
- "geneticist",
- "virologist",
- "janitor",
- "bartender",
- "cook",
- "clown",
- "mime",
- "chaplain",
- "librarian",
- "quartermaster",
- "cargo tech",
- "miner",
- "lawyer",
- "AI",
- "cyborg",
- "drone",
- "pAI"
- ],
-
- "Antagonists": [
- "traitor",
- "changeling",
- "nuke op",
- "wizard",
- "alien",
- "ghost",
- "blob",
- "cultist",
- "devil"
- ],
-
- "Objects": [
- "airlock",
- "table",
- "rack",
- "weapon",
- "trap",
- "false wall",
- "window",
- "item",
- "loot",
- "teleporter",
- "blueprints",
- "boots",
- "clothes",
- "clothing",
- "drugs",
- "medicine",
- "crate",
- "locker",
- "handcuffs",
- "plant",
- "food",
- "drink",
- "tool",
- "amazing item",
- "amazing loot",
- "amazing clothing",
- "amazing drugs",
- "amazing rack"
- ],
-
- "Techniques": [
- "close-ranged battle",
- "ranged battle",
- "eliminating one at a time",
- "luring it out",
- "beating to a pulp",
- "lying in ambush",
- "stealth",
- "fleeing",
- "charging",
- "stabbing in the back"
- ],
-
- "Actions": [
- "attacking",
- "hacking",
- "sneaking",
- "slipping",
- "running",
- "walking",
- "sprinting",
- "running away",
- "holding with both hands",
- "jumping",
- "restraining",
- "crying",
- "cheering"
- ],
-
- "Geography": [
- "hallway",
- "room",
- "corridor",
- "airlock",
- "space",
- "hidden path",
- "gorgeous view",
- "open area",
- "tight spot",
- "tunnel",
- "dark area",
- "bright area",
- "shuttle",
- "pod",
- "security",
- "arrivals",
- "escape",
- "engineering",
- "atmospherics",
- "medbay",
- "science",
- "brig",
- "prison",
- "asteroid",
- "cargo",
- "mining",
- "cave",
- "maintenance"
- ],
-
- "Orientation": [
- "front",
- "back",
- "left",
- "right",
- "up",
- "down",
- "north",
- "south",
- "east",
- "west",
- "northeast",
- "northwest",
- "southeast",
- "southwest",
- "that way"
- ],
-
- "Body parts": [
- "head",
- "neck",
- "stomach",
- "back",
- "arm",
- "leg",
- "heel",
- "rear",
- "tail",
- "wings",
- "anywhere",
- "everywhere"
- ],
-
- "Concepts": [
- "chance",
- "hint",
- "secret",
- "happiness",
- "sorrow",
- "life",
- "death",
- "elation",
- "grief",
- "hope",
- "despair",
- "light",
- "dark",
- "bravery",
- "resignation",
- "comfort",
- "tears"
- ],
-
- "Musings": [
- "I can't take this...",
- "it'll happen to you too",
- "you don't deserve this",
- "you bastard",
- "you can do it",
- "don't give up",
- "don't you dare",
- "do it"
- ]
-}
\ No newline at end of file