diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000000..2df370e6ea
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,66 @@
+# This list auto requests reviews from the specified org members
+# when a PR that modifies the file in question is opened
+# This list is alphabetized by User -> Filename KEEP IT THAT WAY
+
+# ChangelingRain
+
+/code/__DEFINES/clockcult.dm @ChangelingRain
+/code/datums/antagonists/datum_clockcult.dm @ChangelingRain
+/code/game/gamemodes/blob/* @ChangelingRain
+/code/game/gamemodes/clock_cult/* @ChangelingRain
+/code/game/gamemodes/miniantags/revenant* @ChangelingRain
+/code/game/objects/effects/temporary_visuals/* @ChangelingRain
+/code/modules/reagents/chemistry/reagents/blob_reagents.dm @ChangelingRain
+
+# Cyberboss
+
+/code/__DATASTRUCTURES/globals.dm @Cyberboss
+/code/__DEFINES/components.dm @Cyberboss
+/code/__DEFINES/server_tools.config.dm @Cyberboss
+/code/__DEFINES/server_tools.dm @Cyberboss
+/code/controllers/subsystem/atoms.dm @Cyberboss
+/code/controllers/subsystem/mapping.dm @Cyberboss
+/code/controllers/globals.dm @Cyberboss
+/code/datums/helper_datums/getrev.dm @Cyberboss
+/code/datums/components/* @Cyberboss
+/code/datums/map_config.dm @Cyberboss
+/code/datums/forced_movement.dm @Cyberboss
+/code/datums/holocall.dm @Cyberboss
+/code/modules/admin/verbs/adminhelp.dm @Cyberboss
+/code/modules/admin/verbs/adminpm.dm @Cyberboss
+/code/modules/server_tools/* @Cyberboss
+/code/modules/mapping/* @Cyberboss
+
+# duncathan
+
+/code/__DEFINES/atmospherics.dm @duncathan
+/code/controllers/subsystem/air.dm @duncathan
+/code/modules/atmospherics/* @duncathan
+
+# Jordie0608
+
+/SQL/* @Jordie0608
+/code/controllers/subsystem/dbcore.dm @Jordie0608
+/tools/SQLAlertEmail/* @Jordie0608
+
+# MrStonedOne
+
+/code/__DEFINES/MC.dm @MrStonedOne
+/code/__DEFINES/tick.dm @MrStonedOne
+/code/controllers/admin.dm @MrStonedOne
+/code/controllers/master.dm @MrStonedOne
+/code/controllers/failsafe.dm @MrStonedOne
+/code/controllers/subsystem.dm @MrStonedOne
+/code/controllers/subsystem/air.dm @MrStonedOne
+/code/controllers/subsystem/timer.dm @MrStonedOne
+
+# ninjanomnom
+
+/code/controllers/subsystem/shuttle.dm @ninjanomnom
+/code/modules/shuttle/* @ninjanomnom
+
+# ShizCalev
+
+/_maps/* @ShizCalev
+/icons/* @ShizCalev
+/sound/* @ShizCalev
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 699ab8ffa2..10f60767bb 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,3 +1,9 @@
-[Directions]: # (INCLUDE THE ROUND ID from the Status panel or retrieve it from https://atlantaned.space/newSS13tools/round.php ! If you believe the issue to be caused by a test merge [OOC tab -> Show Server Revision], report it in the pull request's comment section instead. Explain your issue in detail, including the steps to reproduce it.)
+[Directions]: # (If you discovered this issue from playing tgstation hosted servers
+
+
+INCLUDE THE ROUND ID
+
+
+from the Status panel or retrieve it from https://atlantaned.space/statbus/round.php ! If you believe the issue to be caused by a test merge [OOC tab -> Show Server Revision], report it in the pull request's comment section instead. Explain your issue in detail, including the steps to reproduce it.)
[For Admins]: # (Oddities induced by var-edits and other admin tools are not necessarily bugs. Verify that your issues occur under regular circumstances before reporting them.)
diff --git a/README.md b/README.md
index e2b9bbfbbc..b286239314 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,10 @@
-<<<<<<< HEAD
##Citadel Station 13
Based and maintained from /tg/station.
-=======
+
[](https://travis-ci.org/tgstation/tgstation) [](https://www.krihelinator.xyz)
[](https://isitmaintained.com/project/tgstation/tgstation "Percentage of issues still open") [](https://isitmaintained.com/project/tgstation/tgstation "Average time to resolve an issue") 
[](https://forthebadge.com) [](https://forthebadge.com) [](https://www.reddit.com/r/SS13/comments/5oplxp/what_is_the_main_problem_with_byond_as_an_engine/dclbu1a)
->>>>>>> c47dde9... Merge pull request #33172 from praisenarsie/patch-12
[](https://travis-ci.org/Citadel-Station-13/Citadel-Station-13) [](http://www.krihelinator.xyz)
diff --git a/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm b/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm
index 04e9d6ba68..1da57dc70a 100644
--- a/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm
+++ b/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm
@@ -990,7 +990,7 @@
desc = "A thick gelatinous surface covers the floor. Someone get the golashes.";
name = "gelatinous floor"
},
-/mob/living/simple_animal/hostile/creature{
+/mob/living/simple_animal/hostile/netherworld{
desc = "Awh its so sm-OH GOD WHAT THE FUCK.";
health = 25;
maxHealth = 25;
@@ -1010,7 +1010,7 @@
icon_state = "trails_1";
dir = 10
},
-/mob/living/simple_animal/hostile/creature{
+/mob/living/simple_animal/hostile/netherworld{
desc = "Awh its so sm-OH GOD WHAT THE FUCK.";
health = 25;
maxHealth = 25;
@@ -1378,7 +1378,7 @@
desc = "A thick gelatinous surface covers the floor. Someone get the golashes.";
name = "gelatinous floor"
},
-/mob/living/simple_animal/hostile/creature{
+/mob/living/simple_animal/hostile/netherworld{
name = "Miss Tiggles"
},
/turf/open/floor/plasteel,
@@ -1888,7 +1888,7 @@
desc = "A thick gelatinous surface covers the floor. Someone get the golashes.";
name = "gelatinous floor"
},
-/mob/living/simple_animal/hostile/creature{
+/mob/living/simple_animal/hostile/netherworld{
desc = "Awh its so sm-OH GOD WHAT THE FUCK.";
health = 25;
maxHealth = 25;
diff --git a/_maps/RandomZLevels/Academy.dmm b/_maps/RandomZLevels/Academy.dmm
index 4e943346f2..535cb1377c 100644
--- a/_maps/RandomZLevels/Academy.dmm
+++ b/_maps/RandomZLevels/Academy.dmm
@@ -3738,7 +3738,7 @@
/turf/open/floor/vault,
/area/awaymission/academy/academyengine)
"ml" = (
-/mob/living/simple_animal/hostile/creature,
+/mob/living/simple_animal/hostile/netherworld,
/turf/open/floor/vault,
/area/awaymission/academy/academyengine)
"mm" = (
diff --git a/_maps/RandomZLevels/research.dmm b/_maps/RandomZLevels/research.dmm
index 39ffb0c913..5693bd14ff 100644
--- a/_maps/RandomZLevels/research.dmm
+++ b/_maps/RandomZLevels/research.dmm
@@ -4347,7 +4347,7 @@
/turf/open/floor/mineral/plasma,
/area/space/nearstation)
"nc" = (
-/mob/living/simple_animal/hostile/creature,
+/mob/living/simple_animal/hostile/netherworld,
/turf/open/floor/mineral/plasma,
/area/space/nearstation)
"nd" = (
diff --git a/_maps/RandomZLevels/wildwest.dmm b/_maps/RandomZLevels/wildwest.dmm
index 426e68e015..e24d9dcb85 100644
--- a/_maps/RandomZLevels/wildwest.dmm
+++ b/_maps/RandomZLevels/wildwest.dmm
@@ -726,7 +726,7 @@
/turf/open/floor/wood,
/area/awaymission/wildwest/gov)
"cG" = (
-/mob/living/simple_animal/hostile/creature,
+/mob/living/simple_animal/hostile/netherworld,
/turf/open/floor/plasteel/stage_bleft,
/area/awaymission/wildwest/gov)
"cH" = (
@@ -761,7 +761,7 @@
/turf/open/floor/wood,
/area/awaymission/wildwest/gov)
"cN" = (
-/mob/living/simple_animal/hostile/creature,
+/mob/living/simple_animal/hostile/netherworld,
/turf/open/floor/wood,
/area/awaymission/wildwest/gov)
"cO" = (
@@ -771,7 +771,7 @@
/turf/open/floor/wood,
/area/awaymission/wildwest/gov)
"cP" = (
-/mob/living/simple_animal/hostile/creature,
+/mob/living/simple_animal/hostile/netherworld,
/turf/open/floor/carpet,
/area/awaymission/wildwest/gov)
"cQ" = (
@@ -1024,7 +1024,7 @@
/area/awaymission/wildwest/gov)
"dB" = (
/obj/structure/toilet,
-/mob/living/simple_animal/hostile/creature,
+/mob/living/simple_animal/hostile/netherworld,
/turf/open/floor/plasteel/white,
/area/awaymission/wildwest/gov)
"dC" = (
@@ -1941,7 +1941,7 @@
/turf/open/floor/wood,
/area/awaymission/wildwest/mines)
"gn" = (
-/mob/living/simple_animal/hostile/creature,
+/mob/living/simple_animal/hostile/netherworld,
/turf/open/floor/grass,
/area/awaymission/wildwest/gov)
"go" = (
diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm
index 82243073f3..27198fe072 100644
--- a/_maps/map_files/generic/CentCom.dmm
+++ b/_maps/map_files/generic/CentCom.dmm
@@ -9835,7 +9835,7 @@
/area/wizard_station)
"zQ" = (
/obj/effect/decal/cleanable/blood/splatter,
-/mob/living/simple_animal/hostile/creature{
+/mob/living/simple_animal/hostile/netherworld{
name = "Experiment 35b"
},
/turf/open/floor/grass,
diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm
index 2decc918f2..dcdf5aa268 100644
--- a/code/__DEFINES/atom_hud.dm
+++ b/code/__DEFINES/atom_hud.dm
@@ -17,8 +17,9 @@
#define DIAG_TRACK_HUD "13"// Mech tracking beacon
#define DIAG_AIRLOCK_HUD "14"//Airlock shock overlay
#define DIAG_PATH_HUD "15"//Bot path indicators
+#define GLAND_HUD "16"//Gland indicators for abductors
//for antag huds. these are used at the /mob level
-#define ANTAG_HUD "16"
+#define ANTAG_HUD "17"
//by default everything in the hud_list of an atom is an image
//a value in hud_list with one of these will change that behavior
@@ -32,21 +33,22 @@
#define DATA_HUD_MEDICAL_ADVANCED 4
#define DATA_HUD_DIAGNOSTIC_BASIC 5
#define DATA_HUD_DIAGNOSTIC_ADVANCED 6
+#define DATA_HUD_ABDUCTOR 7
//antag HUD defines
-#define ANTAG_HUD_CULT 7
-#define ANTAG_HUD_REV 8
-#define ANTAG_HUD_OPS 9
-#define ANTAG_HUD_WIZ 10
-#define ANTAG_HUD_SHADOW 11
-#define ANTAG_HUD_TRAITOR 12
-#define ANTAG_HUD_NINJA 13
-#define ANTAG_HUD_CHANGELING 14
-#define ANTAG_HUD_ABDUCTOR 15
-#define ANTAG_HUD_DEVIL 16
-#define ANTAG_HUD_SINTOUCHED 17
-#define ANTAG_HUD_SOULLESS 18
-#define ANTAG_HUD_CLOCKWORK 19
-#define ANTAG_HUD_BROTHER 20
+#define ANTAG_HUD_CULT 8
+#define ANTAG_HUD_REV 9
+#define ANTAG_HUD_OPS 10
+#define ANTAG_HUD_WIZ 11
+#define ANTAG_HUD_SHADOW 12
+#define ANTAG_HUD_TRAITOR 13
+#define ANTAG_HUD_NINJA 14
+#define ANTAG_HUD_CHANGELING 15
+#define ANTAG_HUD_ABDUCTOR 16
+#define ANTAG_HUD_DEVIL 17
+#define ANTAG_HUD_SINTOUCHED 18
+#define ANTAG_HUD_SOULLESS 19
+#define ANTAG_HUD_CLOCKWORK 20
+#define ANTAG_HUD_BROTHER 21
// Notification action types
#define NOTIFY_JUMP "jump"
diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index 87c226b839..0b2a3e06d4 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -61,6 +61,8 @@
#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob)
#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" //from base of obj/item/attack_obj(): (/obj, /mob)
+#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot)
+#define COMSIG_ITEM_DROPPED "item_drop" //from base of obj/item/dropped(): (/mob/dropper)
// /obj/item/clothing signals
#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
@@ -77,7 +79,6 @@
#define COMSIG_MACHINE_PROCESS "machine_process" //from machinery subsystem fire(): ()
#define COMSIG_MACHINE_PROCESS_ATMOS "machine_process_atmos" //from air subsystem process_atmos_machinery(): ()
-
// /mob/living/carbon/human signals
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
diff --git a/code/__DEFINES/configuration.dm b/code/__DEFINES/configuration.dm
index 3db0ca24c2..c4ef8e6606 100644
--- a/code/__DEFINES/configuration.dm
+++ b/code/__DEFINES/configuration.dm
@@ -1,8 +1,6 @@
//config files
-#define CONFIG_DEF(X) /datum/config_entry/##X { resident_file = CURRENT_RESIDENT_FILE }; /datum/config_entry/##X
#define CONFIG_GET(X) global.config.Get(/datum/config_entry/##X)
#define CONFIG_SET(X, Y) global.config.Set(/datum/config_entry/##X, ##Y)
-#define CONFIG_TWEAK(X) /datum/config_entry/##X
#define CONFIG_MAPS_FILE "maps.txt"
diff --git a/code/__DEFINES/server_tools.config.dm b/code/__DEFINES/server_tools.config.dm
new file mode 100644
index 0000000000..7d3c5b8eba
--- /dev/null
+++ b/code/__DEFINES/server_tools.config.dm
@@ -0,0 +1,8 @@
+#define SERVER_TOOLS_EXTERNAL_CONFIGURATION
+#define SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(Name, Value) GLOBAL_VAR_INIT(##Name, ##Value); GLOBAL_PROTECT(##Name)
+#define SERVER_TOOLS_READ_GLOBAL(Name) GLOB.##Name
+#define SERVER_TOOLS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value
+#define SERVER_TOOLS_WORLD_ANNOUNCE(message) to_chat(world, "[html_encode(##message)]")
+#define SERVER_TOOLS_LOG(message) log_world("SERVICE: [##message]")
+#define SERVER_TOOLS_NOTIFY_ADMINS(event) message_admins(##event)
+#define SERVER_TOOLS_CLIENT_COUNT GLOB.clients.len
diff --git a/code/__DEFINES/server_tools.dm b/code/__DEFINES/server_tools.dm
index 9547c381c1..c0fc133ada 100644
--- a/code/__DEFINES/server_tools.dm
+++ b/code/__DEFINES/server_tools.dm
@@ -1,4 +1,5 @@
-// /tg/station 13 server tools API v3.1.0.2
+// /tg/station 13 server tools API
+#define SERVICE_API_VERSION_STRING "3.2.0.1"
//CONFIGURATION
//use this define if you want to do configuration outside of this file
@@ -10,19 +11,19 @@
//create a global variable named `Name` and set it to `Value`
//These globals must not be modifiable from anywhere outside of the server tools
-#define SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(Name, Value) GLOBAL_VAR_INIT(##Name, ##Value); GLOBAL_PROTECT(##Name)
+#define SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(Name, Value)
//Read the value in the global variable `Name`
-#define SERVER_TOOLS_READ_GLOBAL(Name) GLOB.##Name
+#define SERVER_TOOLS_READ_GLOBAL(Name)
//Set the value in the global variable `Name` to `Value`
-#define SERVER_TOOLS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value
+#define SERVER_TOOLS_WRITE_GLOBAL(Name, Value)
//display an announcement `message` from the server to all players
-#define SERVER_TOOLS_WORLD_ANNOUNCE(message) to_chat(world, "[html_encode(##message)]")
+#define SERVER_TOOLS_WORLD_ANNOUNCE(message)
//Write a string `message` to a server log
-#define SERVER_TOOLS_LOG(message) log_world("SERVICE: [##message]")
+#define SERVER_TOOLS_LOG(message)
//Notify current in-game administrators of a string `event`
-#define SERVER_TOOLS_NOTIFY_ADMINS(event) message_admins(##event)
+#define SERVER_TOOLS_NOTIFY_ADMINS(event)
//The current amount of connected clients
-#define SERVER_TOOLS_CLIENT_COUNT GLOB.clients.len
+#define SERVER_TOOLS_CLIENT_COUNT
#endif
//Required hooks:
@@ -64,16 +65,15 @@
//IMPLEMENTATION
-#define SERVICE_API_VERSION_STRING "3.1.0.2"
-
#define REBOOT_MODE_NORMAL 0
#define REBOOT_MODE_HARD 1
#define REBOOT_MODE_SHUTDOWN 2
#define SERVICE_WORLD_PARAM "server_service"
#define SERVICE_VERSION_PARAM "server_service_version"
+#define SERVICE_INSTANCE_PARAM "server_instance"
#define SERVICE_PR_TEST_JSON "prtestjob.json"
-#define SERVICE_INTERFACE_DLL "TGServiceInterface.dll"
+#define SERVICE_INTERFACE_DLL "TGDreamDaemonBridge.dll"
#define SERVICE_INTERFACE_FUNCTION "DDEntryPoint"
#define SERVICE_CMD_HARD_REBOOT "hard_reboot"
@@ -98,11 +98,12 @@
#define SERVICE_REQUEST_WORLD_REBOOT "worldreboot"
#define SERVICE_REQUEST_API_VERSION "api_ver"
+#define SERVICE_RETURN_SUCCESS "SUCCESS"
+
/*
The MIT License
-Copyright (c) 2011 Dominic Tarr
-
+Copyright (c) 2017 Jordan Brown
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"), to
diff --git a/code/citadel/cit_weapons.dm b/code/citadel/cit_weapons.dm
deleted file mode 100644
index dbf0448240..0000000000
--- a/code/citadel/cit_weapons.dm
+++ /dev/null
@@ -1,240 +0,0 @@
-/obj/item/toy/sword/cx
- name = "\improper DX Non-Euplastic LightSword"
- desc = "A deluxe toy replica of an energy sword. Realistic visuals and sounds! Ages 8 and up."
- icon = 'icons/obj/cit_weapons.dmi'
- icon_state = "cxsword_hilt"
- item_state = "cxsword"
- lefthand_file = 'icons/mob/citadel/melee_lefthand.dmi'
- righthand_file = 'icons/mob/citadel/melee_righthand.dmi'
- active = FALSE
- w_class = WEIGHT_CLASS_SMALL
- attack_verb = list("poked", "jabbed", "hit")
- light_color = "#37FFF7"
- var/light_brightness = 3
- actions_types = list()
-
-/obj/item/toy/sword/cx/attack_self(mob/user)
- active = !( active )
-
- if (active)
- to_chat(user, "You activate the holographic blade with a press of a button.")
- playsound(user, 'sound/weapons/nebon.ogg', 50, 1)
- w_class = WEIGHT_CLASS_BULKY
- attack_verb = list("slashed", "stabbed", "ravaged")
- set_light(light_brightness)
- update_icon()
-
- else
- to_chat(user, "You deactivate the holographic blade with a press of a button.")
- playsound(user, 'sound/weapons/neboff.ogg', 50, 1)
- w_class = WEIGHT_CLASS_SMALL
- attack_verb = list("poked", "jabbed", "hit")
- set_light(0)
- update_icon()
-
- for(var/X in actions)
- var/datum/action/A = X
- A.UpdateButtonIcon()
-
- add_fingerprint(user)
-
-/obj/item/toy/sword/cx/update_icon()
- var/mutable_appearance/blade_overlay = mutable_appearance('icons/obj/cit_weapons.dmi', "cxsword_blade")
- var/mutable_appearance/gem_overlay = mutable_appearance('icons/obj/cit_weapons.dmi', "cxsword_gem")
-
- if(light_color)
- blade_overlay.color = light_color
- gem_overlay.color = light_color
-
- cut_overlays() //So that it doesn't keep stacking overlays non-stop on top of each other
-
- add_overlay(gem_overlay)
-
- if(active)
- add_overlay(blade_overlay)
-
- if(ismob(loc))
- var/mob/M = loc
- M.update_inv_hands()
-
-/obj/item/toy/sword/cx/AltClick(mob/living/user)
- if(user.incapacitated() || !istype(user))
- to_chat(user, "You can't do that right now!")
- return
- if(!in_range(src, user))
- return
- if(user.incapacitated() || !istype(user) || !in_range(src, user))
- return
-
- if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
- var/energy_color_input = input(usr,"Choose Energy Color") as color|null
- if(energy_color_input)
- light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
- update_icon()
- update_light()
-
-/obj/item/toy/sword/cx/worn_overlays(isinhands, icon_file)
- . = ..()
- if(active)
- if(isinhands)
- var/mutable_appearance/blade_inhand = mutable_appearance(icon_file, "cxsword_blade")
- blade_inhand.color = light_color
- . += blade_inhand
-
-/obj/item/toy/sword/cx/attackby(obj/item/W, mob/living/user, params)
- if(istype(W, /obj/item/toy/sword/cx))
- if((W.flags_1 & NODROP_1) || (flags_1 & NODROP_1))
- to_chat(user, "\the [flags_1 & NODROP_1 ? src : W] is stuck to your hand, you can't attach it to \the [flags_1 & NODROP_1 ? W : src]!")
- return
- else
- to_chat(user, "You combine the two plastic swords, making a single supermassive toy! You're fake-cool.")
- new /obj/item/twohanded/hypereutactic/toy(user.loc)
- qdel(W)
- qdel(src)
- else
- return ..()
-
-/obj/item/toy/sword/cx/examine(mob/user)
- ..()
- to_chat(user, "Alt-click to recolor it.")
-
-/*///autolathe memes/// I really need to stop doing this and find a proper way of adding in my toys
-
-/datum/design/toyneb
- name = "Non-Euplastic Blade"
- id = "toyneb"
- build_type = AUTOLATHE
- materials = list(MAT_METAL = 10000, MAT_GLASS = 1000)
- build_path = /obj/item/toy/sword/cx
- category = list("hacked", "Misc")
-*/ // There, I stopped doing it
-
-/datum/crafting_recipe/toyneb
- name = "Non-Euplastic Blade"
- reqs = list(/obj/item/light/bulb = 1, /obj/item/stack/cable_coil = 1, /obj/item/toy/sword = 1)
- result = /obj/item/toy/sword/cx
- category = CAT_MISC
-
-/*/////////////////////////////////////////////////////////////////////////
-///////////// The TRUE Energy Sword ///////////////////////////
-*//////////////////////////////////////////////////////////////////////////
-
-/obj/item/melee/transforming/energy/sword/cx
- name = "non-eutactic blade"
- desc = "The CX Armories Type-69 Non-Eutactic Blade utilizes a hardlight blade that is dynamically 'forged' on demand to create a deadly sharp edge that is unbreakable."
- icon_state = "cxsword_hilt"
- icon = 'icons/obj/cit_weapons.dmi'
- item_state = "cxsword"
- lefthand_file = 'icons/mob/citadel/melee_lefthand.dmi'
- righthand_file = 'icons/mob/citadel/melee_righthand.dmi'
- force = 3
- throwforce = 5
- hitsound = "swing_hit" //it starts deactivated
- hitsound_on = 'sound/weapons/nebhit.ogg'
- attack_verb_off = list("tapped", "poked")
- throw_speed = 3
- throw_range = 5
- sharpness = IS_SHARP
- embed_chance = 40
- embedded_impact_pain_multiplier = 10
- armour_penetration = 0
- block_chance = 60
- light_color = "#37FFF7"
- actions_types = list()
-
-/obj/item/melee/transforming/energy/sword/cx/transform_weapon(mob/living/user, supress_message_text)
- active = !active //I'd use a ..() here but it'd inherit from the regular esword's proc instead, so SPAGHETTI CODE
- if(active) //also I need to rip out the iconstate changing bits
- force = force_on
- throwforce = throwforce_on
- hitsound = hitsound_on
- throw_speed = 4
- if(attack_verb_on.len)
- attack_verb = attack_verb_on
- w_class = w_class_on
- START_PROCESSING(SSobj, src)
- set_light(brightness_on)
- update_icon()
- else
- force = initial(force)
- throwforce = initial(throwforce)
- hitsound = initial(hitsound)
- throw_speed = initial(throw_speed)
- if(attack_verb_off.len)
- attack_verb = attack_verb_off
- w_class = initial(w_class)
- STOP_PROCESSING(SSobj, src)
- set_light(0)
- update_icon()
- transform_messages(user, supress_message_text)
- add_fingerprint(user)
- return TRUE
-
-/obj/item/melee/transforming/energy/sword/cx/transform_messages(mob/living/user, supress_message_text)
- playsound(user, active ? 'sound/weapons/nebon.ogg' : 'sound/weapons/neboff.ogg', 65, 1)
- if(!supress_message_text)
- to_chat(user, "[src] [active ? "is now active":"can now be concealed"].")
-
-/obj/item/melee/transforming/energy/sword/cx/update_icon()
- var/mutable_appearance/blade_overlay = mutable_appearance('icons/obj/cit_weapons.dmi', "cxsword_blade")
- var/mutable_appearance/gem_overlay = mutable_appearance('icons/obj/cit_weapons.dmi', "cxsword_gem")
-
- if(light_color)
- blade_overlay.color = light_color
- gem_overlay.color = light_color
-
- cut_overlays() //So that it doesn't keep stacking overlays non-stop on top of each other
-
- add_overlay(gem_overlay)
-
- if(active)
- add_overlay(blade_overlay)
-
- if(ismob(loc))
- var/mob/M = loc
- M.update_inv_hands()
-
-/obj/item/melee/transforming/energy/sword/cx/AltClick(mob/living/user)
- if(user.incapacitated() || !istype(user))
- to_chat(user, "You can't do that right now!")
- return
- if(!in_range(src, user))
- return
- if(user.incapacitated() || !istype(user) || !in_range(src, user))
- return
-
- if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
- var/energy_color_input = input(usr,"Choose Energy Color") as color|null
- if(energy_color_input)
- light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
- update_icon()
- update_light()
-
-/obj/item/melee/transforming/energy/sword/cx/examine(mob/user)
- ..()
- to_chat(user, "Alt-click to recolor it.")
-
-/obj/item/melee/transforming/energy/sword/cx/worn_overlays(isinhands, icon_file)
- . = ..()
- if(active)
- if(isinhands)
- var/mutable_appearance/blade_inhand = mutable_appearance(icon_file, "cxsword_blade")
- blade_inhand.color = light_color
- . += blade_inhand
-
-/obj/item/melee/transforming/energy/sword/cx/traitor
- name = "\improper Dragon's Tooth Sword"
- desc = "The Dragon's Tooth sword is a blackmarket modification of the CX Armouries Type-69 NEB, \
- which utilizes a hardlight blade that is dynamically 'forged' on demand to create a deadly sharp edge that is unbreakable. \
- It appears to have a wooden grip and a shaved down guard."
- icon_state = "cxsword_hilt_traitor"
- armour_penetration = 35
- embed_chance = 75
- block_chance = 50
- hitsound_on = 'sound/weapons/blade1.ogg'
- light_color = "#37F0FF"
-
-/obj/item/melee/transforming/energy/sword/cx/traitor/transform_messages(mob/living/user, supress_message_text)
- playsound(user, active ? 'sound/weapons/saberon.ogg' : 'sound/weapons/saberoff.ogg', 35, 1)
- if(!supress_message_text)
- to_chat(user, "[src] [active ? "is now active":"can now be concealed"].")
\ No newline at end of file
diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm
index 804060aaa8..d2db743d91 100644
--- a/code/controllers/configuration/config_entry.dm
+++ b/code/controllers/configuration/config_entry.dm
@@ -9,7 +9,7 @@
var/value
var/default //read-only, just set value directly
- var/resident_file //the file which this belongs to, must be set
+ var/resident_file //the file which this was loaded from, if any
var/modified = FALSE //set to TRUE if the default has been overridden by a config entry
var/protection = NONE
@@ -18,8 +18,6 @@
var/dupes_allowed = FALSE
/datum/config_entry/New()
- if(!resident_file)
- CRASH("Config entry [type] has no resident_file set")
if(type == abstract_type)
CRASH("Abstract config entry [type] instatiated!")
name = lowertext(type2top(type))
diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index e9c0aa71b8..f411bd65d3 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -20,10 +20,13 @@ GLOBAL_PROTECT(config_dir)
/datum/controller/configuration/New()
config = src
- var/list/config_files = InitEntries()
+ InitEntries()
LoadModes()
- for(var/I in config_files)
- LoadEntries(I)
+ if(!LoadEntries("config.txt"))
+ log_config("No $include directives found in config.txt! Loading legacy game_options/dbconfig/comms files...")
+ LoadEntries("game_options.txt")
+ LoadEntries("dbconfig.txt")
+ LoadEntries("comms.txt")
loadmaplist(CONFIG_MAPS_FILE)
/datum/controller/configuration/Destroy()
@@ -42,8 +45,6 @@ GLOBAL_PROTECT(config_dir)
var/list/_entries_by_type = list()
entries_by_type = _entries_by_type
- . = list()
-
for(var/I in typesof(/datum/config_entry)) //typesof is faster in this case
var/datum/config_entry/E = I
if(initial(E.abstract_type) == I)
@@ -57,24 +58,30 @@ GLOBAL_PROTECT(config_dir)
continue
_entries[esname] = E
_entries_by_type[I] = E
- .[E.resident_file] = TRUE
/datum/controller/configuration/proc/RemoveEntry(datum/config_entry/CE)
entries -= CE.name
entries_by_type -= CE.type
-/datum/controller/configuration/proc/LoadEntries(filename)
+/datum/controller/configuration/proc/LoadEntries(filename, list/stack = list())
+ var/filename_to_test = world.system_type == MS_WINDOWS ? lowertext(filename) : filename
+ if(filename_to_test in stack)
+ log_config("Warning: Config recursion detected ([english_list(stack)]), breaking!")
+ return
+ stack = stack + filename_to_test
+
log_config("Loading config file [filename]...")
var/list/lines = world.file2list("[GLOB.config_dir][filename]")
var/list/_entries = entries
for(var/L in lines)
if(!L)
continue
-
- if(copytext(L, 1, 2) == "#")
+
+ var/firstchar = copytext(L, 1, 2)
+ if(firstchar == "#")
continue
- var/lockthis = copytext(L, 1, 2) == "@"
+ var/lockthis = firstchar == "@"
if(lockthis)
L = copytext(L, 2)
@@ -91,14 +98,17 @@ GLOBAL_PROTECT(config_dir)
if(!entry)
continue
+ if(entry == "$include")
+ if(!value)
+ log_config("Warning: Invalid $include directive: [value]")
+ else
+ LoadEntries(value, stack)
+ continue
+
var/datum/config_entry/E = _entries[entry]
if(!E)
log_config("Unknown setting in configuration: '[entry]'")
continue
-
- if(filename != E.resident_file)
- log_config("Found [entry] in [filename] when it should have been in [E.resident_file]! Ignoring.")
- continue
if(lockthis)
E.protection |= CONFIG_ENTRY_LOCKED
@@ -107,10 +117,14 @@ GLOBAL_PROTECT(config_dir)
if(!validated)
log_config("Failed to validate setting \"[value]\" for [entry]")
else if(E.modified && !E.dupes_allowed)
- log_config("Duplicate setting for [entry] ([value]) detected! Using latest.")
+ log_config("Duplicate setting for [entry] ([value], [E.resident_file]) detected! Using latest.")
+
+ E.resident_file = filename
if(validated)
E.modified = TRUE
+
+ . = TRUE
/datum/controller/configuration/can_vv_get(var_name)
return (var_name != "entries_by_type" || !hiding_entries_by_type) && ..()
diff --git a/code/controllers/configuration/entries/comms.dm b/code/controllers/configuration/entries/comms.dm
index bf099f6cb6..56cec985f1 100644
--- a/code/controllers/configuration/entries/comms.dm
+++ b/code/controllers/configuration/entries/comms.dm
@@ -1,22 +1,20 @@
-#define CURRENT_RESIDENT_FILE "comms.txt"
-
-CONFIG_DEF(string/comms_key)
+/datum/config_entry/string/comms_key
protection = CONFIG_ENTRY_HIDDEN
/datum/config_entry/string/comms_key/ValidateAndSet(str_val)
return str_val != "default_pwd" && length(str_val) > 6 && ..()
-CONFIG_DEF(string/cross_server_address)
+/datum/config_entry/keyed_string_list/cross_server
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/cross_server_address/ValidateAndSet(str_val)
return str_val != "byond:\\address:port" && ..()
-CONFIG_DEF(string/cross_comms_name)
+/datum/config_entry/string/cross_comms_name
GLOBAL_VAR_INIT(medals_enabled, TRUE) //will be auto set to false if the game fails contacting the medal hub to prevent unneeded calls.
-CONFIG_DEF(string/medal_hub_address)
+/datum/config_entry/string/medal_hub_address
-CONFIG_DEF(string/medal_hub_password)
- protection = CONFIG_ENTRY_HIDDEN
\ No newline at end of file
+/datum/config_entry/string/medal_hub_password
+ protection = CONFIG_ENTRY_HIDDEN
diff --git a/code/controllers/configuration/entries/config.dm b/code/controllers/configuration/entries/config.dm
deleted file mode 100644
index 37081c15dd..0000000000
--- a/code/controllers/configuration/entries/config.dm
+++ /dev/null
@@ -1,390 +0,0 @@
-#define CURRENT_RESIDENT_FILE "config.txt"
-
-CONFIG_DEF(flag/autoadmin) // if autoadmin is enabled
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(string/autoadmin_rank) // the rank for autoadmins
- value = "Game Master"
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(string/servername) // server name (the name of the game window)
-
-CONFIG_DEF(string/serversqlname) // short form server name used for the DB
-
-CONFIG_DEF(string/stationname) // station name (the name of the station in-game)
-
-CONFIG_DEF(number/lobby_countdown) // In between round countdown.
- value = 120
- min_val = 0
-
-CONFIG_DEF(number/round_end_countdown) // Post round murder death kill countdown
- value = 25
- min_val = 0
-
-CONFIG_DEF(flag/hub) // if the game appears on the hub or not
-
-CONFIG_DEF(flag/log_ooc) // log OOC channel
-
-CONFIG_DEF(flag/log_access) // log login/logout
-
-CONFIG_DEF(flag/log_say) // log client say
-
-CONFIG_DEF(flag/log_admin) // log admin actions
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(flag/log_prayer) // log prayers
-
-CONFIG_DEF(flag/log_law) // log lawchanges
-
-CONFIG_DEF(flag/log_game) // log game events
-
-CONFIG_DEF(flag/log_vote) // log voting
-
-CONFIG_DEF(flag/log_whisper) // log client whisper
-
-CONFIG_DEF(flag/log_attack) // log attack messages
-
-CONFIG_DEF(flag/log_emote) // log emotes
-
-CONFIG_DEF(flag/log_adminchat) // log admin chat messages
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(flag/log_pda) // log pda messages
-
-CONFIG_DEF(flag/log_twitter) // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
-
-CONFIG_DEF(flag/log_world_topic) // log all world.Topic() calls
-
-CONFIG_DEF(flag/log_manifest) // log crew manifest to seperate file
-
-CONFIG_DEF(flag/allow_admin_ooccolor) // Allows admins with relevant permissions to have their own ooc colour
-
-CONFIG_DEF(flag/allow_vote_restart) // allow votes to restart
-
-CONFIG_DEF(flag/allow_vote_mode) // allow votes to change mode
-
-CONFIG_DEF(number/vote_delay) // minimum time between voting sessions (deciseconds, 10 minute default)
- value = 6000
- min_val = 0
-
-CONFIG_DEF(number/vote_period) // length of voting period (deciseconds, default 1 minute)
- value = 600
- min_val = 0
-
-CONFIG_DEF(flag/default_no_vote) // vote does not default to nochange/norestart
-
-CONFIG_DEF(flag/no_dead_vote) // dead people can't vote
-
-CONFIG_DEF(flag/allow_metadata) // Metadata is supported.
-
-CONFIG_DEF(flag/popup_admin_pm) // adminPMs to non-admins show in a pop-up 'reply' window when set
-
-CONFIG_DEF(number/fps)
- value = 20
- min_val = 1
- max_val = 100 //byond will start crapping out at 50, so this is just ridic
- var/sync_validate = FALSE
-
-/datum/config_entry/number/fps/ValidateAndSet(str_val)
- . = ..()
- if(.)
- sync_validate = TRUE
- var/datum/config_entry/number/ticklag/TL = config.entries_by_type[/datum/config_entry/number/ticklag]
- if(!TL.sync_validate)
- TL.ValidateAndSet(10 / value)
- sync_validate = FALSE
-
-CONFIG_DEF(number/ticklag)
- integer = FALSE
- var/sync_validate = FALSE
-
-/datum/config_entry/number/ticklag/New() //ticklag weirdly just mirrors fps
- var/datum/config_entry/CE = /datum/config_entry/number/fps
- value = 10 / initial(CE.value)
- ..()
-
-/datum/config_entry/number/ticklag/ValidateAndSet(str_val)
- . = text2num(str_val) > 0 && ..()
- if(.)
- sync_validate = TRUE
- var/datum/config_entry/number/fps/FPS = config.entries_by_type[/datum/config_entry/number/fps]
- if(!FPS.sync_validate)
- FPS.ValidateAndSet(10 / value)
- sync_validate = FALSE
-
-CONFIG_DEF(flag/allow_holidays)
-
-CONFIG_DEF(number/tick_limit_mc_init) //SSinitialization throttling
- value = TICK_LIMIT_MC_INIT_DEFAULT
- min_val = 0 //oranges warned us
- integer = FALSE
-
-CONFIG_DEF(flag/admin_legacy_system) //Defines whether the server uses the legacy admin system with admins.txt or the SQL system
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(string/hostedby)
-
-CONFIG_DEF(flag/norespawn)
-
-CONFIG_DEF(flag/guest_jobban)
-
-CONFIG_DEF(flag/usewhitelist)
-
-CONFIG_DEF(flag/ban_legacy_system) //Defines whether the server uses the legacy banning system with the files in /data or the SQL system.
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(flag/use_age_restriction_for_jobs) //Do jobs use account age restrictions? --requires database
-
-CONFIG_DEF(flag/use_account_age_for_jobs) //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
-
-CONFIG_DEF(flag/use_exp_tracking)
-
-CONFIG_DEF(flag/use_exp_restrictions_heads)
-
-CONFIG_DEF(number/use_exp_restrictions_heads_hours)
- value = 0
- min_val = 0
-
-CONFIG_DEF(flag/use_exp_restrictions_heads_department)
-
-CONFIG_DEF(flag/use_exp_restrictions_other)
-
-CONFIG_DEF(flag/use_exp_restrictions_admin_bypass)
-
-CONFIG_DEF(string/server)
-
-CONFIG_DEF(string/banappeals)
-
-CONFIG_DEF(string/wikiurl)
- value = "http://www.tgstation13.org/wiki"
-
-CONFIG_DEF(string/forumurl)
- value = "http://tgstation13.org/phpBB/index.php"
-
-CONFIG_DEF(string/rulesurl)
- value = "http://www.tgstation13.org/wiki/Rules"
-
-CONFIG_DEF(string/githuburl)
- value = "https://www.github.com/tgstation/-tg-station"
-
-CONFIG_DEF(number/githubrepoid)
- value = null
- min_val = 0
-
-CONFIG_DEF(flag/guest_ban)
-
-CONFIG_DEF(number/id_console_jobslot_delay)
- value = 30
- min_val = 0
-
-CONFIG_DEF(number/inactivity_period) //time in ds until a player is considered inactive)
- value = 3000
- min_val = 0
-
-/datum/config_entry/number/inactivity_period/ValidateAndSet(str_val)
- . = ..()
- if(.)
- value *= 10 //documented as seconds in config.txt
-
-CONFIG_DEF(number/afk_period) //time in ds until a player is considered inactive)
- value = 3000
- min_val = 0
-
-/datum/config_entry/number/afk_period/ValidateAndSet(str_val)
- . = ..()
- if(.)
- value *= 10 //documented as seconds in config.txt
-
-CONFIG_DEF(flag/kick_inactive) //force disconnect for inactive players
-
-CONFIG_DEF(flag/load_jobs_from_txt)
-
-CONFIG_DEF(flag/forbid_singulo_possession)
-
-CONFIG_DEF(flag/automute_on) //enables automuting/spam prevention
-
-CONFIG_DEF(string/panic_server_name)
-
-/datum/config_entry/string/panic_server_name/ValidateAndSet(str_val)
- return str_val != "\[Put the name here\]" && ..()
-
-CONFIG_DEF(string/panic_server_address) //Reconnect a player this linked server if this server isn't accepting new players
-
-/datum/config_entry/string/panic_server_address/ValidateAndSet(str_val)
- return str_val != "byond://address:port" && ..()
-
-CONFIG_DEF(string/invoke_youtubedl)
- protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-
-CONFIG_DEF(flag/show_irc_name)
-
-CONFIG_DEF(flag/see_own_notes) //Can players see their own admin notes (read-only)?
-
-CONFIG_DEF(number/note_fresh_days)
- value = null
- min_val = 0
- integer = FALSE
-
-CONFIG_DEF(number/note_stale_days)
- value = null
- min_val = 0
- integer = FALSE
-
-CONFIG_DEF(flag/maprotation)
-
-CONFIG_DEF(number/maprotatechancedelta)
- value = 0.75
- min_val = 0
- max_val = 1
- integer = FALSE
-
-CONFIG_DEF(number/soft_popcap)
- value = null
- min_val = 0
-
-CONFIG_DEF(number/hard_popcap)
- value = null
- min_val = 0
-
-CONFIG_DEF(number/extreme_popcap)
- value = null
- min_val = 0
-
-CONFIG_DEF(string/soft_popcap_message)
- value = "Be warned that the server is currently serving a high number of users, consider using alternative game servers."
-
-CONFIG_DEF(string/hard_popcap_message)
- value = "The server is currently serving a high number of users, You cannot currently join. You may wait for the number of living crew to decline, observe, or find alternative servers."
-
-CONFIG_DEF(string/extreme_popcap_message)
- value = "The server is currently serving a high number of users, find alternative servers."
-
-CONFIG_DEF(flag/panic_bunker) // prevents people the server hasn't seen before from connecting
-
-CONFIG_DEF(number/notify_new_player_age) // how long do we notify admins of a new player
- min_val = -1
-
-CONFIG_DEF(number/notify_new_player_account_age) // how long do we notify admins of a new byond account
- min_val = 0
-
-CONFIG_DEF(flag/irc_first_connection_alert) // do we notify the irc channel when somebody is connecting for the first time?
-
-CONFIG_DEF(flag/check_randomizer)
-
-CONFIG_DEF(string/ipintel_email)
-
-/datum/config_entry/string/ipintel_email/ValidateAndSet(str_val)
- return str_val != "ch@nge.me" && ..()
-
-CONFIG_DEF(number/ipintel_rating_bad)
- value = 1
- integer = FALSE
- min_val = 0
- max_val = 1
-
-CONFIG_DEF(number/ipintel_save_good)
- value = 12
- min_val = 0
-
-CONFIG_DEF(number/ipintel_save_bad)
- value = 1
- min_val = 0
-
-CONFIG_DEF(string/ipintel_domain)
- value = "check.getipintel.net"
-
-CONFIG_DEF(flag/aggressive_changelog)
-
-CONFIG_DEF(flag/autoconvert_notes) //if all connecting player's notes should attempt to be converted to the database
- protection = CONFIG_ENTRY_LOCKED
-
-CONFIG_DEF(flag/allow_webclient)
-
-CONFIG_DEF(flag/webclient_only_byond_members)
-
-CONFIG_DEF(flag/announce_admin_logout)
-
-CONFIG_DEF(flag/announce_admin_login)
-
-CONFIG_DEF(flag/allow_map_voting)
-
-CONFIG_DEF(flag/generate_minimaps)
-
-CONFIG_DEF(number/client_warn_version)
- value = null
- min_val = 500
- max_val = DM_VERSION - 1
-
-CONFIG_DEF(string/client_warn_message)
- value = "Your version of byond may have issues or be blocked from accessing this server in the future."
-
-CONFIG_DEF(flag/client_warn_popup)
-
-CONFIG_DEF(number/client_error_version)
- value = null
- min_val = 500
- max_val = DM_VERSION - 1
-
-CONFIG_DEF(string/client_error_message)
- value = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
-
-CONFIG_DEF(number/minute_topic_limit)
- value = null
- min_val = 0
-
-CONFIG_DEF(number/second_topic_limit)
- value = null
- min_val = 0
-
-CONFIG_DEF(number/error_cooldown) // The "cooldown" time for each occurrence of a unique error)
- value = 600
- min_val = 0
-
-CONFIG_DEF(number/error_limit) // How many occurrences before the next will silence them
- value = 50
-
-CONFIG_DEF(number/error_silence_time) // How long a unique error will be silenced for
- value = 6000
-
-CONFIG_DEF(number/error_msg_delay) // How long to wait between messaging admins about occurrences of a unique error
- value = 50
-
-CONFIG_DEF(flag/irc_announce_new_game)
-
-CONFIG_DEF(flag/debug_admin_hrefs)
-
-CONFIG_DEF(number/mc_tick_rate/base_mc_tick_rate)
- integer = FALSE
- value = 1
-
-CONFIG_DEF(number/mc_tick_rate/high_pop_mc_tick_rate)
- integer = FALSE
- value = 1.1
-
-CONFIG_DEF(number/mc_tick_rate/high_pop_mc_mode_amount)
- value = 65
-
-CONFIG_DEF(number/mc_tick_rate/disable_high_pop_mc_mode_amount)
- value = 60
-
-CONFIG_TWEAK(number/mc_tick_rate)
- abstract_type = /datum/config_entry/number/mc_tick_rate
-
-CONFIG_TWEAK(number/mc_tick_rate/ValidateAndSet(str_val))
- . = ..()
- if (.)
- Master.UpdateTickRate()
-
-CONFIG_DEF(flag/resume_after_initializations)
-
-CONFIG_TWEAK(flag/resume_after_initializations/ValidateAndSet(str_val))
- . = ..()
- if(. && Master.current_runlevel)
- world.sleep_offline = !value
-
-CONFIG_DEF(number/rounds_until_hard_restart)
- value = -1
- min_val = 0
-
-CONFIG_DEF(string/default_view)
- value = "15x15"
diff --git a/code/controllers/configuration/entries/dbconfig.dm b/code/controllers/configuration/entries/dbconfig.dm
index c46880686a..1ac4d85419 100644
--- a/code/controllers/configuration/entries/dbconfig.dm
+++ b/code/controllers/configuration/entries/dbconfig.dm
@@ -1,28 +1,26 @@
-#define CURRENT_RESIDENT_FILE "dbconfig.txt"
-
-CONFIG_DEF(flag/sql_enabled) // for sql switching
+/datum/config_entry/flag/sql_enabled // for sql switching
protection = CONFIG_ENTRY_LOCKED
-CONFIG_DEF(string/address)
+/datum/config_entry/string/address
value = "localhost"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-CONFIG_DEF(number/port)
+/datum/config_entry/number/port
value = 3306
min_val = 0
max_val = 65535
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-CONFIG_DEF(string/feedback_database)
+/datum/config_entry/string/feedback_database
value = "test"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-CONFIG_DEF(string/feedback_login)
+/datum/config_entry/string/feedback_login
value = "root"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-CONFIG_DEF(string/feedback_password)
+/datum/config_entry/string/feedback_password
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-CONFIG_DEF(string/feedback_tableprefix)
+/datum/config_entry/string/feedback_tableprefix
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index b04d7845f5..2d96e3c64b 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -1,253 +1,255 @@
-#define CURRENT_RESIDENT_FILE "game_options.txt"
+/datum/config_entry/number_list/repeated_mode_adjust
-CONFIG_DEF(number_list/repeated_mode_adjust)
-
-CONFIG_DEF(keyed_number_list/probability)
+/datum/config_entry/keyed_number_list/probability
/datum/config_entry/keyed_number_list/probability/ValidateKeyName(key_name)
return key_name in config.modes
-CONFIG_DEF(keyed_number_list/max_pop)
+/datum/config_entry/keyed_number_list/max_pop
/datum/config_entry/keyed_number_list/max_pop/ValidateKeyName(key_name)
return key_name in config.modes
-CONFIG_DEF(keyed_number_list/min_pop)
+/datum/config_entry/keyed_number_list/min_pop
/datum/config_entry/keyed_number_list/min_pop/ValidateKeyName(key_name)
return key_name in config.modes
-CONFIG_DEF(keyed_flag_list/continuous) // which roundtypes continue if all antagonists die
+/datum/config_entry/keyed_flag_list/continuous // which roundtypes continue if all antagonists die
/datum/config_entry/keyed_flag_list/continuous/ValidateKeyName(key_name)
return key_name in config.modes
-CONFIG_DEF(keyed_flag_list/midround_antag) // which roundtypes use the midround antagonist system
+/datum/config_entry/keyed_flag_list/midround_antag // which roundtypes use the midround antagonist system
/datum/config_entry/keyed_flag_list/midround_antag/ValidateKeyName(key_name)
return key_name in config.modes
-CONFIG_DEF(keyed_string_list/policy)
+/datum/config_entry/keyed_string_list/policy
-CONFIG_DEF(number/damage_multiplier)
+/datum/config_entry/number/damage_multiplier
value = 1
integer = FALSE
-CONFIG_DEF(number/minimal_access_threshold) //If the number of players is larger than this threshold, minimal access will be turned on.
+/datum/config_entry/number/minimal_access_threshold //If the number of players is larger than this threshold, minimal access will be turned on.
min_val = 0
-CONFIG_DEF(flag/jobs_have_minimal_access) //determines whether jobs use minimal access or expanded access.
+/datum/config_entry/flag/jobs_have_minimal_access //determines whether jobs use minimal access or expanded access.
-CONFIG_DEF(flag/assistants_have_maint_access)
+/datum/config_entry/flag/assistants_have_maint_access
-CONFIG_DEF(flag/security_has_maint_access)
+/datum/config_entry/flag/security_has_maint_access
-CONFIG_DEF(flag/everyone_has_maint_access)
+/datum/config_entry/flag/everyone_has_maint_access
-CONFIG_DEF(flag/sec_start_brig) //makes sec start in brig instead of dept sec posts
+/datum/config_entry/flag/sec_start_brig //makes sec start in brig instead of dept sec posts
-CONFIG_DEF(flag/force_random_names)
+/datum/config_entry/flag/force_random_names
-CONFIG_DEF(flag/humans_need_surnames)
+/datum/config_entry/flag/humans_need_surnames
-CONFIG_DEF(flag/allow_ai) // allow ai job
+/datum/config_entry/flag/allow_ai // allow ai job
-CONFIG_DEF(flag/disable_secborg) // disallow secborg module to be chosen.
+/datum/config_entry/flag/disable_secborg // disallow secborg module to be chosen.
-CONFIG_DEF(flag/disable_peaceborg)
+/datum/config_entry/flag/disable_peaceborg
-CONFIG_DEF(number/traitor_scaling_coeff) //how much does the amount of players get divided by to determine traitors
+/datum/config_entry/number/traitor_scaling_coeff //how much does the amount of players get divided by to determine traitors
value = 6
min_val = 1
-CONFIG_DEF(number/brother_scaling_coeff) //how many players per brother team
+/datum/config_entry/number/brother_scaling_coeff //how many players per brother team
value = 25
min_val = 1
-CONFIG_DEF(number/changeling_scaling_coeff) //how much does the amount of players get divided by to determine changelings
+/datum/config_entry/number/changeling_scaling_coeff //how much does the amount of players get divided by to determine changelings
value = 6
min_val = 1
-CONFIG_DEF(number/security_scaling_coeff) //how much does the amount of players get divided by to determine open security officer positions
+/datum/config_entry/number/security_scaling_coeff //how much does the amount of players get divided by to determine open security officer positions
value = 8
min_val = 1
-CONFIG_DEF(number/abductor_scaling_coeff) //how many players per abductor team
+/datum/config_entry/number/abductor_scaling_coeff //how many players per abductor team
value = 15
min_val = 1
-CONFIG_DEF(number/traitor_objectives_amount)
+/datum/config_entry/number/traitor_objectives_amount
value = 2
min_val = 0
-CONFIG_DEF(number/brother_objectives_amount)
+/datum/config_entry/number/brother_objectives_amount
value = 2
min_val = 0
-CONFIG_DEF(flag/reactionary_explosions) //If we use reactionary explosions, explosions that react to walls and doors
+/datum/config_entry/flag/reactionary_explosions //If we use reactionary explosions, explosions that react to walls and doors
-CONFIG_DEF(flag/protect_roles_from_antagonist) //If security and such can be traitor/cult/other
+/datum/config_entry/flag/protect_roles_from_antagonist //If security and such can be traitor/cult/other
-CONFIG_DEF(flag/protect_assistant_from_antagonist) //If assistants can be traitor/cult/other
+/datum/config_entry/flag/protect_assistant_from_antagonist //If assistants can be traitor/cult/other
-CONFIG_DEF(flag/enforce_human_authority) //If non-human species are barred from joining as a head of staff
+/datum/config_entry/flag/enforce_human_authority //If non-human species are barred from joining as a head of staff
-CONFIG_DEF(flag/allow_latejoin_antagonists) // If late-joining players can be traitor/changeling
+/datum/config_entry/flag/allow_latejoin_antagonists // If late-joining players can be traitor/changeling
-CONFIG_DEF(number/midround_antag_time_check) // How late (in minutes) you want the midround antag system to stay on, setting this to 0 will disable the system
+/datum/config_entry/number/midround_antag_time_check // How late (in minutes you want the midround antag system to stay on, setting this to 0 will disable the system)
value = 60
min_val = 0
-CONFIG_DEF(number/midround_antag_life_check) // A ratio of how many people need to be alive in order for the round not to immediately end in midround antagonist
+/datum/config_entry/number/midround_antag_life_check // A ratio of how many people need to be alive in order for the round not to immediately end in midround antagonist
value = 0.7
integer = FALSE
min_val = 0
max_val = 1
-CONFIG_DEF(number/shuttle_refuel_delay)
+/datum/config_entry/number/shuttle_refuel_delay
value = 12000
min_val = 0
-CONFIG_DEF(flag/show_game_type_odds) //if set this allows players to see the odds of each roundtype on the get revision screen
+/datum/config_entry/flag/show_game_type_odds //if set this allows players to see the odds of each roundtype on the get revision screen
-CONFIG_DEF(keyed_flag_list/roundstart_races) //races you can play as from the get go.
+/datum/config_entry/keyed_flag_list/roundstart_races //races you can play as from the get go.
-CONFIG_DEF(flag/join_with_mutant_humans) //players can pick mutant bodyparts for humans before joining the game
+/datum/config_entry/flag/join_with_mutant_humans //players can pick mutant bodyparts for humans before joining the game
-CONFIG_DEF(flag/no_summon_guns) //No
+/datum/config_entry/flag/no_summon_guns //No
-CONFIG_DEF(flag/no_summon_magic) //Fun
+/datum/config_entry/flag/no_summon_magic //Fun
-CONFIG_DEF(flag/no_summon_events) //Allowed
+/datum/config_entry/flag/no_summon_events //Allowed
-CONFIG_DEF(flag/no_intercept_report) //Whether or not to send a communications intercept report roundstart. This may be overriden by gamemodes.
+/datum/config_entry/flag/no_intercept_report //Whether or not to send a communications intercept report roundstart. This may be overriden by gamemodes.
-CONFIG_DEF(number/arrivals_shuttle_dock_window) //Time from when a player late joins on the arrivals shuttle to when the shuttle docks on the station
+/datum/config_entry/number/arrivals_shuttle_dock_window //Time from when a player late joins on the arrivals shuttle to when the shuttle docks on the station
value = 55
min_val = 30
-CONFIG_DEF(flag/arrivals_shuttle_require_undocked) //Require the arrivals shuttle to be undocked before latejoiners can join
+/datum/config_entry/flag/arrivals_shuttle_require_undocked //Require the arrivals shuttle to be undocked before latejoiners can join
-CONFIG_DEF(flag/arrivals_shuttle_require_safe_latejoin) //Require the arrivals shuttle to be operational in order for latejoiners to join
+/datum/config_entry/flag/arrivals_shuttle_require_safe_latejoin //Require the arrivals shuttle to be operational in order for latejoiners to join
-CONFIG_DEF(string/alert_green)
+/datum/config_entry/string/alert_green
value = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced."
-CONFIG_DEF(string/alert_blue_upto)
+/datum/config_entry/string/alert_blue_upto
value = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted."
-CONFIG_DEF(string/alert_blue_downto)
+/datum/config_entry/string/alert_blue_downto
value = "The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed."
-CONFIG_DEF(string/alert_red_upto)
+/datum/config_entry/string/alert_red_upto
value = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised."
-CONFIG_DEF(string/alert_red_downto)
+/datum/config_entry/string/alert_red_downto
value = "The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised."
-CONFIG_DEF(string/alert_delta)
+/datum/config_entry/string/alert_delta
value = "Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
-CONFIG_DEF(flag/revival_pod_plants)
+/datum/config_entry/flag/revival_pod_plants
-CONFIG_DEF(flag/revival_cloning)
+/datum/config_entry/flag/revival_cloning
-CONFIG_DEF(number/revival_brain_life)
+/datum/config_entry/number/revival_brain_life
value = -1
min_val = -1
-CONFIG_DEF(flag/rename_cyborg)
+/datum/config_entry/flag/rename_cyborg
-CONFIG_DEF(flag/ooc_during_round)
+/datum/config_entry/flag/ooc_during_round
-CONFIG_DEF(flag/emojis)
+/datum/config_entry/flag/emojis
-CONFIG_DEF(number/run_delay) //Used for modifying movement speed for mobs.
+/datum/config_entry/number/run_delay //Used for modifying movement speed for mobs.
var/static/value_cache = 0
-CONFIG_TWEAK(number/run_delay/ValidateAndSet())
+/datum/config_entry/number/run_delay/ValidateAndSet()
. = ..()
if(.)
value_cache = value
-CONFIG_DEF(number/walk_delay)
+/datum/config_entry/number/walk_delay
var/static/value_cache = 0
-CONFIG_TWEAK(number/walk_delay/ValidateAndSet())
+/datum/config_entry/number/walk_delay/ValidateAndSet()
. = ..()
if(.)
value_cache = value
-CONFIG_DEF(number/human_delay) //Mob specific modifiers. NOTE: These will affect different mob types in different ways
-CONFIG_DEF(number/robot_delay)
-CONFIG_DEF(number/monkey_delay)
-CONFIG_DEF(number/alien_delay)
-CONFIG_DEF(number/slime_delay)
-CONFIG_DEF(number/animal_delay)
+/datum/config_entry/number/human_delay //Mob specific modifiers. NOTE: These will affect different mob types in different ways
+/datum/config_entry/number/robot_delay
+/datum/config_entry/number/monkey_delay
+/datum/config_entry/number/alien_delay
+/datum/config_entry/number/slime_delay
+/datum/config_entry/number/animal_delay
-CONFIG_DEF(number/gateway_delay) //How long the gateway takes before it activates. Default is half an hour.
+/datum/config_entry/number/gateway_delay //How long the gateway takes before it activates. Default is half an hour.
value = 18000
min_val = 0
-CONFIG_DEF(flag/ghost_interaction)
+/datum/config_entry/flag/ghost_interaction
-CONFIG_DEF(flag/silent_ai)
-CONFIG_DEF(flag/silent_borg)
+/datum/config_entry/flag/silent_ai
+/datum/config_entry/flag/silent_borg
-CONFIG_DEF(flag/sandbox_autoclose) // close the sandbox panel after spawning an item, potentially reducing griff
+/datum/config_entry/flag/sandbox_autoclose // close the sandbox panel after spawning an item, potentially reducing griff
-CONFIG_DEF(number/default_laws) //Controls what laws the AI spawns with.
+/datum/config_entry/number/default_laws //Controls what laws the AI spawns with.
value = 0
min_val = 0
max_val = 3
-CONFIG_DEF(number/silicon_max_law_amount)
+/datum/config_entry/number/silicon_max_law_amount
value = 12
min_val = 0
-CONFIG_DEF(keyed_flag_list/random_laws)
+/datum/config_entry/keyed_flag_list/random_laws
-CONFIG_DEF(keyed_number_list/law_weight)
+/datum/config_entry/keyed_number_list/law_weight
splitter = ","
-CONFIG_DEF(number/assistant_cap)
+/datum/config_entry/number/assistant_cap
value = -1
min_val = -1
-CONFIG_DEF(flag/starlight)
-CONFIG_DEF(flag/grey_assistants)
+/datum/config_entry/flag/starlight
+/datum/config_entry/flag/grey_assistants
-CONFIG_DEF(number/lavaland_budget)
+/datum/config_entry/number/lavaland_budget
value = 60
min_val = 0
-CONFIG_DEF(number/space_budget)
+/datum/config_entry/number/space_budget
value = 16
min_val = 0
-CONFIG_DEF(flag/allow_random_events) // Enables random events mid-round when set
+/datum/config_entry/flag/allow_random_events // Enables random events mid-round when set
-CONFIG_DEF(number/events_min_time_mul) // Multipliers for random events minimal starting time and minimal players amounts
+/datum/config_entry/number/events_min_time_mul // Multipliers for random events minimal starting time and minimal players amounts
value = 1
min_val = 0
integer = FALSE
-CONFIG_DEF(number/events_min_players_mul)
+/datum/config_entry/number/events_min_players_mul
value = 1
min_val = 0
integer = FALSE
-CONFIG_DEF(number/mice_roundstart)
+/datum/config_entry/number/mice_roundstart
value = 10
min_val = 0
-CONFIG_DEF(number/bombcap)
+/datum/config_entry/number/bombcap
value = 14
min_val = 4
-CONFIG_DEF(flag/allow_crew_objectives)
-CONFIG_DEF(flag/allow_miscreants)
-CONFIG_DEF(flag/allow_extended_miscreants)
+//Cit changes - Adds config options for crew objectives and miscreants
+/datum/config_entry/flag/allow_crew_objectives
+
+/datum/config_entry/flag/allow_miscreants
+
+/datum/config_entry/flag/allow_extended_miscreants
+//End of Cit changes
/datum/config_entry/number/bombcap/ValidateAndSet(str_val)
. = ..()
@@ -258,9 +260,9 @@ CONFIG_DEF(flag/allow_extended_miscreants)
GLOB.MAX_EX_FLASH_RANGE = value
GLOB.MAX_EX_FLAME_RANGE = value
-CONFIG_DEF(number/emergency_shuttle_autocall_threshold)
+/datum/config_entry/number/emergency_shuttle_autocall_threshold
min_val = 0
max_val = 1
integer = FALSE
-CONFIG_DEF(flag/ic_printing)
+/datum/config_entry/flag/ic_printing
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
new file mode 100644
index 0000000000..637e65c46f
--- /dev/null
+++ b/code/controllers/configuration/entries/general.dm
@@ -0,0 +1,388 @@
+/datum/config_entry/flag/autoadmin // if autoadmin is enabled
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/string/autoadmin_rank // the rank for autoadmins
+ value = "Game Master"
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/string/servername // server name (the name of the game window)
+
+/datum/config_entry/string/serversqlname // short form server name used for the DB
+
+/datum/config_entry/string/stationname // station name (the name of the station in-game)
+
+/datum/config_entry/number/lobby_countdown // In between round countdown.
+ value = 120
+ min_val = 0
+
+/datum/config_entry/number/round_end_countdown // Post round murder death kill countdown
+ value = 25
+ min_val = 0
+
+/datum/config_entry/flag/hub // if the game appears on the hub or not
+
+/datum/config_entry/flag/log_ooc // log OOC channel
+
+/datum/config_entry/flag/log_access // log login/logout
+
+/datum/config_entry/flag/log_say // log client say
+
+/datum/config_entry/flag/log_admin // log admin actions
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/flag/log_prayer // log prayers
+
+/datum/config_entry/flag/log_law // log lawchanges
+
+/datum/config_entry/flag/log_game // log game events
+
+/datum/config_entry/flag/log_vote // log voting
+
+/datum/config_entry/flag/log_whisper // log client whisper
+
+/datum/config_entry/flag/log_attack // log attack messages
+
+/datum/config_entry/flag/log_emote // log emotes
+
+/datum/config_entry/flag/log_adminchat // log admin chat messages
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/flag/log_pda // log pda messages
+
+/datum/config_entry/flag/log_twitter // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
+
+/datum/config_entry/flag/log_world_topic // log all world.Topic() calls
+
+/datum/config_entry/flag/log_manifest // log crew manifest to seperate file
+
+/datum/config_entry/flag/allow_admin_ooccolor // Allows admins with relevant permissions to have their own ooc colour
+
+/datum/config_entry/flag/allow_vote_restart // allow votes to restart
+
+/datum/config_entry/flag/allow_vote_mode // allow votes to change mode
+
+/datum/config_entry/number/vote_delay // minimum time between voting sessions (deciseconds, 10 minute default)
+ value = 6000
+ min_val = 0
+
+/datum/config_entry/number/vote_period // length of voting period (deciseconds, default 1 minute)
+ value = 600
+ min_val = 0
+
+/datum/config_entry/flag/default_no_vote // vote does not default to nochange/norestart
+
+/datum/config_entry/flag/no_dead_vote // dead people can't vote
+
+/datum/config_entry/flag/allow_metadata // Metadata is supported.
+
+/datum/config_entry/flag/popup_admin_pm // adminPMs to non-admins show in a pop-up 'reply' window when set
+
+/datum/config_entry/number/fps
+ value = 20
+ min_val = 1
+ max_val = 100 //byond will start crapping out at 50, so this is just ridic
+ var/sync_validate = FALSE
+
+/datum/config_entry/number/fps/ValidateAndSet(str_val)
+ . = ..()
+ if(.)
+ sync_validate = TRUE
+ var/datum/config_entry/number/ticklag/TL = config.entries_by_type[/datum/config_entry/number/ticklag]
+ if(!TL.sync_validate)
+ TL.ValidateAndSet(10 / value)
+ sync_validate = FALSE
+
+/datum/config_entry/number/ticklag
+ integer = FALSE
+ var/sync_validate = FALSE
+
+/datum/config_entry/number/ticklag/New() //ticklag weirdly just mirrors fps
+ var/datum/config_entry/CE = /datum/config_entry/number/fps
+ value = 10 / initial(CE.value)
+ ..()
+
+/datum/config_entry/number/ticklag/ValidateAndSet(str_val)
+ . = text2num(str_val) > 0 && ..()
+ if(.)
+ sync_validate = TRUE
+ var/datum/config_entry/number/fps/FPS = config.entries_by_type[/datum/config_entry/number/fps]
+ if(!FPS.sync_validate)
+ FPS.ValidateAndSet(10 / value)
+ sync_validate = FALSE
+
+/datum/config_entry/flag/allow_holidays
+
+/datum/config_entry/number/tick_limit_mc_init //SSinitialization throttling
+ value = TICK_LIMIT_MC_INIT_DEFAULT
+ min_val = 0 //oranges warned us
+ integer = FALSE
+
+/datum/config_entry/flag/admin_legacy_system //Defines whether the server uses the legacy admin system with admins.txt or the SQL system
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/string/hostedby
+
+/datum/config_entry/flag/norespawn
+
+/datum/config_entry/flag/guest_jobban
+
+/datum/config_entry/flag/usewhitelist
+
+/datum/config_entry/flag/ban_legacy_system //Defines whether the server uses the legacy banning system with the files in /data or the SQL system.
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/flag/use_age_restriction_for_jobs //Do jobs use account age restrictions? --requires database
+
+/datum/config_entry/flag/use_account_age_for_jobs //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
+
+/datum/config_entry/flag/use_exp_tracking
+
+/datum/config_entry/flag/use_exp_restrictions_heads
+
+/datum/config_entry/number/use_exp_restrictions_heads_hours
+ value = 0
+ min_val = 0
+
+/datum/config_entry/flag/use_exp_restrictions_heads_department
+
+/datum/config_entry/flag/use_exp_restrictions_other
+
+/datum/config_entry/flag/use_exp_restrictions_admin_bypass
+
+/datum/config_entry/string/server
+
+/datum/config_entry/string/banappeals
+
+/datum/config_entry/string/wikiurl
+ value = "http://www.tgstation13.org/wiki"
+
+/datum/config_entry/string/forumurl
+ value = "http://tgstation13.org/phpBB/index.php"
+
+/datum/config_entry/string/rulesurl
+ value = "http://www.tgstation13.org/wiki/Rules"
+
+/datum/config_entry/string/githuburl
+ value = "https://www.github.com/tgstation/-tg-station"
+
+/datum/config_entry/number/githubrepoid
+ value = null
+ min_val = 0
+
+/datum/config_entry/flag/guest_ban
+
+/datum/config_entry/number/id_console_jobslot_delay
+ value = 30
+ min_val = 0
+
+/datum/config_entry/number/inactivity_period //time in ds until a player is considered inactive
+ value = 3000
+ min_val = 0
+
+/datum/config_entry/number/inactivity_period/ValidateAndSet(str_val)
+ . = ..()
+ if(.)
+ value *= 10 //documented as seconds in config.txt
+
+/datum/config_entry/number/afk_period //time in ds until a player is considered inactive
+ value = 3000
+ min_val = 0
+
+/datum/config_entry/number/afk_period/ValidateAndSet(str_val)
+ . = ..()
+ if(.)
+ value *= 10 //documented as seconds in config.txt
+
+/datum/config_entry/flag/kick_inactive //force disconnect for inactive players
+
+/datum/config_entry/flag/load_jobs_from_txt
+
+/datum/config_entry/flag/forbid_singulo_possession
+
+/datum/config_entry/flag/automute_on //enables automuting/spam prevention
+
+/datum/config_entry/string/panic_server_name
+
+/datum/config_entry/string/panic_server_name/ValidateAndSet(str_val)
+ return str_val != "\[Put the name here\]" && ..()
+
+/datum/config_entry/string/panic_server_address //Reconnect a player this linked server if this server isn't accepting new players
+
+/datum/config_entry/string/panic_server_address/ValidateAndSet(str_val)
+ return str_val != "byond://address:port" && ..()
+
+/datum/config_entry/string/invoke_youtubedl
+ protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
+
+/datum/config_entry/flag/show_irc_name
+
+/datum/config_entry/flag/see_own_notes //Can players see their own admin notes
+
+/datum/config_entry/number/note_fresh_days
+ value = null
+ min_val = 0
+ integer = FALSE
+
+/datum/config_entry/number/note_stale_days
+ value = null
+ min_val = 0
+ integer = FALSE
+
+/datum/config_entry/flag/maprotation
+
+/datum/config_entry/number/maprotatechancedelta
+ value = 0.75
+ min_val = 0
+ max_val = 1
+ integer = FALSE
+
+/datum/config_entry/number/soft_popcap
+ value = null
+ min_val = 0
+
+/datum/config_entry/number/hard_popcap
+ value = null
+ min_val = 0
+
+/datum/config_entry/number/extreme_popcap
+ value = null
+ min_val = 0
+
+/datum/config_entry/string/soft_popcap_message
+ value = "Be warned that the server is currently serving a high number of users, consider using alternative game servers."
+
+/datum/config_entry/string/hard_popcap_message
+ value = "The server is currently serving a high number of users, You cannot currently join. You may wait for the number of living crew to decline, observe, or find alternative servers."
+
+/datum/config_entry/string/extreme_popcap_message
+ value = "The server is currently serving a high number of users, find alternative servers."
+
+/datum/config_entry/flag/panic_bunker // prevents people the server hasn't seen before from connecting
+
+/datum/config_entry/number/notify_new_player_age // how long do we notify admins of a new player
+ min_val = -1
+
+/datum/config_entry/number/notify_new_player_account_age // how long do we notify admins of a new byond account
+ min_val = 0
+
+/datum/config_entry/flag/irc_first_connection_alert // do we notify the irc channel when somebody is connecting for the first time?
+
+/datum/config_entry/flag/check_randomizer
+
+/datum/config_entry/string/ipintel_email
+
+/datum/config_entry/string/ipintel_email/ValidateAndSet(str_val)
+ return str_val != "ch@nge.me" && ..()
+
+/datum/config_entry/number/ipintel_rating_bad
+ value = 1
+ integer = FALSE
+ min_val = 0
+ max_val = 1
+
+/datum/config_entry/number/ipintel_save_good
+ value = 12
+ min_val = 0
+
+/datum/config_entry/number/ipintel_save_bad
+ value = 1
+ min_val = 0
+
+/datum/config_entry/string/ipintel_domain
+ value = "check.getipintel.net"
+
+/datum/config_entry/flag/aggressive_changelog
+
+/datum/config_entry/flag/autoconvert_notes //if all connecting player's notes should attempt to be converted to the database
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/flag/allow_webclient
+
+/datum/config_entry/flag/webclient_only_byond_members
+
+/datum/config_entry/flag/announce_admin_logout
+
+/datum/config_entry/flag/announce_admin_login
+
+/datum/config_entry/flag/allow_map_voting
+
+/datum/config_entry/flag/generate_minimaps
+
+/datum/config_entry/number/client_warn_version
+ value = null
+ min_val = 500
+ max_val = DM_VERSION - 1
+
+/datum/config_entry/string/client_warn_message
+ value = "Your version of byond may have issues or be blocked from accessing this server in the future."
+
+/datum/config_entry/flag/client_warn_popup
+
+/datum/config_entry/number/client_error_version
+ value = null
+ min_val = 500
+ max_val = DM_VERSION - 1
+
+/datum/config_entry/string/client_error_message
+ value = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
+
+/datum/config_entry/number/minute_topic_limit
+ value = null
+ min_val = 0
+
+/datum/config_entry/number/second_topic_limit
+ value = null
+ min_val = 0
+
+/datum/config_entry/number/error_cooldown // The "cooldown" time for each occurrence of a unique error
+ value = 600
+ min_val = 0
+
+/datum/config_entry/number/error_limit // How many occurrences before the next will silence them
+ value = 50
+
+/datum/config_entry/number/error_silence_time // How long a unique error will be silenced for
+ value = 6000
+
+/datum/config_entry/number/error_msg_delay // How long to wait between messaging admins about occurrences of a unique error
+ value = 50
+
+/datum/config_entry/flag/irc_announce_new_game
+
+/datum/config_entry/flag/debug_admin_hrefs
+
+/datum/config_entry/number/mc_tick_rate/base_mc_tick_rate
+ integer = FALSE
+ value = 1
+
+/datum/config_entry/number/mc_tick_rate/high_pop_mc_tick_rate
+ integer = FALSE
+ value = 1.1
+
+/datum/config_entry/number/mc_tick_rate/high_pop_mc_mode_amount
+ value = 65
+
+/datum/config_entry/number/mc_tick_rate/disable_high_pop_mc_mode_amount
+ value = 60
+
+/datum/config_entry/number/mc_tick_rate
+ abstract_type = /datum/config_entry/number/mc_tick_rate
+
+/datum/config_entry/number/mc_tick_rate/ValidateAndSet(str_val)
+ . = ..()
+ if (.)
+ Master.UpdateTickRate()
+
+/datum/config_entry/flag/resume_after_initializations
+
+/datum/config_entry/flag/resume_after_initializations/ValidateAndSet(str_val)
+ . = ..()
+ if(. && Master.current_runlevel)
+ world.sleep_offline = !value
+
+/datum/config_entry/number/rounds_until_hard_restart
+ value = -1
+ min_val = 0
+
+/datum/config_entry/string/default_view
+ value = "15x15"
diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm
new file mode 100644
index 0000000000..5dbb642f2e
--- /dev/null
+++ b/code/controllers/subsystem/input.dm
@@ -0,0 +1,12 @@
+SUBSYSTEM_DEF(input)
+ name = "Input"
+ wait = 1 //SS_TICKER means this runs every tick
+ flags = SS_TICKER | SS_NO_INIT
+ priority = 1000
+ runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
+
+/datum/controller/subsystem/input/fire()
+ var/list/clients = GLOB.clients // Let's sing the list cache song
+ for(var/i in 1 to clients.len)
+ var/client/C = clients[i]
+ C.keyLoop()
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index c80bc17047..35208d4137 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -307,6 +307,9 @@ SUBSYSTEM_DEF(shuttle)
return 1
/datum/controller/subsystem/shuttle/proc/autoEvac()
+ if (!SSticker.IsRoundInProgress())
+ return
+
var/callShuttle = 1
for(var/thing in GLOB.shuttle_caller_list)
diff --git a/code/datums/components/jousting.dm b/code/datums/components/jousting.dm
new file mode 100644
index 0000000000..68621e60ec
--- /dev/null
+++ b/code/datums/components/jousting.dm
@@ -0,0 +1,81 @@
+/datum/component/jousting
+ var/current_direction = NONE
+ var/max_tile_charge = 5
+ var/min_tile_charge = 2 //tiles before this code gets into effect.
+ var/current_tile_charge = 0
+ var/movement_reset_tolerance = 2 //deciseconds
+ var/unmounted_damage_boost_per_tile = 0
+ var/unmounted_knockdown_chance_per_tile = 0
+ var/unmounted_knockdown_time = 0
+ var/mounted_damage_boost_per_tile = 2
+ var/mounted_knockdown_chance_per_tile = 20
+ var/mounted_knockdown_time = 20
+ var/requires_mob_riding = TRUE //whether this only works if the attacker is riding a mob, rather than anything they can buckle to.
+ var/requires_mount = TRUE //kinda defeats the point of jousting if you're not mounted but whatever.
+ var/mob/current_holder
+ var/datum/component/redirect/listener
+ var/current_timerid
+
+/datum/component/jousting/Initialize()
+ if(!isitem(parent))
+ . = COMPONENT_INCOMPATIBLE
+ stack_trace("Warning: Jousting component incorrectly applied to invalid parent type [parent.type]")
+ RegisterSignal(COMSIG_ITEM_EQUIPPED, .proc/on_equip)
+ RegisterSignal(COMSIG_ITEM_DROPPED, .proc/on_drop)
+ RegisterSignal(COMSIG_ITEM_ATTACK, .proc/on_attack)
+
+/datum/component/jousting/Destroy()
+ QDEL_NULL(listener)
+ return ..()
+
+/datum/component/jousting/proc/on_equip(mob/user, slot)
+ QDEL_NULL(listener)
+ current_holder = user
+ listener = new(user, COMSIG_MOVABLE_MOVED, CALLBACK(src, .proc/mob_move))
+
+/datum/component/jousting/proc/on_drop(mob/user)
+ QDEL_NULL(listener)
+ current_holder = null
+ current_direction = NONE
+ current_tile_charge = 0
+
+/datum/component/jousting/proc/on_attack(mob/living/target, mob/user)
+ if(user != current_holder)
+ return
+ var/current = current_tile_charge
+ var/obj/item/I = parent
+ var/target_buckled = target.buckled ? TRUE : FALSE //we don't need the reference of what they're buckled to, just whether they are.
+ if((requires_mount && ((requires_mob_riding && !ismob(user.buckled)) || (!user.buckled))) || !current_direction || (current_tile_charge < min_tile_charge))
+ return
+ var/turf/target_turf = get_step(user, current_direction)
+ if(target in range(1, target_turf))
+ var/knockdown_chance = (target_buckled? mounted_knockdown_chance_per_tile : unmounted_knockdown_chance_per_tile) * current
+ var/knockdown_time = (target_buckled? mounted_knockdown_time : unmounted_knockdown_time)
+ var/damage = (target_buckled? mounted_damage_boost_per_tile : unmounted_damage_boost_per_tile) * current
+ var/sharp = I.is_sharp()
+ var/msg
+ if(damage)
+ msg += "[user] [sharp? "impales" : "slams into"] [target] [sharp? "on" : "with"] their [parent]"
+ target.apply_damage(damage, BRUTE, user.zone_selected, 0)
+ if(prob(knockdown_chance))
+ msg += " and knocks [target] [target_buckled? "off of [target.buckled]" : "down"]"
+ if(target_buckled)
+ target.buckled.unbuckle_mob(target)
+ target.Knockdown(knockdown_time)
+ if(length(msg))
+ user.visible_message("[msg]!")
+
+/datum/component/jousting/proc/mob_move(newloc, dir)
+ if(!current_holder || (requires_mount && ((requires_mob_riding && !ismob(current_holder.buckled)) || (!current_holder.buckled))))
+ return
+ if(dir != current_direction)
+ current_tile_charge = 0
+ current_direction = dir
+ if(current_tile_charge < max_tile_charge)
+ current_tile_charge++
+ if(current_timerid)
+ deltimer(current_timerid)
+ current_timerid = addtimer(CALLBACK(src, .proc/reset_charge), movement_reset_tolerance, TIMER_STOPPABLE)
+
+/datum/component/jousting/proc/reset_charge()
+ current_tile_charge = 0
diff --git a/code/datums/hud.dm b/code/datums/hud.dm
index 837e7a6a95..fc6c09be14 100644
--- a/code/datums/hud.dm
+++ b/code/datums/hud.dm
@@ -10,6 +10,7 @@ GLOBAL_LIST_INIT(huds, list(
DATA_HUD_MEDICAL_ADVANCED = new/datum/atom_hud/data/human/medical/advanced(),
DATA_HUD_DIAGNOSTIC_BASIC = new/datum/atom_hud/data/diagnostic/basic(),
DATA_HUD_DIAGNOSTIC_ADVANCED = new/datum/atom_hud/data/diagnostic/advanced(),
+ DATA_HUD_ABDUCTOR = new/datum/atom_hud/abductor(),
ANTAG_HUD_CULT = new/datum/atom_hud/antag(),
ANTAG_HUD_REV = new/datum/atom_hud/antag(),
ANTAG_HUD_OPS = new/datum/atom_hud/antag(),
diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm
index 562311180d..b84133faf7 100644
--- a/code/datums/looping_sounds/machinery_sounds.dm
+++ b/code/datums/looping_sounds/machinery_sounds.dm
@@ -32,7 +32,7 @@
mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1)
mid_length = 2
end_sound = 'sound/machines/fryer/deep_fryer_emerge.ogg'
- volume = 25
+ volume = 15
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 3e0f0112ff..121ac00f1d 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -414,7 +414,7 @@
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
if(!buckled_mob.Move(newloc, direct))
- loc = buckled_mob.loc
+ forceMove(buckled_mob.loc)
last_move = buckled_mob.last_move
inertia_dir = last_move
buckled_mob.inertia_dir = last_move
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index 1afd2953a0..74ac93c023 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -60,6 +60,9 @@
/datum/atom_hud/data/bot_path
hud_icons = list(DIAG_PATH_HUD)
+/datum/atom_hud/abductor
+ hud_icons = list(GLAND_HUD)
+
/* MED/SEC/DIAG HUD HOOKS */
/*
diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm
index c0516fa2dd..878b747ea9 100644
--- a/code/game/gamemodes/blob/overmind.dm
+++ b/code/game/gamemodes/blob/overmind.dm
@@ -215,12 +215,12 @@ GLOBAL_LIST_EMPTY(blob_nodes)
if(placed)
var/obj/structure/blob/B = locate() in range("3x3", NewLoc)
if(B)
- loc = NewLoc
+ forceMove(NewLoc)
else
return 0
else
var/area/A = get_area(NewLoc)
if(isspaceturf(NewLoc) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
return 0
- loc = NewLoc
+ forceMove(NewLoc)
return 1
diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm
index aa1a3e7046..2ef047506f 100644
--- a/code/game/gamemodes/blob/powers.dm
+++ b/code/game/gamemodes/blob/powers.dm
@@ -42,7 +42,7 @@
return 0
else if(placement_override == 1)
var/turf/T = pick(GLOB.blobstart)
- loc = T //got overrided? you're somewhere random, motherfucker
+ forceMove(T) //got overrided? you're somewhere random, motherfucker
if(placed && blob_core)
blob_core.forceMove(loc)
else
@@ -74,7 +74,7 @@
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
var/obj/structure/blob/node/chosen_node = nodes[node_name]
if(chosen_node)
- loc = chosen_node.loc
+ forceMove(chosen_node.loc)
/mob/camera/blob/proc/createSpecial(price, blobType, nearEquals, needsNode, turf/T)
if(!T)
diff --git a/code/game/gamemodes/clock_cult/clock_helpers/power_helpers.dm b/code/game/gamemodes/clock_cult/clock_helpers/power_helpers.dm
index 1935eb3e0b..c2479460c7 100644
--- a/code/game/gamemodes/clock_cult/clock_helpers/power_helpers.dm
+++ b/code/game/gamemodes/clock_cult/clock_helpers/power_helpers.dm
@@ -10,12 +10,15 @@
for(var/obj/effect/clockwork/sigil/transmission/T in GLOB.all_clockwork_objects)
T.update_icon()
var/power_overwhelming = GLOB.clockwork_power
+ var/unlock_message
if(power_overwhelming >= SCRIPT_UNLOCK_THRESHOLD && !GLOB.script_scripture_unlocked)
GLOB.script_scripture_unlocked = TRUE
- hierophant_message("The Ark swells as a key power threshold is reached. Script scriptures are now available.")
+ unlock_message = "The Ark swells as a key power threshold is reached. Script scriptures are now available."
if(power_overwhelming >= APPLICATION_UNLOCK_THRESHOLD && !GLOB.application_scripture_unlocked)
GLOB.application_scripture_unlocked = TRUE
- hierophant_message("The Ark surges as a key power threshold is reached. Application scriptures are now available.")
+ unlock_message = "The Ark surges as a key power threshold is reached. Application scriptures are now available."
+ if(GLOB.servants_active)
+ hierophant_message(unlock_message)
return TRUE
/proc/can_access_clockwork_power(atom/movable/access_point, amount) //Returns true if the access point has access to clockwork power (and optionally, a number of watts for it)
diff --git a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm
index 0b94d34ab1..bfa27cefdb 100644
--- a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm
+++ b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm
@@ -11,6 +11,8 @@
//reports to servants when scripture is locked or unlocked
/proc/scripture_unlock_alert(list/previous_states)
+ if(!GLOB.servants_active)
+ return
. = scripture_unlock_check()
for(var/i in .)
if(.[i] != previous_states[i])
diff --git a/code/game/gamemodes/clock_cult/clock_mobs/clockwork_marauder.dm b/code/game/gamemodes/clock_cult/clock_mobs/clockwork_marauder.dm
index a1c3d211fb..562814dfeb 100644
--- a/code/game/gamemodes/clock_cult/clock_mobs/clockwork_marauder.dm
+++ b/code/game/gamemodes/clock_cult/clock_mobs/clockwork_marauder.dm
@@ -1,13 +1,13 @@
#define MARAUDER_SLOWDOWN_PERCENTAGE 0.40 //Below this percentage of health, marauders will become slower
-#define MARAUDER_SHIELD_REGEN_TIME 100 //In deciseconds, how long it takes for shields to regenerate after breaking
+#define MARAUDER_SHIELD_REGEN_TIME 200 //In deciseconds, how long it takes for shields to regenerate after breaking
//Clockwork marauder: A well-rounded frontline construct. Only one can exist for every two human servants.
/mob/living/simple_animal/hostile/clockwork/marauder
name = "clockwork marauder"
desc = "The stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield."
icon_state = "clockwork_marauder"
- health = 150
- maxHealth = 150
+ health = 120
+ maxHealth = 120
force_threshold = 8
speed = 0
obj_damage = 40
@@ -39,10 +39,11 @@
speed = initial(speed) + 1 //Yes, this slows them down
else
speed = initial(speed)
- if(shield_health != max_shield_health && world.time >= shield_health_regen)
- to_chat(src, "Your shield has recovered. [max_shield_health] blocks remaining!")
+ if(shield_health < max_shield_health && world.time >= shield_health_regen)
+ shield_health_regen = world.time + MARAUDER_SHIELD_REGEN_TIME
+ to_chat(src, "Your shield has recovered, [shield_health] blocks remaining!")
playsound_local(src, "shatter", 75, TRUE, frequency = -1)
- shield_health = max_shield_health
+ shield_health++
/mob/living/simple_animal/hostile/clockwork/marauder/update_values()
if(GLOB.ratvar_awakens) //Massive attack damage bonuses and health increase, because Ratvar
diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
index 9128847e16..3e7e5f01ef 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
@@ -2,6 +2,8 @@
#define VEST_COMBAT 2
#define GIZMO_SCAN 1
#define GIZMO_MARK 2
+#define MIND_DEVICE_MESSAGE 1
+#define MIND_DEVICE_CONTROL 2
//AGENT VEST
/obj/item/clothing/suit/armor/abductor/vest
@@ -278,6 +280,84 @@
if(!istype(I, /obj/item/device/radio/headset))
r.broadcasting = 0 //goddamned headset hacks
+/obj/item/device/abductor/mind_device
+ name = "mental interface device"
+ desc = "A dual-mode tool for directly communicating with sentient brains. It can be used to send a direct message to a target, \
+ or to send a command to a test subject with a charged gland."
+ icon_state = "mind_device_message"
+ item_state = "silencer"
+ lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
+ var/mode = MIND_DEVICE_MESSAGE
+
+/obj/item/device/abductor/mind_device/attack_self(mob/user)
+ if(!ScientistCheck(user))
+ return
+
+ if(mode == MIND_DEVICE_MESSAGE)
+ mode = MIND_DEVICE_CONTROL
+ icon_state = "mind_device_control"
+ else
+ mode = MIND_DEVICE_MESSAGE
+ icon_state = "mind_device_message"
+ to_chat(user, "You switch the device to [mode==MIND_DEVICE_MESSAGE? "TRANSMISSION": "COMMAND"] MODE")
+
+/obj/item/device/abductor/mind_device/afterattack(atom/target, mob/living/user, flag, params)
+ if(!ScientistCheck(user))
+ return
+
+ switch(mode)
+ if(MIND_DEVICE_CONTROL)
+ mind_control(target, user)
+ if(MIND_DEVICE_MESSAGE)
+ mind_message(target, user)
+
+/obj/item/device/abductor/mind_device/proc/mind_control(atom/target, mob/living/user)
+ if(iscarbon(target))
+ var/mob/living/carbon/C = target
+ var/obj/item/organ/heart/gland/G = C.getorganslot("heart")
+ if(!istype(G))
+ to_chat(user, "Your target does not have an experimental gland!")
+ return
+ if(!G.mind_control_uses)
+ to_chat(user, "Your target's gland is spent!")
+ return
+ if(G.active_mind_control)
+ to_chat(user, "Your target is already under a mind-controlling influence!")
+ return
+
+ var/command = stripped_input(user, "Enter the command for your target to follow.\
+ Uses Left: [G.mind_control_uses], Duration: [G.mind_control_duration / 10] seconds","Enter command")
+
+ if(!command)
+ return
+
+ if(QDELETED(user) || user.get_active_held_item() != src || loc != user)
+ return
+
+ if(QDELETED(G))
+ return
+
+ G.mind_control(command, user)
+ to_chat(user, "You send the command to your target.")
+
+/obj/item/device/abductor/mind_device/proc/mind_message(atom/target, mob/living/user)
+ if(isliving(target))
+ var/mob/living/L = target
+ if(L.stat == DEAD)
+ to_chat(user, "Your target is dead!")
+ return
+ var/message = stripped_input(user, "Write a message to send to your target's brain.","Enter message")
+ if(!message)
+ return
+ if(QDELETED(L) || L.stat == DEAD)
+ return
+
+ to_chat(L, "You hear a voice in your head saying: [message]")
+ to_chat(user, "You send the message to your target.")
+ log_talk(user,"[key_name(user)] sent an abductor mind message to [L]/[L.ckey]: '[message]'", LOGSAY)
+
+
/obj/item/device/firing_pin/abductor
name = "alien firing pin"
icon_state = "firing_pin_ayy"
diff --git a/code/game/gamemodes/miniantags/abduction/gland.dm b/code/game/gamemodes/miniantags/abduction/gland.dm
index 22edb79c80..508f4e9f13 100644
--- a/code/game/gamemodes/miniantags/abduction/gland.dm
+++ b/code/game/gamemodes/miniantags/abduction/gland.dm
@@ -12,28 +12,68 @@
var/human_only = 0
var/active = 0
+ var/mind_control_uses = 1
+ var/mind_control_duration = 1800
+ var/active_mind_control = FALSE
+
/obj/item/organ/heart/gland/proc/ownerCheck()
if(ishuman(owner))
- return 1
+ return TRUE
if(!human_only && iscarbon(owner))
- return 1
- return 0
+ return TRUE
+ return FALSE
/obj/item/organ/heart/gland/proc/Start()
active = 1
next_activation = world.time + rand(cooldown_low,cooldown_high)
+/obj/item/organ/heart/gland/proc/update_gland_hud()
+ if(!owner)
+ return
+ var/image/holder = owner.hud_list[GLAND_HUD]
+ var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
+ holder.pixel_y = I.Height() - world.icon_size
+ if(active_mind_control)
+ holder.icon_state = "hudgland_active"
+ else if(mind_control_uses)
+ holder.icon_state = "hudgland_ready"
+ else
+ holder.icon_state = "hudgland_spent"
-/obj/item/organ/heart/gland/Remove(var/mob/living/carbon/M, special = 0)
+/obj/item/organ/heart/gland/proc/mind_control(command, mob/living/user)
+ if(!ownerCheck() || !mind_control_uses || active_mind_control)
+ return
+ mind_control_uses--
+ to_chat(owner, "You suddenly feel an irresistible compulsion to follow an order...")
+ to_chat(owner, "[command]")
+ active_mind_control = TRUE
+ log_admin("[key_name(user)] sent an abductor mind control message to [key_name(owner)]: [command]")
+ update_gland_hud()
+
+ addtimer(CALLBACK(src, .proc/clear_mind_control), mind_control_duration)
+
+/obj/item/organ/heart/gland/proc/clear_mind_control()
+ if(!ownerCheck() || !active_mind_control)
+ return
+ to_chat(owner, "You feel the compulsion fade, and you completely forget about your previous orders.")
+ active_mind_control = FALSE
+
+/obj/item/organ/heart/gland/Remove(mob/living/carbon/M, special = 0)
active = 0
if(initial(uses) == 1)
uses = initial(uses)
+ var/datum/atom_hud/abductor/hud = GLOB.huds[DATA_HUD_ABDUCTOR]
+ hud.remove_from_hud(owner)
+ clear_mind_control()
..()
-/obj/item/organ/heart/gland/Insert(var/mob/living/carbon/M, special = 0)
+/obj/item/organ/heart/gland/Insert(mob/living/carbon/M, special = 0)
..()
if(special != 2 && uses) // Special 2 means abductor surgery
Start()
+ var/datum/atom_hud/abductor/hud = GLOB.huds[DATA_HUD_ABDUCTOR]
+ hud.add_to_hud(owner)
+ update_gland_hud()
/obj/item/organ/heart/gland/on_life()
if(!beating)
@@ -59,6 +99,8 @@
cooldown_high = 400
uses = -1
icon_state = "health"
+ mind_control_uses = 3
+ mind_control_duration = 3000
/obj/item/organ/heart/gland/heals/activate()
to_chat(owner, "You feel curiously revitalized.")
@@ -71,6 +113,8 @@
cooldown_high = 1200
uses = -1
icon_state = "slime"
+ mind_control_uses = 1
+ mind_control_duration = 2400
/obj/item/organ/heart/gland/slime/activate()
to_chat(owner, "You feel nauseous!")
@@ -86,6 +130,8 @@
cooldown_high = 300
uses = -1
icon_state = "mindshock"
+ mind_control_uses = 1
+ mind_control_duration = 6000
/obj/item/organ/heart/gland/mindshock/activate()
to_chat(owner, "You get a headache.")
@@ -103,6 +149,8 @@
uses = -1
human_only = 1
icon_state = "species"
+ mind_control_uses = 5
+ mind_control_duration = 300
/obj/item/organ/heart/gland/pop/activate()
to_chat(owner, "You feel unlike yourself.")
@@ -114,6 +162,8 @@
cooldown_high = 2400
uses = 1
icon_state = "vent"
+ mind_control_uses = 4
+ mind_control_duration = 1800
/obj/item/organ/heart/gland/ventcrawling/activate()
to_chat(owner, "You feel very stretchy.")
@@ -125,6 +175,8 @@
cooldown_high = 2400
uses = 1
icon_state = "viral"
+ mind_control_uses = 1
+ mind_control_duration = 1800
/obj/item/organ/heart/gland/viral/activate()
to_chat(owner, "You feel sick.")
@@ -141,6 +193,8 @@
cooldown_high = 1600
uses = 10
icon_state = "emp"
+ mind_control_uses = 1
+ mind_control_duration = 1800
/obj/item/organ/heart/gland/emp/activate()
to_chat(owner, "You feel a spike of pain in your head.")
@@ -151,6 +205,8 @@
cooldown_high = 900
uses = 10
icon_state = "spider"
+ mind_control_uses = 2
+ mind_control_duration = 2400
/obj/item/organ/heart/gland/spiderman/activate()
to_chat(owner, "You feel something crawling in your skin.")
@@ -164,6 +220,8 @@
icon_state = "egg"
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
+ mind_control_uses = 2
+ mind_control_duration = 1800
/obj/item/organ/heart/gland/egg/activate()
to_chat(owner, "You lay an egg!")
@@ -175,6 +233,8 @@
cooldown_low = 200
cooldown_high = 400
uses = -1
+ mind_control_uses = 1
+ mind_control_duration = 450
/obj/item/organ/heart/gland/bloody/activate()
owner.blood_volume -= 20
@@ -192,6 +252,8 @@
cooldown_high = 600
human_only = 1
uses = 1
+ mind_control_uses = 1
+ mind_control_duration = 600
/obj/item/organ/heart/gland/bodysnatch/activate()
to_chat(owner, "You feel something moving around inside you...")
@@ -233,6 +295,8 @@
cooldown_low = 1200
cooldown_high = 1800
uses = -1
+ mind_control_uses = 1
+ mind_control_duration = 800
/obj/item/organ/heart/gland/plasma/activate()
to_chat(owner, "You feel bloated.")
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/console.dm b/code/game/gamemodes/miniantags/abduction/machinery/console.dm
index f243f161c3..0b13c359eb 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/console.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/console.dm
@@ -48,6 +48,7 @@
dat += "Agent Vest
"
dat += "Radio Silencer
"
dat += "Science Tool
"
+ dat += "Mental Interface Device
"
else
dat += "NO EXPERIMENT MACHINE DETECTED
"
@@ -109,6 +110,8 @@
Dispense(/obj/item/device/abductor/gizmo)
if("vest")
Dispense(/obj/item/clothing/suit/armor/abductor/vest)
+ if("mind_device")
+ Dispense(/obj/item/device/abductor/mind_device,cost=2)
updateUsrDialog()
/obj/machinery/abductor/console/proc/TeleporterRetrieve()
diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm
index 727203b150..b4dc0794cc 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant.dm
@@ -374,7 +374,7 @@
return
var/key_of_revenant
message_admins("Revenant ectoplasm was left undestroyed for 1 minute and is reforming into a new revenant.")
- loc = get_turf(src) //In case it's in a backpack or someone's hand
+ forceMove(drop_location()) //In case it's in a backpack or someone's hand
revenant.forceMove(loc)
if(client_to_revive)
for(var/mob/M in GLOB.dead_mob_list)
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index c59ad05cd5..21de0fc2f9 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -213,7 +213,7 @@
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
var/mob/living/carbon/human/target = null
var/list/mob/living/carbon/human/possible = list()
- var/obj/item/link = null
+ var/obj/item/linked_item = null
var/cooldown_time = 30 //3s
var/cooldown = 0
max_integrity = 10
@@ -237,10 +237,10 @@
cooldown = world.time +cooldown_time
return
- if(!link)
+ if(!linked_item)
if(I.loc == user && istype(I) && I.w_class <= WEIGHT_CLASS_SMALL)
if (user.transferItemToLoc(I,src))
- link = I
+ linked_item = I
to_chat(user, "You attach [I] to the doll.")
update_targets()
@@ -255,11 +255,11 @@
return
if(user.zone_selected == "chest")
- if(link)
+ if(linked_item)
target = null
- link.loc = get_turf(src)
- to_chat(user, "You remove the [link] from the doll.")
- link = null
+ linked_item.forceMove(drop_location())
+ to_chat(user, "You remove the [linked_item] from the doll.")
+ linked_item = null
update_targets()
return
@@ -291,10 +291,10 @@
/obj/item/voodoo/proc/update_targets()
possible = list()
- if(!link)
+ if(!linked_item)
return
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
- if(md5(H.dna.uni_identity) in link.fingerprints)
+ if(md5(H.dna.uni_identity) in linked_item.fingerprints)
possible |= H
/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
diff --git a/code/game/machinery/PDApainter.dm b/code/game/machinery/PDApainter.dm
index 61d5627354..6156ee1d86 100644
--- a/code/game/machinery/PDApainter.dm
+++ b/code/game/machinery/PDApainter.dm
@@ -134,7 +134,7 @@
return
if(storedpda)
- storedpda.loc = get_turf(src.loc)
+ storedpda.forceMove(drop_location())
storedpda = null
update_icon()
else
diff --git a/code/game/machinery/computer/telecrystalconsoles.dm b/code/game/machinery/computer/telecrystalconsoles.dm
index c9c8504955..08210bf706 100644
--- a/code/game/machinery/computer/telecrystalconsoles.dm
+++ b/code/game/machinery/computer/telecrystalconsoles.dm
@@ -51,7 +51,7 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
/obj/machinery/computer/telecrystals/uplinker/proc/ejectuplink()
if(uplinkholder)
- uplinkholder.loc = get_turf(src.loc)
+ uplinkholder.forceMove(drop_location())
uplinkholder = null
update_icon()
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index 99cbded13a..4328a22222 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -157,15 +157,15 @@
if(istype(P, /obj/item/crowbar))
playsound(src.loc, P.usesound, 50, 1)
state = 2
- circuit.loc = src.loc
+ circuit.forceMove(drop_location())
components.Remove(circuit)
circuit = null
if(components.len == 0)
to_chat(user, "You remove the circuit board.")
else
to_chat(user, "You remove the circuit board and other components.")
- for(var/atom/movable/A in components)
- A.loc = src.loc
+ for(var/atom/movable/AM in components)
+ AM.forceMove(drop_location())
desc = initial(desc)
req_components = null
components = null
@@ -186,9 +186,9 @@
qdel(O)
new_machine.component_parts = list()
for(var/obj/O in src)
- O.loc = null
+ O.moveToNullspace()
new_machine.component_parts += O
- circuit.loc = null
+ circuit.moveToNullspace()
new_machine.RefreshParts()
qdel(src)
return
diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm
index ec8779b7d2..79ec733303 100644
--- a/code/game/machinery/dance_machine.dm
+++ b/code/game/machinery/dance_machine.dm
@@ -459,6 +459,8 @@
var/sound/song_played = sound(selection.song_path)
for(var/mob/M in range(10,src))
+ if(!M.client || !(M.client.prefs.toggles & SOUND_INSTRUMENTS))
+ continue
if(!(M in rangers))
rangers[M] = TRUE
M.playsound_local(get_turf(M), null, 100, channel = CHANNEL_JUKEBOX, S = song_played)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index d30554d258..775c9dd894 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -1036,7 +1036,7 @@
panel_open = TRUE
update_icon(AIRLOCK_OPENING)
visible_message("[src]'s panel is blown off in a spray of deadly shrapnel!")
- charge.loc = get_turf(src)
+ charge.forceMove(drop_location())
charge.ex_act(EXPLODE_DEVASTATE)
detonated = 1
charge = null
@@ -1340,7 +1340,7 @@
else
ae = electronics
electronics = null
- ae.loc = src.loc
+ ae.forceMove(drop_location())
qdel(src)
/obj/machinery/door/airlock/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 2313afec3b..dce884b794 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -275,7 +275,7 @@
else
ae = electronics
electronics = null
- ae.loc = src.loc
+ ae.forceMove(drop_location())
qdel(src)
return
@@ -495,4 +495,4 @@
/obj/machinery/door/window/brigdoor/security/holding/southright
dir = SOUTH
icon_state = "rightsecure"
- base_state = "rightsecure"
\ No newline at end of file
+ base_state = "rightsecure"
diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm
index d6d8c93ed1..10a552564b 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -75,7 +75,7 @@ Possible to do for anyone motivated enough:
replay_stop()
if(record_mode)
record_stop()
-
+
QDEL_NULL(disk)
holopads -= src
@@ -256,12 +256,12 @@ Possible to do for anyone motivated enough:
temp = ""
if(outgoing_call)
outgoing_call.Disconnect()
-
+
else if(href_list["disk_eject"])
if(disk && !replay_mode)
disk.forceMove(drop_location())
disk = null
-
+
else if(href_list["replay_stop"])
replay_stop()
else if(href_list["replay_start"])
@@ -424,7 +424,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(masters[user])
var/obj/effect/overlay/holo_pad_hologram/H = masters[user]
step_to(H, new_turf)
- H.loc = new_turf
+ H.forceMove(new_turf)
var/area/holo_area = get_area(src)
var/area/eye_area = new_turf.loc
@@ -505,7 +505,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
current_delay += entry[2]
var/time_delta = world.time - record_start - current_delay
-
+
if(time_delta >= 1)
disk.record.entries += list(list(HOLORECORD_DELAY,time_delta))
disk.record.entries += list(list(HOLORECORD_SAY,message))
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index 18acd9ece7..ee9b1ff31a 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -780,7 +780,7 @@ GLOBAL_LIST_EMPTY(allCasters)
/obj/machinery/newscaster/proc/AttachPhoto(mob/user)
if(photo)
if(!photo.sillynewscastervar)
- photo.loc = loc
+ photo.forceMove(drop_location())
if(!issilicon(user))
user.put_in_inactive_hand(photo)
else
@@ -856,7 +856,7 @@ GLOBAL_LIST_EMPTY(allCasters)
NEWSPAPER.wantedBody = GLOB.news_network.wanted_issue.body
if(GLOB.news_network.wanted_issue.img)
NEWSPAPER.wantedPhoto = GLOB.news_network.wanted_issue.img
- NEWSPAPER.loc = get_turf(src)
+ NEWSPAPER.forceMove(drop_location())
NEWSPAPER.creationTime = GLOB.news_network.lastAction
paper_remaining--
diff --git a/code/game/machinery/robot_fabricator.dm b/code/game/machinery/robot_fabricator.dm
index 606f64c7f3..c01c72d7a8 100644
--- a/code/game/machinery/robot_fabricator.dm
+++ b/code/game/machinery/robot_fabricator.dm
@@ -137,7 +137,7 @@ Please wait until completion...
spawn (build_time)
if (!isnull(src.being_built))
- src.being_built.loc = get_turf(src)
+ src.being_built.forceMove(drop_location())
src.being_built = null
src.use_power = IDLE_POWER_USE
operating = FALSE
diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm
index f7a18ff246..eb24a04b0f 100644
--- a/code/game/machinery/spaceheater.dm
+++ b/code/game/machinery/spaceheater.dm
@@ -228,7 +228,7 @@
settableTemperatureMedian + settableTemperatureRange)
if("eject")
if(panel_open && cell)
- cell.loc = get_turf(src)
+ cell.forceMove(drop_location())
cell = null
. = TRUE
diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm
index fe18365a9c..7624312f84 100644
--- a/code/game/machinery/transformer.dm
+++ b/code/game/machinery/transformer.dm
@@ -57,7 +57,7 @@
var/move_dir = get_dir(loc, AM.loc)
var/mob/living/carbon/human/H = AM
if((transform_standing || H.lying) && move_dir == EAST)// || move_dir == WEST)
- AM.loc = src.loc
+ AM.forceMove(drop_location())
do_transform(AM)
/obj/machinery/transformer/CanPass(atom/movable/mover, turf/target)
diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm
index e2a35ac591..54530d368c 100644
--- a/code/game/mecha/equipment/mecha_equipment.dm
+++ b/code/game/mecha/equipment/mecha_equipment.dm
@@ -104,7 +104,7 @@
/obj/item/mecha_parts/mecha_equipment/proc/attach(obj/mecha/M)
M.equipment += src
chassis = M
- src.loc = M
+ forceMove(M)
M.log_message("[src] initialized.")
if(!M.selected && selectable)
M.selected = src
diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm
index d456642633..f076b723ae 100644
--- a/code/game/mecha/equipment/tools/work_tools.dm
+++ b/code/game/mecha/equipment/tools/work_tools.dm
@@ -39,7 +39,7 @@
O.anchored = TRUE
if(do_after_cooldown(target))
cargo_holder.cargo += O
- O.loc = chassis
+ O.forceMove(chassis)
O.anchored = FALSE
occupant_message("[target] successfully loaded.")
log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]")
@@ -91,7 +91,7 @@
O.anchored = TRUE
if(do_after_cooldown(target))
cargo_holder.cargo += O
- O.loc = chassis
+ O.forceMove(chassis)
O.anchored = FALSE
occupant_message("[target] successfully loaded.")
log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]")
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index e50da70c5d..799344fe54 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -24,7 +24,7 @@
infra_luminosity = 15 //byond implementation is bugged.
force = 5
flags_1 = HEAR_1
- var/can_move = 1
+ var/can_move = 0 //time of next allowed movement
var/mob/living/carbon/occupant = null
var/step_in = 10 //make a step in step_in/10 sec.
var/dir_in = 2//What direction will the mech face when entered/powered on? Defaults to South.
@@ -502,7 +502,7 @@
return domove(direction)
/obj/mecha/proc/domove(direction)
- if(!can_move)
+ if(can_move >= world.time)
return 0
if(!Process_Spacemove(direction))
return 0
@@ -520,21 +520,19 @@
return 0
var/move_result = 0
+ var/oldloc = loc
if(internal_damage & MECHA_INT_CONTROL_LOST)
move_result = mechsteprand()
else if(dir != direction && !strafe)
move_result = mechturn(direction)
else
move_result = mechstep(direction)
- if(move_result)
+ if(move_result || loc != oldloc)// halfway done diagonal move still returns false
use_power(step_energy_drain)
- can_move = 0
- spawn(step_in)
- can_move = 1
+ can_move = world.time + step_in
return 1
return 0
-
/obj/mecha/proc/mechturn(direction)
setDir(direction)
if(turnsound)
diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm
index 272d3530a6..de50d6f86f 100644
--- a/code/game/mecha/mecha_construction_paths.dm
+++ b/code/game/mecha/mecha_construction_paths.dm
@@ -542,7 +542,7 @@
else
user.visible_message("[user] removes the capacitor from the [holder].", "You remove the capacitor from the [holder].")
var/obj/item/I = locate(/obj/item/stock_parts/capacitor) in holder
- I.loc = get_turf(holder)
+ I.forceMove(holder.drop_location())
holder.icon_state = "gygax12"
if(9)
if(diff==FORWARD)
@@ -1155,7 +1155,7 @@
else
user.visible_message("[user] removes the scanner module from the [holder].", "You remove the scanner module from the [holder].")
var/obj/item/I = locate(/obj/item/stock_parts/scanning_module) in holder
- I.loc = get_turf(holder)
+ I.forceMove(holder.drop_location())
holder.icon_state = "durand10"
if(11)
if(diff==FORWARD)
@@ -1173,7 +1173,7 @@
else
user.visible_message("[user] removes the super capacitor from the [holder].", "You remove the capacitor from the [holder].")
var/obj/item/I = locate(/obj/item/stock_parts/capacitor) in holder
- I.loc = get_turf(holder)
+ I.forceMove(holder.drop_location())
holder.icon_state = "durand12"
if(9)
if(diff==FORWARD)
@@ -1480,7 +1480,7 @@
else
user.visible_message("[user] removes the phasic scanner module from the [holder].", "You remove the scanner module from the [holder].")
var/obj/item/I = locate(/obj/item/stock_parts/scanning_module) in holder
- I.loc = get_turf(holder)
+ I.forceMove(holder.drop_location())
holder.icon_state = "phazon10"
if(15)
if(diff==FORWARD)
@@ -1498,7 +1498,7 @@
else
user.visible_message("[user] removes the super capacitor from the [holder].", "You remove the capacitor from the [holder].")
var/obj/item/I = locate(/obj/item/stock_parts/capacitor) in holder
- I.loc = get_turf(holder)
+ I.forceMove(holder.drop_location())
holder.icon_state = "phazon12"
if(13)
if(diff==FORWARD)
diff --git a/code/game/mecha/mecha_wreckage.dm b/code/game/mecha/mecha_wreckage.dm
index 67e5c1dbd1..de8f8ecb3a 100644
--- a/code/game/mecha/mecha_wreckage.dm
+++ b/code/game/mecha/mecha_wreckage.dm
@@ -68,7 +68,7 @@
if(crowbar_salvage && crowbar_salvage.len)
var/obj/S = pick(crowbar_salvage)
if(S)
- S.loc = get_turf(user)
+ S.forceMove(user.drop_location())
crowbar_salvage -= S
user.visible_message("[user] pries [S] from [src].", "You pry [S] from [src].")
return
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index 89a5ce7353..4ecba7c982 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -150,7 +150,7 @@
spawn(travel_time)
if(!exit_vent || exit_vent.welded)
- loc = entry_vent
+ forceMove(entry_vent)
entry_vent = null
return
@@ -162,7 +162,7 @@
forceMove(entry_vent)
entry_vent = null
return
- loc = exit_vent.loc
+ forceMove(exit_vent.loc)
entry_vent = null
var/area/new_area = get_area(loc)
if(new_area)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index f4dd741695..d4e5240642 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -119,6 +119,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/icon_override = null
+ //Grinder vars
+ var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
+ var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
+
/obj/item/Initialize()
if (!materials)
materials = list()
@@ -282,7 +286,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(!user.put_in_active_hand(src))
dropped(user)
-
/obj/item/attack_paw(mob/user)
if(!user)
return
@@ -396,6 +399,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return ITALICS | REDUCE_RANGE
/obj/item/proc/dropped(mob/user)
+ SendSignal(COMSIG_ITEM_DROPPED, user)
for(var/X in actions)
var/datum/action/A = X
A.Remove(user)
@@ -427,6 +431,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// for items that can be placed in multiple slots
// note this isn't called during the initial dressing of a player
/obj/item/proc/equipped(mob/user, slot)
+ SendSignal(COMSIG_ITEM_EQUIPPED, user, slot)
for(var/X in actions)
var/datum/action/A = X
if(item_action_slot_check(slot, user)) //some items only give their actions buttons when in a specific slot.
@@ -678,6 +683,15 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/obj/item/proc/on_mob_death(mob/living/L, gibbed)
+/obj/item/proc/grind_requirements(obj/machinery/reagentgrinder/R) //Used to check for extra requirements for grinding an object
+ return TRUE
+
+ //Called BEFORE the object is ground up - use this to change grind results based on conditions
+ //Use "return -1" to prevent the grinding from occurring
+/obj/item/proc/on_grind()
+
+/obj/item/proc/on_juice()
+
/obj/item/proc/set_force_string()
switch(force)
if(0 to 4)
@@ -713,4 +727,3 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/obj/item/MouseExited()
deltimer(tip_timer)//delete any in-progress timer if the mouse is moved off the item before it finishes
closeToolTip(usr)
-
diff --git a/code/game/objects/items/apc_frame.dm b/code/game/objects/items/apc_frame.dm
index 4c8d342c16..5048f6ed2d 100644
--- a/code/game/objects/items/apc_frame.dm
+++ b/code/game/objects/items/apc_frame.dm
@@ -120,4 +120,5 @@
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_SMALL
- materials = list(MAT_METAL=50, MAT_GLASS=50)
\ No newline at end of file
+ materials = list(MAT_METAL=50, MAT_GLASS=50)
+ grind_results = list("iron" = 10, "silicon" = 10)
diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm
index 11336cd06a..7533718c17 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -163,7 +163,7 @@
/obj/effect/chrono_field/New(loc, var/mob/living/target, var/obj/item/gun/energy/chrono_gun/G)
if(target && isliving(target) && G)
- target.loc = src
+ target.forceMove(src)
src.captured = target
var/icon/mob_snapshot = getFlatIcon(target)
var/icon/cached_icon = new()
@@ -198,7 +198,7 @@
if(captured)
if(tickstokill > initial(tickstokill))
for(var/atom/movable/AM in contents)
- AM.loc = loc
+ AM.forceMove(drop_location())
qdel(src)
else if(tickstokill <= 0)
to_chat(captured, "As the last essence of your being is erased from time, you begin to re-experience your most enjoyable memory. You feel happy...")
@@ -213,7 +213,7 @@
else
captured.Unconscious(80)
if(captured.loc != src)
- captured.loc = src
+ captured.forceMove(src)
update_icon()
if(gun)
if(gun.field_check(src))
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index 491feb91ce..9c7c34510c 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -25,6 +25,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
var/smoketime = 5
w_class = WEIGHT_CLASS_TINY
heat = 1000
+ grind_results = list("phosphorus" = 2)
/obj/item/match/process()
smoketime--
@@ -104,6 +105,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
container_type = INJECTABLE_1
w_class = WEIGHT_CLASS_TINY
body_parts_covered = null
+ grind_results = list()
var/lit = FALSE
var/starts_lit = FALSE
var/icon_on = "cigon" //Note - these are in masks.dmi not in cigarette.dmi
@@ -363,6 +365,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon_state = "cigbutt"
w_class = WEIGHT_CLASS_TINY
throwforce = 0
+ grind_results = list("carbon" = 2)
/obj/item/cigbutt/cigarbutt
name = "cigar butt"
@@ -484,6 +487,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
heat = 1500
resistance_flags = FIRE_PROOF
light_color = LIGHT_COLOR_FIRE
+ grind_results = list("iron" = 1, "welding_fuel" = 5, "oil" = 5)
/obj/item/lighter/update_icon()
if(lit)
diff --git a/code/game/objects/items/circuitboards/circuitboard.dm b/code/game/objects/items/circuitboards/circuitboard.dm
index 82350e37f9..12b54a3751 100644
--- a/code/game/objects/items/circuitboards/circuitboard.dm
+++ b/code/game/objects/items/circuitboards/circuitboard.dm
@@ -12,6 +12,7 @@
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
materials = list(MAT_GLASS=1000)
w_class = WEIGHT_CLASS_SMALL
+ grind_results = list("silicon" = 20, "sacid" = 0.5) //Retrieving acid this way is extremely inefficient
var/build_path = null
/obj/item/circuitboard/proc/apply_default_parts(obj/machinery/M)
diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm
index c96ec4167a..f2a804e9e9 100644
--- a/code/game/objects/items/clown_items.dm
+++ b/code/game/objects/items/clown_items.dm
@@ -21,6 +21,7 @@
throwforce = 0
throw_speed = 3
throw_range = 7
+ grind_results = list("lye" = 10)
var/cleanspeed = 50 //slower than mop
force_string = "robust... against germs"
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 7b2d730daf..56bad47963 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -26,6 +26,7 @@
item_color = "red"
w_class = WEIGHT_CLASS_TINY
attack_verb = list("attacked", "coloured")
+ grind_results = list()
var/paint_color = "#FF0000" //RGB
var/drawtype
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index afed9c4b4c..25fbb49c9b 100644
--- a/code/game/objects/items/defib.dm
+++ b/code/game/objects/items/defib.dm
@@ -328,7 +328,7 @@
O.unwield()
to_chat(user, "The paddles snap back into the main unit.")
defib.on = 0
- loc = defib
+ forceMove(defib)
defib.update_icon()
return unwield(user)
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 1f7fd77c4a..f2bc8b5686 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -543,7 +543,7 @@ GLOBAL_LIST_EMPTY(PDAs)
if("2") // Eject pAI device
var/turf/T = get_turf(src.loc)
if(T)
- pai.loc = T
+ pai.forceMove(T)
//LINK FUNCTIONS===================================
@@ -578,7 +578,7 @@ GLOBAL_LIST_EMPTY(PDAs)
M.put_in_hands(id)
to_chat(usr, "You remove the ID from the [name].")
else
- id.loc = get_turf(src)
+ id.forceMove(drop_location())
id = null
update_icon()
diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm
index b405e21ca6..a07d8d8d60 100644
--- a/code/game/objects/items/devices/chameleonproj.dm
+++ b/code/game/objects/items/devices/chameleonproj.dm
@@ -85,7 +85,7 @@
/obj/item/device/chameleon/proc/eject_all()
for(var/atom/movable/A in active_dummy)
- A.loc = active_dummy.loc
+ A.forceMove(active_dummy.loc)
if(ismob(A))
var/mob/M = A
M.reset_perspective(null)
@@ -106,7 +106,7 @@
VRD.force_dismount(M)
else
V.unbuckle_mob(M, force = TRUE)
- M.loc = src
+ M.forceMove(src)
master = C
master.active_dummy = src
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 08c570a786..f656d55afd 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -256,6 +256,7 @@
var/produce_heat = 1500
heat = 1000
light_color = LIGHT_COLOR_FLARE
+ grind_results = list("sulfur" = 15)
/obj/item/device/flashlight/flare/New()
fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds.
@@ -404,6 +405,7 @@
color = LIGHT_COLOR_GREEN
icon_state = "glowstick"
item_state = "glowstick"
+ grind_results = list("phenol" = 15, "hydrogen" = 10, "oxygen" = 5) //Meth-in-a-stick
var/fuel = 0
/obj/item/device/flashlight/glowstick/Initialize()
diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm
index b1b200f489..eb1ccd15f4 100644
--- a/code/game/objects/items/devices/laserpointer.dm
+++ b/code/game/objects/items/devices/laserpointer.dm
@@ -50,7 +50,7 @@
else if(istype(W, /obj/item/screwdriver))
if(diode)
to_chat(user, "You remove the [diode.name] from \the [src].")
- diode.loc = get_turf(src.loc)
+ diode.forceMove(drop_location())
diode = null
else
return ..()
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index 9ff19ba57c..750e1f0511 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -227,7 +227,7 @@
if(keyslot)
var/turf/T = get_turf(user)
if(T)
- keyslot.loc = T
+ keyslot.forceMove(T)
keyslot = null
@@ -235,7 +235,7 @@
if(keyslot2)
var/turf/T = get_turf(user)
if(T)
- keyslot2.loc = T
+ keyslot2.forceMove(T)
keyslot2 = null
recalculateChannels()
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 236f3df93e..8227d75069 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -569,7 +569,7 @@
if(keyslot)
var/turf/T = get_turf(user)
if(T)
- keyslot.loc = T
+ keyslot.forceMove(T)
keyslot = null
recalculateChannels()
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 3f17485550..9a60bb0edb 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -335,6 +335,7 @@ GAS ANALYZER
throw_speed = 3
throw_range = 7
materials = list(MAT_METAL=30, MAT_GLASS=20)
+ grind_results = list("mercury" = 5, "iron" = 5, "silicon" = 5)
/obj/item/device/analyzer/attack_self(mob/user)
diff --git a/code/game/objects/items/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm
index e791a74541..8698594555 100644
--- a/code/game/objects/items/grenades/chem_grenade.dm
+++ b/code/game/objects/items/grenades/chem_grenade.dm
@@ -110,12 +110,12 @@
else if(stage == WIRED && istype(I, /obj/item/wrench))
if(beakers.len)
for(var/obj/O in beakers)
- O.loc = get_turf(src)
+ O.forceMove(drop_location())
beakers = list()
to_chat(user, "You open the [initial(name)] assembly and remove the payload.")
return // First use of the wrench remove beakers, then use the wrench to remove the activation mechanism.
if(nadeassembly)
- nadeassembly.loc = get_turf(src)
+ nadeassembly.forceMove(drop_location())
nadeassembly.master = null
nadeassembly = null
else // If "nadeassembly = null && stage == WIRED", then it most have been cable_coil that was used.
@@ -167,7 +167,7 @@
playsound(loc, 'sound/items/screwdriver2.ogg', 50, 1)
if(beakers.len)
for(var/obj/O in beakers)
- O.loc = get_turf(src)
+ O.forceMove(drop_location())
beakers = list()
stage_change(EMPTY)
return
diff --git a/code/game/objects/items/implants/implantcase.dm b/code/game/objects/items/implants/implantcase.dm
index 7c363fe052..00bda4dadb 100644
--- a/code/game/objects/items/implants/implantcase.dm
+++ b/code/game/objects/items/implants/implantcase.dm
@@ -1,79 +1,80 @@
-/obj/item/implantcase
- name = "implant case"
- desc = "A glass case containing an implant."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "implantcase-0"
- item_state = "implantcase"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- throw_speed = 2
- throw_range = 5
- w_class = WEIGHT_CLASS_TINY
- materials = list(MAT_GLASS=500)
- var/obj/item/implant/imp = null
- var/imp_type
-
-/obj/item/implantcase/update_icon()
- if(imp)
- icon_state = "implantcase-[imp.item_color]"
- reagents = imp.reagents
- else
- icon_state = "implantcase-0"
- reagents = null
-
-
-/obj/item/implantcase/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/pen))
- var/t = stripped_input(user, "What would you like the label to be?", name, null)
- if(user.get_active_held_item() != W)
- return
- if(!in_range(src, user) && loc != user)
- return
- if(t)
- name = "implant case - '[t]'"
- else
- name = "implant case"
- else if(istype(W, /obj/item/implanter))
- var/obj/item/implanter/I = W
- if(I.imp)
- if(imp || I.imp.imp_in)
- return
- I.imp.loc = src
- imp = I.imp
- I.imp = null
- update_icon()
- I.update_icon()
- else
- if(imp)
- if(I.imp)
- return
- imp.loc = I
- I.imp = imp
- imp = null
- update_icon()
- I.update_icon()
-
- else
- return ..()
-
-/obj/item/implantcase/Initialize(mapload)
- . = ..()
- if(imp_type)
- imp = new imp_type(src)
- update_icon()
-
-
-/obj/item/implantcase/tracking
- name = "implant case - 'Tracking'"
- desc = "A glass case containing a tracking implant."
- imp_type = /obj/item/implant/tracking
-
-/obj/item/implantcase/weapons_auth
- name = "implant case - 'Firearms Authentication'"
- desc = "A glass case containing a firearms authentication implant."
- imp_type = /obj/item/implant/weapons_auth
-
-/obj/item/implantcase/adrenaline
- name = "implant case - 'Adrenaline'"
- desc = "A glass case containing an adrenaline implant."
- imp_type = /obj/item/implant/adrenalin
+/obj/item/implantcase
+ name = "implant case"
+ desc = "A glass case containing an implant."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "implantcase-0"
+ item_state = "implantcase"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ throw_speed = 2
+ throw_range = 5
+ w_class = WEIGHT_CLASS_TINY
+ materials = list(MAT_GLASS=500)
+ var/obj/item/implant/imp = null
+ var/imp_type
+
+
+/obj/item/implantcase/update_icon()
+ if(imp)
+ icon_state = "implantcase-[imp.item_color]"
+ reagents = imp.reagents
+ else
+ icon_state = "implantcase-0"
+ reagents = null
+
+
+/obj/item/implantcase/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/pen))
+ var/t = stripped_input(user, "What would you like the label to be?", name, null)
+ if(user.get_active_held_item() != W)
+ return
+ if(!in_range(src, user) && loc != user)
+ return
+ if(t)
+ name = "implant case - '[t]'"
+ else
+ name = "implant case"
+ else if(istype(W, /obj/item/implanter))
+ var/obj/item/implanter/I = W
+ if(I.imp)
+ if(imp || I.imp.imp_in)
+ return
+ I.imp.forceMove(src)
+ imp = I.imp
+ I.imp = null
+ update_icon()
+ I.update_icon()
+ else
+ if(imp)
+ if(I.imp)
+ return
+ imp.forceMove(I)
+ I.imp = imp
+ imp = null
+ update_icon()
+ I.update_icon()
+
+ else
+ return ..()
+
+/obj/item/implantcase/Initialize(mapload)
+ . = ..()
+ if(imp_type)
+ imp = new imp_type(src)
+ update_icon()
+
+
+/obj/item/implantcase/tracking
+ name = "implant case - 'Tracking'"
+ desc = "A glass case containing a tracking implant."
+ imp_type = /obj/item/implant/tracking
+
+/obj/item/implantcase/weapons_auth
+ name = "implant case - 'Firearms Authentication'"
+ desc = "A glass case containing a firearms authentication implant."
+ imp_type = /obj/item/implant/weapons_auth
+
+/obj/item/implantcase/adrenaline
+ name = "implant case - 'Adrenaline'"
+ desc = "A glass case containing an adrenaline implant."
+ imp_type = /obj/item/implant/adrenalin
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index 97e6752efb..d2f1d2a31b 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -33,7 +33,7 @@
add_logs(user, M, "stunned", src, "(INTENT: [uppertext(user.a_intent)])")
/obj/item/borg/cyborghug
- name = "Hugging Module"
+ name = "hugging module"
icon_state = "hugmodule"
desc = "For when a someone really needs a hug."
var/mode = 0 //0 = Hugs 1 = "Hug" 2 = Shock 3 = CRUSH
@@ -336,6 +336,10 @@
cooldown = world.time + 600
log_game("[user.ckey]([user]) used an emagged Cyborg Harm Alarm in ([user.x],[user.y],[user.z])")
+#define DISPENSE_LOLLIPOP_MODE 1
+#define THROW_LOLLIPOP_MODE 2
+#define THROW_GUMBALL_MODE 3
+
/obj/item/borg/lollipop
name = "lollipop fabricator"
desc = "Reward good humans with this. Toggle in-module to switch between dispensing and high velocity ejection modes."
@@ -343,8 +347,9 @@
var/candy = 30
var/candymax = 30
var/charge_delay = 10
- var/charging = 0
- var/mode = 1
+ var/charging = FALSE
+ var/mode = DISPENSE_LOLLIPOP_MODE
+
var/firedelay = 0
var/hitspeed = 2
var/hitdamage = 0
@@ -379,10 +384,22 @@
var/obj/O = A
if(O.density)
return FALSE
- new /obj/item/reagent_containers/food/snacks/lollipop(T)
+
+ var/obj/item/reagent_containers/food/snacks/lollipop/L = new(T)
+
+ var/into_hands = FALSE
+ if(ismob(A))
+ var/mob/M = A
+ into_hands = M.put_in_hands(L)
+
candy--
check_amount()
- to_chat(user, "Dispensing lollipop...")
+
+ if(into_hands)
+ user.visible_message("[user] dispenses a lollipop into the hands of [A].", "You dispense a lollipop into the hands of [A].", "You hear a click.")
+ else
+ user.visible_message("[user] dispenses a lollipop.", "You dispense a lollipop.", "You hear a click.")
+
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
return TRUE
@@ -427,29 +444,33 @@
if(R.emagged)
hitdamage = emaggedhitdamage
switch(mode)
- if(1)
+ if(DISPENSE_LOLLIPOP_MODE)
if(!proximity)
return FALSE
dispense(target, user)
- if(2)
+ if(THROW_LOLLIPOP_MODE)
shootL(target, user, click_params)
- if(3)
+ if(THROW_GUMBALL_MODE)
shootG(target, user, click_params)
hitdamage = initial(hitdamage)
/obj/item/borg/lollipop/attack_self(mob/living/user)
switch(mode)
- if(1)
- mode++
+ if(DISPENSE_LOLLIPOP_MODE)
+ mode = THROW_LOLLIPOP_MODE
to_chat(user, "Module is now throwing lollipops.")
- if(2)
- mode++
+ if(THROW_LOLLIPOP_MODE)
+ mode = THROW_GUMBALL_MODE
to_chat(user, "Module is now blasting gumballs.")
- if(3)
- mode = 1
+ if(THROW_GUMBALL_MODE)
+ mode = DISPENSE_LOLLIPOP_MODE
to_chat(user, "Module is now dispensing lollipops.")
..()
+#undef DISPENSE_LOLLIPOP_MODE
+#undef THROW_LOLLIPOP_MODE
+#undef THROW_GUMBALL_MODE
+
/obj/item/ammo_casing/caseless/gumball
name = "Gumball"
desc = "Why are you seeing this?!"
@@ -655,7 +676,7 @@
/obj/item/borg/sight/xray
- name = "\proper x-ray Vision"
+ name = "\proper x-ray vision"
icon = 'icons/obj/decals.dmi'
icon_state = "securearea"
sight_mode = BORGXRAY
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index 09e3ccdeb0..339b7fbf4b 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -69,7 +69,7 @@
if(!l_arm && !r_arm && !l_leg && !r_leg && !chest && !head)
if (M.use(1))
var/obj/item/ed209_assembly/B = new /obj/item/ed209_assembly
- B.loc = get_turf(src)
+ B.forceMove(drop_location())
to_chat(user, "You arm the robot frame.")
var/holding_this = user.get_inactive_held_item()==src
qdel(src)
@@ -227,7 +227,7 @@
O.job = "Cyborg"
O.cell = chest.cell
- chest.cell.loc = O
+ chest.cell.forceMove(O)
chest.cell = null
W.forceMove(O)//Should fix cybros run time erroring when blown up. It got deleted before, along with the frame.
if(O.mmi) //we delete the mmi created by robot/New()
@@ -271,7 +271,7 @@
O.cell = chest.cell
- chest.cell.loc = O
+ chest.cell.forceMove(O)
chest.cell = null
O.locked = panel_locked
O.job = "Cyborg"
diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm
index 5276050b03..978966706e 100644
--- a/code/game/objects/items/stacks/bscrystal.dm
+++ b/code/game/objects/items/stacks/bscrystal.dm
@@ -9,6 +9,7 @@
points = 50
var/blink_range = 8 // The teleport range when crushed/thrown at someone.
refined_type = /obj/item/stack/sheet/bluespace_crystal
+ grind_results = list("bluespace" = 2)
/obj/item/ore/bluespace_crystal/refined
name = "refined bluespace crystal"
@@ -48,6 +49,7 @@
blink_range = 4 // Not as good as the organic stuff!
points = 0 //nice try
refined_type = null
+ grind_results = list("bluespace" = 1, "silicon" = 2)
//Polycrystals, aka stacks
/obj/item/stack/sheet/bluespace_crystal
@@ -58,6 +60,7 @@
materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT)
attack_verb = list("bluespace polybashed", "bluespace polybattered", "bluespace polybludgeoned", "bluespace polythrashed", "bluespace polysmashed")
novariants = TRUE
+ grind_results = list("bluespace" = 2)
var/crystal_type = /obj/item/ore/bluespace_crystal/refined
/obj/item/stack/sheet/bluespace_crystal/attack_self(mob/user)// to prevent the construction menu from ever happening
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 560182d9c7..7a0f85a8f2 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -111,6 +111,7 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
heal_brute = 40
self_delay = 20
+ grind_results = list("styptic_powder" = 1)
/obj/item/stack/medical/bruise_pack/suicide_act(mob/user)
user.visible_message("[user] is bludgeoning [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -147,3 +148,4 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
heal_burn = 40
self_delay = 20
+ grind_results = list("silver_sulfadiazine" = 1)
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 0544598246..8cc6a60efa 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -22,6 +22,7 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/glass
+ grind_results = list("silicon" = 1)
/obj/item/stack/sheet/glass/cyborg
materials = list()
@@ -79,6 +80,7 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 75, "acid" = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/plasmaglass
+ grind_results = list("silicon" = 1, "plasma" = 1)
/obj/item/stack/sheet/plasmaglass/fifty
amount = 50
@@ -128,6 +130,7 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 70, acid = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/rglass
+ grind_results = list("silicon" = 1, "iron" = 1)
/obj/item/stack/sheet/rglass/attackby(obj/item/W, mob/user, params)
add_fingerprint(user)
@@ -168,6 +171,7 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \
armor = list("melee" = 20, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/plasmarglass
+ grind_results = list("silicon" = 1, "plasma" = 1, "iron" = 1)
/obj/item/stack/sheet/plasmarglass/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.prglass_recipes
diff --git a/code/game/objects/items/stacks/sheets/light.dm b/code/game/objects/items/stacks/sheets/light.dm
index a02d182f1c..051d8326b8 100644
--- a/code/game/objects/items/stacks/sheets/light.dm
+++ b/code/game/objects/items/stacks/sheets/light.dm
@@ -1,37 +1,38 @@
-/obj/item/stack/light_w
- name = "wired glass tile"
- singular_name = "wired glass floor tile"
- desc = "A glass tile, which is wired, somehow."
- icon = 'icons/obj/tiles.dmi'
- icon_state = "glass_wire"
- w_class = WEIGHT_CLASS_NORMAL
- force = 3
- throwforce = 5
- throw_speed = 3
- throw_range = 7
+/obj/item/stack/light_w
+ name = "wired glass tile"
+ singular_name = "wired glass floor tile"
+ desc = "A glass tile, which is wired, somehow."
+ icon = 'icons/obj/tiles.dmi'
+ icon_state = "glass_wire"
+ w_class = WEIGHT_CLASS_NORMAL
+ force = 3
+ throwforce = 5
+ throw_speed = 3
+ throw_range = 7
flags_1 = CONDUCT_1
- max_amount = 60
-
-/obj/item/stack/light_w/attackby(obj/item/O, mob/user, params)
-
+ max_amount = 60
+ grind_results = list("silicon" = 1, "copper" = 1)
+
+/obj/item/stack/light_w/attackby(obj/item/O, mob/user, params)
+
if(istype(O, /obj/item/wirecutters))
- var/obj/item/stack/cable_coil/CC = new (user.loc)
- CC.amount = 5
- CC.add_fingerprint(user)
- amount--
- var/obj/item/stack/sheet/glass/G = new (user.loc)
- G.add_fingerprint(user)
- if(amount <= 0)
- qdel(src)
-
- else if(istype(O, /obj/item/stack/sheet/metal))
- var/obj/item/stack/sheet/metal/M = O
- if (M.use(1))
- use(1)
- var/obj/item/L = new /obj/item/stack/tile/light(user.loc)
- to_chat(user, "You make a light tile.")
- L.add_fingerprint(user)
- else
- to_chat(user, "You need one metal sheet to finish the light tile!")
- else
- return ..()
+ var/obj/item/stack/cable_coil/CC = new (user.loc)
+ CC.amount = 5
+ CC.add_fingerprint(user)
+ amount--
+ var/obj/item/stack/sheet/glass/G = new (user.loc)
+ G.add_fingerprint(user)
+ if(amount <= 0)
+ qdel(src)
+
+ else if(istype(O, /obj/item/stack/sheet/metal))
+ var/obj/item/stack/sheet/metal/M = O
+ if (M.use(1))
+ use(1)
+ var/obj/item/L = new /obj/item/stack/tile/light(user.loc)
+ to_chat(user, "You make a light tile.")
+ L.add_fingerprint(user)
+ else
+ to_chat(user, "You need one metal sheet to finish the light tile!")
+ else
+ return ..()
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index e2ae00d06c..e44366daec 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -126,6 +126,7 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \
sheettype = "uranium"
materials = list(MAT_URANIUM=MINERAL_MATERIAL_AMOUNT)
novariants = TRUE
+ grind_results = list("uranium" = 20)
GLOBAL_LIST_INIT(uranium_recipes, list ( \
new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, one_per_turf = 1, on_floor = 1), \
@@ -149,6 +150,7 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \
resistance_flags = FLAMMABLE
max_integrity = 100
materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT)
+ grind_results = list("plasma" = 20)
GLOBAL_LIST_INIT(plasma_recipes, list ( \
new/datum/stack_recipe("plasma door", /obj/structure/mineral_door/transparent/plasma, 10, one_per_turf = 1, on_floor = 1), \
@@ -182,6 +184,7 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \
singular_name = "gold bar"
sheettype = "gold"
materials = list(MAT_GOLD=MINERAL_MATERIAL_AMOUNT)
+ grind_results = list("gold" = 20)
GLOBAL_LIST_INIT(gold_recipes, list ( \
new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, one_per_turf = 1, on_floor = 1), \
@@ -207,6 +210,7 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \
singular_name = "silver bar"
sheettype = "silver"
materials = list(MAT_SILVER=MINERAL_MATERIAL_AMOUNT)
+ grind_results = list("silver" = 20)
GLOBAL_LIST_INIT(silver_recipes, list ( \
new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, one_per_turf = 1, on_floor = 1), \
@@ -232,6 +236,7 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \
sheettype = "clown"
materials = list(MAT_BANANIUM=MINERAL_MATERIAL_AMOUNT)
novariants = TRUE
+ grind_results = list("banana" = 20)
GLOBAL_LIST_INIT(clown_recipes, list ( \
new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20), \
@@ -302,6 +307,7 @@ GLOBAL_LIST_INIT(plastitanium_recipes, list ( \
singular_name = "snow block"
force = 1
throwforce = 2
+ grind_results = list("ice" = 20)
GLOBAL_LIST_INIT(snow_recipes, list ( \
new/datum/stack_recipe("Snow Wall", /turf/closed/wall/mineral/snow, 5, one_per_turf = 1, on_floor = 1), \
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index d8019d98a3..36b9cf210a 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -99,6 +99,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
flags_1 = CONDUCT_1
resistance_flags = FIRE_PROOF
merge_type = /obj/item/stack/sheet/metal
+ grind_results = list("iron" = 20)
/obj/item/stack/sheet/metal/ratvar_act()
new /obj/item/stack/tile/brass(loc, amount)
@@ -151,6 +152,7 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 80)
resistance_flags = FIRE_PROOF
merge_type = /obj/item/stack/sheet/plasteel
+ grind_results = list("iron" = 20, "plasma" = 20)
/obj/item/stack/sheet/plasteel/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.plasteel_recipes
@@ -202,6 +204,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
resistance_flags = FLAMMABLE
merge_type = /obj/item/stack/sheet/mineral/wood
novariants = TRUE
+ grind_results = list("carbon" = 20)
/obj/item/stack/sheet/mineral/wood/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.wood_recipes
@@ -322,6 +325,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list ( \
sheettype = "runed"
merge_type = /obj/item/stack/sheet/runed_metal
novariants = TRUE
+ grind_results = list("iron" = 0.5, "blood" = 1.5)
/obj/item/stack/sheet/runed_metal/ratvar_act()
new /obj/item/stack/tile/brass(loc, amount)
@@ -385,6 +389,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
throw_range = 3
turf_type = /turf/open/floor/clockwork
novariants = FALSE
+ grind_results = list("iron" = 0.5, "teslium" = 1.5)
/obj/item/stack/tile/brass/narsie_act()
new /obj/item/stack/sheet/runed_metal(loc, amount)
@@ -435,6 +440,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
w_class = WEIGHT_CLASS_NORMAL
throw_speed = 1
throw_range = 3
+ grind_results = list("carbon" = 1)
GLOBAL_LIST_INIT(plastic_recipes, list(
new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, one_per_turf = TRUE, on_floor = TRUE, time = 40), \
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 7cea6d71e8..5e80353db9 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -21,6 +21,17 @@
var/merge_type = null // This path and its children should merge with this stack, defaults to src.type
var/full_w_class = WEIGHT_CLASS_NORMAL //The weight class the stack should have at amount > 2/3rds max_amount
var/novariants = TRUE //Determines whether the item should update it's sprites based on amount.
+ //NOTE: When adding grind_results, the amounts should be for an INDIVIDUAL ITEM - these amounts will be multiplied by the stack size in on_grind()
+
+/obj/item/stack/on_grind()
+ for(var/i in 1 to grind_results.len) //This should only call if it's ground, so no need to check if grind_results exists
+ grind_results[grind_results[i]] *= amount //Gets the key at position i, then the reagent amount of that key, then multiplies it by stack size
+
+/obj/item/stack/grind_requirements()
+ if(is_cyborg)
+ to_chat(usr, "[src] is electronically synthesized in your chassis and can't be ground up!")
+ return
+ return TRUE
/obj/item/stack/Initialize(mapload, new_amount=null , merge = TRUE)
. = ..()
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index 58aadadce0..fa7d14d572 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -131,7 +131,7 @@
..()
to_chat(user, "The mister snaps back onto the watertank.")
tank.on = 0
- loc = tank
+ forceMove(tank)
/obj/item/reagent_containers/spray/mister/attack_self()
return
@@ -236,13 +236,13 @@
tank = parent_tank
reagents = tank.reagents
max_water = tank.volume
- loc = tank
+ forceMove(tank)
/obj/item/extinguisher/mini/nozzle/Move()
..()
if(loc != tank.loc)
- loc = tank
+ forceMove(tank)
return
/obj/item/extinguisher/mini/nozzle/attack_self(mob/user)
@@ -268,7 +268,7 @@
..()
to_chat(user, "The nozzle snaps back onto the tank!")
tank.on = 0
- loc = tank
+ forceMove(tank)
/obj/item/extinguisher/mini/nozzle/afterattack(atom/target, mob/user)
if(nozzle_mode == EXTINGUISHER)
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index e82f536dad..259193b177 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -182,7 +182,7 @@
src.add_fingerprint(user)
if (src.bullets < 1)
user.show_message("*click*", 2)
- playsound(src, "gun_dry_fire", 50, 1)
+ playsound(src, "gun_dry_fire", 60, 1)
return
playsound(user, 'sound/weapons/gunshot.ogg', 100, 1)
src.bullets--
diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm
index c9552a3d39..b1313ef84f 100644
--- a/code/game/objects/items/trash.dm
+++ b/code/game/objects/items/trash.dm
@@ -66,6 +66,7 @@
name = "crushed can"
icon_state = "cola"
resistance_flags = NONE
+ grind_results = list("aluminum" = 10)
/obj/item/trash/attack(mob/M, mob/living/user)
return
@@ -75,6 +76,7 @@
icon = 'icons/obj/mining.dmi'
icon_state = "slag"
desc = "Someone's gotten on the naughty list."
+ grind_results = list("carbon" = 20)
/obj/item/trash/coal/burn()
visible_message("[src] fuses into a diamond! Someone wasn't so naughty after all...")
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index 9058e837ab..58758668c3 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -429,6 +429,10 @@
var/obj/item/grenade/explosive = null
var/war_cry = "AAAAARGH!!!"
+/obj/item/twohanded/spear/Initialize()
+ . = ..()
+ AddComponent(/datum/component/jousting)
+
/obj/item/twohanded/spear/examine(mob/user)
..()
if(explosive)
@@ -447,7 +451,7 @@
return
if(explosive && wielded)
user.say("[war_cry]")
- explosive.loc = AM
+ explosive.forceMove(AM)
explosive.prime()
qdel(src)
diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm
index 39fbbe3335..aabbba6b2f 100644
--- a/code/game/objects/structures/artstuff.dm
+++ b/code/game/objects/structures/artstuff.dm
@@ -20,7 +20,7 @@
var/obj/item/canvas/C = I
user.dropItemToGround(C)
painting = C
- C.loc = get_turf(src)
+ C.forceMove(get_turf(src))
C.layer = layer+0.1
user.visible_message("[user] puts \the [C] on \the [src].","You place \the [C] on \the [src].")
else
@@ -32,7 +32,7 @@
var/turf/T = get_turf(src)
..()
if(painting && painting.loc == T) //Only move if it's near us.
- painting.loc = get_turf(src)
+ painting.forceMove(get_turf(src))
else
painting = null
diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm
index 241d7ea41c..30384d2da9 100644
--- a/code/game/objects/structures/displaycase.dm
+++ b/code/game/objects/structures/displaycase.dm
@@ -224,7 +224,7 @@
G.use(10)
var/obj/structure/displaycase/display = new(src.loc)
if(electronics)
- electronics.loc = display
+ electronics.forceMove(display)
display.electronics = electronics
if(electronics.one_access)
display.req_one_access = electronics.accesses
diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm
index 81c9e9cc63..f2b0efb6b7 100644
--- a/code/game/objects/structures/electricchair.dm
+++ b/code/game/objects/structures/electricchair.dm
@@ -15,7 +15,7 @@
var/obj/structure/chair/C = new /obj/structure/chair(loc)
playsound(loc, W.usesound, 50, 1)
C.setDir(dir)
- part.loc = loc
+ part.forceMove(loc)
part.master = null
part = null
qdel(src)
diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm
index 5f1fa2ebb7..d6b50d0b1a 100644
--- a/code/game/objects/structures/kitchen_spike.dm
+++ b/code/game/objects/structures/kitchen_spike.dm
@@ -81,7 +81,7 @@
return
playsound(src.loc, 'sound/effects/splat.ogg', 25, 1)
L.visible_message("[user] slams [L] onto the meat spike!", "[user] slams you onto the meat spike!", "You hear a squishy wet noise.")
- L.loc = src.loc
+ L.forceMove(drop_location())
L.emote("scream")
L.add_splatter_floor()
L.adjustBruteLoss(30)
diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm
index aeca1453e3..f667832843 100644
--- a/code/game/objects/structures/noticeboard.dm
+++ b/code/game/objects/structures/noticeboard.dm
@@ -18,7 +18,7 @@
if(notices > 4)
break
if(istype(I, /obj/item/paper))
- I.loc = src
+ I.forceMove(src)
notices++
icon_state = "nboard0[notices]"
@@ -58,7 +58,7 @@
return
var/obj/item/I = locate(href_list["remove"]) in contents
if(istype(I) && I.loc == src)
- I.loc = usr.loc
+ I.forceMove(usr.loc)
usr.put_in_hands(I)
notices--
icon_state = "nboard0[notices]"
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 65d25055f8..95c2380802 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -121,7 +121,7 @@
T.quick_empty()
for(var/obj/item/C in oldContents)
- C.loc = src.loc
+ C.forceMove(drop_location())
user.visible_message("[user] empties [I] on [src].")
return
diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm
index c3496678c2..58b4186ad5 100644
--- a/code/game/objects/structures/target_stake.dm
+++ b/code/game/objects/structures/target_stake.dm
@@ -18,7 +18,7 @@
/obj/structure/target_stake/Move()
..()
if(pinned_target)
- pinned_target.loc = loc
+ pinned_target.forceMove(loc)
/obj/structure/target_stake/attackby(obj/item/target/T, mob/user)
if(pinned_target)
@@ -36,7 +36,7 @@
/obj/structure/target_stake/proc/removeTarget(mob/user)
pinned_target.layer = OBJ_LAYER
- pinned_target.loc = user.loc
+ pinned_target.forceMove(user.loc)
pinned_target.nullPinnedLoc()
nullPinnedTarget()
if(ishuman(user))
@@ -44,7 +44,7 @@
user.put_in_hands(pinned_target)
to_chat(user, "You take the target out of the stake.")
else
- pinned_target.loc = get_turf(user)
+ pinned_target.forceMove(user.drop_location())
to_chat(user, "You take the target out of the stake.")
/obj/structure/target_stake/bullet_act(obj/item/projectile/P)
diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm
index b29df0aaf4..bb5be3a501 100644
--- a/code/game/objects/structures/windoor_assembly.dm
+++ b/code/game/objects/structures/windoor_assembly.dm
@@ -216,13 +216,13 @@
if(do_after(user, 40, target = src))
if(!src || electronics)
- W.loc = src.loc
+ W.forceMove(drop_location())
return
to_chat(user, "You install the airlock electronics.")
name = "near finished windoor assembly"
electronics = W
else
- W.loc = loc
+ W.forceMove(drop_location())
//Screwdriver to remove airlock electronics. Step 6 undone.
else if(istype(W, /obj/item/screwdriver))
@@ -240,7 +240,7 @@
var/obj/item/electronics/airlock/ae
ae = electronics
electronics = null
- ae.loc = loc
+ ae.forceMove(drop_location())
else if(istype(W, /obj/item/pen))
var/t = stripped_input(user, "Enter the name for the door.", name, created_name,MAX_NAME_LEN)
@@ -285,7 +285,7 @@
else
windoor.req_access = electronics.accesses
windoor.electronics = electronics
- electronics.loc = windoor
+ electronics.forceMove(windoor)
if(created_name)
windoor.name = created_name
qdel(src)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 5380f0ca20..f5aec5c274 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -283,11 +283,10 @@
return
if(!disassembled)
playsound(src, breaksound, 70, 1)
- var/turf/T = loc
if(!(flags_1 & NODECONSTRUCT_1))
for(var/i in debris)
var/obj/item/I = i
- I.loc = T
+ I.forceMove(drop_location())
transfer_fingerprints_to(I)
qdel(src)
update_nearby_icons()
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 085c5eecd5..9cfa197738 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -182,7 +182,15 @@
if("bullet_miss")
soundin = pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg')
if("gun_dry_fire")
- soundin = pick('sound/weapons/dry_fire_1.ogg', 'sound/weapons/dry_fire_2.ogg', 'sound/weapons/dry_fire_3.ogg', 'sound/weapons/dry_fire_4.ogg')
+ soundin = pick('sound/weapons/gun_dry_fire_1.ogg', 'sound/weapons/gun_dry_fire_2.ogg', 'sound/weapons/gun_dry_fire_3.ogg', 'sound/weapons/gun_dry_fire_4.ogg')
+ if("gun_insert_empty_magazine")
+ soundin = pick('sound/weapons/gun_magazine_insert_empty_1.ogg', 'sound/weapons/gun_magazine_insert_empty_2.ogg', 'sound/weapons/gun_magazine_insert_empty_3.ogg', 'sound/weapons/gun_magazine_insert_empty_4.ogg')
+ if("gun_insert_full_magazine")
+ soundin = pick('sound/weapons/gun_magazine_insert_full_1.ogg', 'sound/weapons/gun_magazine_insert_full_2.ogg', 'sound/weapons/gun_magazine_insert_full_3.ogg', 'sound/weapons/gun_magazine_insert_full_4.ogg', 'sound/weapons/gun_magazine_insert_full_5.ogg')
+ if("gun_remove_empty_magazine")
+ soundin = pick('sound/weapons/gun_magazine_remove_empty_1.ogg', 'sound/weapons/gun_magazine_remove_empty_2.ogg', 'sound/weapons/gun_magazine_remove_empty_3.ogg', 'sound/weapons/gun_magazine_remove_empty_4.ogg')
+ if("gun_slide_lock")
+ soundin = pick('sound/weapons/gun_slide_lock_1.ogg', 'sound/weapons/gun_slide_lock_2.ogg', 'sound/weapons/gun_slide_lock_3.ogg', 'sound/weapons/gun_slide_lock_4.ogg', 'sound/weapons/gun_slide_lock_5.ogg')
if("law")
soundin = pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg')
if("honkbot_e")
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index 1d7b32e3a2..b1e8215592 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -141,7 +141,7 @@
var/mob/living/L = A
if(L.pulling)
var/turf/T = get_step(L.loc,turn(A.dir, 180))
- L.pulling.loc = T
+ L.pulling.forceMove(T)
//now we're on the new z_level, proceed the space drifting
stoplag()//Let a diagonal move finish, if necessary
@@ -202,4 +202,3 @@
destination_x = dest_x
destination_y = dest_y
destination_z = dest_z
-
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 22365c4584..0b0957e072 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -720,41 +720,43 @@
/datum/admins/proc/manage_free_slots()
if(!check_rights())
return
- var/dat = "
| [J_title]: | [J_opPos]/[job.total_positions < 0 ? " (unlimited)" : J_totPos]"
if(job.title == "AI" || job.title == "Cyborg")
- dat += " (Cannot Late Join) " + dat += " (Cannot Late Join) | "
continue
- if(job.total_positions >= 0)
- dat += " Add | "
- if(job.total_positions > job.current_positions)
- dat += "Remove | "
- else
- dat += "Remove | "
- dat += "Unlimit"
else
- dat += " Limit"
- dat += "" + if(job.total_positions >= 0) + dat += "Add | " + if(job.total_positions > job.current_positions) + dat += "Remove | " + else + dat += "Remove | " + dat += "Unlimit | " + else + dat += "Limit" - dat += "" - var/winheight = 100 + (count * 20) - winheight = min(winheight, 690) - usr << browse(dat, "window=players;size=375x[winheight]") + browser.height = min(100 + count * 20, 650) + browser.set_content(dat.Join()) + browser.open() /datum/admins/proc/create_or_modify_area() set category = "Debug" diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index 6e327db6b5..f259e9b1e9 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -11,6 +11,8 @@ return switch(subject) if("notes, memos, watchlist") + if(!check_rights(R_ADMIN)) + return browse_messages() else var/F = file("[GLOB.log_directory]/[subject].html") diff --git a/code/modules/admin/chat_commands.dm b/code/modules/admin/chat_commands.dm index 9a54d094e5..744455bb9a 100644 --- a/code/modules/admin/chat_commands.dm +++ b/code/modules/admin/chat_commands.dm @@ -47,7 +47,9 @@ target = AH.initiator_ckey else return "Ticket #[id] not found!" - return IrcPm(target, all_params.Join(" "), sender) + var/res = IrcPm(target, all_params.Join(" "), sender) + if(res != "Message Successful") + return res /datum/server_tools_command/namecheck name = "namecheck" diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm index 3336f3d0a8..480ba20b4d 100644 --- a/code/modules/admin/fun_balloon.dm +++ b/code/modules/admin/fun_balloon.dm @@ -95,7 +95,7 @@ var/obj/docking_port/stationary/SM = S if(SM.id == "emergency_home") var/new_dir = turn(SM.dir, 180) - SM.loc = get_ranged_target_turf(SM, new_dir, rand(3,15)) + SM.forceMove(get_ranged_target_turf(SM, new_dir, rand(3,15))) break qdel(src) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 0cec1ef3a8..91769ac55a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -58,6 +58,8 @@ toggle_exempt_status(C) else if(href_list["makeAntag"]) + if(!check_rights(R_ADMIN)) + return if (!SSticker.mode) to_chat(usr, "Not until the round starts!") return @@ -201,7 +203,8 @@ return else if(href_list["dbbanaddtype"]) - + if(!check_rights(R_BAN)) + return var/bantype = text2num(href_list["dbbanaddtype"]) var/banckey = href_list["dbbanaddckey"] var/banip = href_list["dbbanaddip"] @@ -599,6 +602,8 @@ return else if(href_list["jobban2"]) + if(!check_rights(R_BAN)) + return var/mob/M = locate(href_list["jobban2"]) if(!ismob(M)) to_chat(usr, "This can only be used on instances of type /mob.") @@ -1029,6 +1034,8 @@ return 0 //we didn't do anything! else if(href_list["boot2"]) + if(!check_rights(R_ADMIN)) + return var/mob/M = locate(href_list["boot2"]) if (ismob(M)) if(!check_if_greater_rights_than(M.client)) @@ -1041,72 +1048,110 @@ qdel(M.client) else if(href_list["addmessage"]) + if(!check_rights(R_ADMIN)) + return var/target_ckey = href_list["addmessage"] create_message("message", target_ckey, secret = 0) else if(href_list["addnote"]) + if(!check_rights(R_ADMIN)) + return var/target_ckey = href_list["addnote"] create_message("note", target_ckey) else if(href_list["addwatch"]) + if(!check_rights(R_ADMIN)) + return var/target_ckey = href_list["addwatch"] create_message("watchlist entry", target_ckey, secret = 1) else if(href_list["addmemo"]) + if(!check_rights(R_ADMIN)) + return create_message("memo", secret = 0, browse = 1) else if(href_list["addmessageempty"]) + if(!check_rights(R_ADMIN)) + return create_message("message", secret = 0) else if(href_list["addnoteempty"]) + if(!check_rights(R_ADMIN)) + return create_message("note") else if(href_list["addwatchempty"]) + if(!check_rights(R_ADMIN)) + return create_message("watchlist entry", secret = 1) else if(href_list["deletemessage"]) + if(!check_rights(R_ADMIN)) + return var/message_id = href_list["deletemessage"] delete_message(message_id) else if(href_list["deletemessageempty"]) + if(!check_rights(R_ADMIN)) + return var/message_id = href_list["deletemessageempty"] delete_message(message_id, browse = 1) else if(href_list["editmessage"]) + if(!check_rights(R_ADMIN)) + return var/message_id = href_list["editmessage"] edit_message(message_id) else if(href_list["editmessageempty"]) + if(!check_rights(R_ADMIN)) + return var/message_id = href_list["editmessageempty"] edit_message(message_id, browse = 1) else if(href_list["secretmessage"]) + if(!check_rights(R_ADMIN)) + return var/message_id = href_list["secretmessage"] toggle_message_secrecy(message_id) else if(href_list["searchmessages"]) + if(!check_rights(R_ADMIN)) + return var/target = href_list["searchmessages"] browse_messages(index = target) else if(href_list["nonalpha"]) + if(!check_rights(R_ADMIN)) + return var/target = href_list["nonalpha"] target = text2num(target) browse_messages(index = target) else if(href_list["showmessages"]) + if(!check_rights(R_ADMIN)) + return var/target = href_list["showmessages"] browse_messages(index = target) else if(href_list["showmemo"]) + if(!check_rights(R_ADMIN)) + return browse_messages("memo") else if(href_list["showwatch"]) + if(!check_rights(R_ADMIN)) + return browse_messages("watchlist entry") else if(href_list["showwatchfilter"]) + if(!check_rights(R_ADMIN)) + return browse_messages("watchlist entry", filter = 1) else if(href_list["showmessageckey"]) + if(!check_rights(R_ADMIN)) + return var/target = href_list["showmessageckey"] var/agegate = TRUE if (href_list["showall"]) @@ -1118,6 +1163,8 @@ browse_messages(target_ckey = target, linkless = 1) else if(href_list["messageedits"]) + if(!check_rights(R_ADMIN)) + return var/message_id = sanitizeSQL("[href_list["messageedits"]]") var/datum/DBQuery/query_get_message_edits = SSdbcore.NewQuery("SELECT edits FROM [format_table_name("messages")] WHERE id = '[message_id]'") if(!query_get_message_edits.warn_execute()) @@ -1307,7 +1354,7 @@ if(alert(usr, "Send [key_name(M)] to Prison?", "Message", "Yes", "No") != "Yes") return - M.loc = pick(GLOB.prisonwarp) + M.forceMove(pick(GLOB.prisonwarp)) to_chat(M, "You have been sent to Prison!") log_admin("[key_name(usr)] has sent [key_name(M)] to Prison!") @@ -1543,7 +1590,7 @@ C.admin_ghost() var/mob/dead/observer/A = C.mob A.ManualFollow(AM) - + else if(href_list["admingetmovable"]) if(!check_rights(R_ADMIN)) return @@ -1568,9 +1615,13 @@ C.jumptocoord(x,y,z) else if(href_list["adminchecklaws"]) + if(!check_rights(R_ADMIN)) + return output_ai_laws() else if(href_list["admincheckdevilinfo"]) + if(!check_rights(R_ADMIN)) + return var/mob/M = locate(href_list["admincheckdevilinfo"]) output_devil_info(M) @@ -1979,20 +2030,28 @@ Secrets_topic(href_list["secrets"],href_list) else if(href_list["ac_view_wanted"]) //Admin newscaster Topic() stuff be here + if(!check_rights(R_ADMIN)) + return src.admincaster_screen = 18 //The ac_ prefix before the hrefs stands for AdminCaster. src.access_news_network() else if(href_list["ac_set_channel_name"]) + if(!check_rights(R_ADMIN)) + return src.admincaster_feed_channel.channel_name = stripped_input(usr, "Provide a Feed Channel Name.", "Network Channel Handler", "") while (findtext(src.admincaster_feed_channel.channel_name," ") == 1) src.admincaster_feed_channel.channel_name = copytext(src.admincaster_feed_channel.channel_name,2,lentext(src.admincaster_feed_channel.channel_name)+1) src.access_news_network() else if(href_list["ac_set_channel_lock"]) + if(!check_rights(R_ADMIN)) + return src.admincaster_feed_channel.locked = !src.admincaster_feed_channel.locked src.access_news_network() else if(href_list["ac_submit_new_channel"]) + if(!check_rights(R_ADMIN)) + return var/check = 0 for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels) if(FC.channel_name == src.admincaster_feed_channel.channel_name) @@ -2010,6 +2069,8 @@ src.access_news_network() else if(href_list["ac_set_channel_receiving"]) + if(!check_rights(R_ADMIN)) + return var/list/available_channels = list() for(var/datum/newscaster/feed_channel/F in GLOB.news_network.network_channels) available_channels += F.channel_name @@ -2017,12 +2078,16 @@ src.access_news_network() else if(href_list["ac_set_new_message"]) + if(!check_rights(R_ADMIN)) + return src.admincaster_feed_message.body = adminscrub(input(usr, "Write your Feed story.", "Network Channel Handler", "")) while (findtext(src.admincaster_feed_message.returnBody(-1)," ") == 1) src.admincaster_feed_message.body = copytext(src.admincaster_feed_message.returnBody(-1),2,lentext(src.admincaster_feed_message.returnBody(-1))+1) src.access_news_network() else if(href_list["ac_submit_new_message"]) + if(!check_rights(R_ADMIN)) + return if(src.admincaster_feed_message.returnBody(-1) =="" || src.admincaster_feed_message.returnBody(-1) =="\[REDACTED\]" || src.admincaster_feed_channel.channel_name == "" ) src.admincaster_screen = 6 else @@ -2037,22 +2102,32 @@ src.access_news_network() else if(href_list["ac_create_channel"]) + if(!check_rights(R_ADMIN)) + return src.admincaster_screen=2 src.access_news_network() else if(href_list["ac_create_feed_story"]) + if(!check_rights(R_ADMIN)) + return src.admincaster_screen=3 src.access_news_network() else if(href_list["ac_menu_censor_story"]) + if(!check_rights(R_ADMIN)) + return src.admincaster_screen=10 src.access_news_network() else if(href_list["ac_menu_censor_channel"]) + if(!check_rights(R_ADMIN)) + return src.admincaster_screen=11 src.access_news_network() else if(href_list["ac_menu_wanted"]) + if(!check_rights(R_ADMIN)) + return var/already_wanted = 0 if(GLOB.news_network.wanted_issue.active) already_wanted = 1 @@ -2064,18 +2139,24 @@ src.access_news_network() else if(href_list["ac_set_wanted_name"]) + if(!check_rights(R_ADMIN)) + return src.admincaster_wanted_message.criminal = adminscrub(input(usr, "Provide the name of the Wanted person.", "Network Security Handler", "")) while(findtext(src.admincaster_wanted_message.criminal," ") == 1) src.admincaster_wanted_message.criminal = copytext(admincaster_wanted_message.criminal,2,lentext(admincaster_wanted_message.criminal)+1) src.access_news_network() else if(href_list["ac_set_wanted_desc"]) + if(!check_rights(R_ADMIN)) + return src.admincaster_wanted_message.body = adminscrub(input(usr, "Provide the a description of the Wanted person and any other details you deem important.", "Network Security Handler", "")) while (findtext(src.admincaster_wanted_message.body," ") == 1) src.admincaster_wanted_message.body = copytext(src.admincaster_wanted_message.body,2,lentext(src.admincaster_wanted_message.body)+1) src.access_news_network() else if(href_list["ac_submit_wanted"]) + if(!check_rights(R_ADMIN)) + return var/input_param = text2num(href_list["ac_submit_wanted"]) if(src.admincaster_wanted_message.criminal == "" || src.admincaster_wanted_message.body == "") src.admincaster_screen = 16 @@ -2092,6 +2173,8 @@ src.access_news_network() else if(href_list["ac_cancel_wanted"]) + if(!check_rights(R_ADMIN)) + return var/choice = alert("Please confirm Wanted Issue removal.","Network Security Handler","Confirm","Cancel") if(choice=="Confirm") GLOB.news_network.deleteWanted() @@ -2099,36 +2182,50 @@ src.access_news_network() else if(href_list["ac_censor_channel_author"]) + if(!check_rights(R_ADMIN)) + return var/datum/newscaster/feed_channel/FC = locate(href_list["ac_censor_channel_author"]) FC.toggleCensorAuthor() src.access_news_network() else if(href_list["ac_censor_channel_story_author"]) + if(!check_rights(R_ADMIN)) + return var/datum/newscaster/feed_message/MSG = locate(href_list["ac_censor_channel_story_author"]) MSG.toggleCensorAuthor() src.access_news_network() else if(href_list["ac_censor_channel_story_body"]) + if(!check_rights(R_ADMIN)) + return var/datum/newscaster/feed_message/MSG = locate(href_list["ac_censor_channel_story_body"]) MSG.toggleCensorBody() src.access_news_network() else if(href_list["ac_pick_d_notice"]) + if(!check_rights(R_ADMIN)) + return var/datum/newscaster/feed_channel/FC = locate(href_list["ac_pick_d_notice"]) src.admincaster_feed_channel = FC src.admincaster_screen=13 src.access_news_network() else if(href_list["ac_toggle_d_notice"]) + if(!check_rights(R_ADMIN)) + return var/datum/newscaster/feed_channel/FC = locate(href_list["ac_toggle_d_notice"]) FC.toggleCensorDclass() src.access_news_network() else if(href_list["ac_view"]) + if(!check_rights(R_ADMIN)) + return src.admincaster_screen=1 src.access_news_network() else if(href_list["ac_setScreen"]) //Brings us to the main menu and resets all fields~ + if(!check_rights(R_ADMIN)) + return src.admincaster_screen = text2num(href_list["ac_setScreen"]) if (src.admincaster_screen == 0) if(src.admincaster_feed_channel) @@ -2140,25 +2237,35 @@ src.access_news_network() else if(href_list["ac_show_channel"]) + if(!check_rights(R_ADMIN)) + return var/datum/newscaster/feed_channel/FC = locate(href_list["ac_show_channel"]) src.admincaster_feed_channel = FC src.admincaster_screen = 9 src.access_news_network() else if(href_list["ac_pick_censor_channel"]) + if(!check_rights(R_ADMIN)) + return var/datum/newscaster/feed_channel/FC = locate(href_list["ac_pick_censor_channel"]) src.admincaster_feed_channel = FC src.admincaster_screen = 12 src.access_news_network() else if(href_list["ac_refresh"]) + if(!check_rights(R_ADMIN)) + return src.access_news_network() else if(href_list["ac_set_signature"]) + if(!check_rights(R_ADMIN)) + return src.admin_signature = adminscrub(input(usr, "Provide your desired signature.", "Network Identity Handler", "")) src.access_news_network() else if(href_list["ac_del_comment"]) + if(!check_rights(R_ADMIN)) + return var/datum/newscaster/feed_comment/FC = locate(href_list["ac_del_comment"]) var/datum/newscaster/feed_message/FM = locate(href_list["ac_del_comment_msg"]) FM.comments -= FC @@ -2166,6 +2273,8 @@ src.access_news_network() else if(href_list["ac_lock_comment"]) + if(!check_rights(R_ADMIN)) + return var/datum/newscaster/feed_message/FM = locate(href_list["ac_lock_comment"]) FM.locked ^= 1 src.access_news_network() @@ -2262,6 +2371,8 @@ error_viewer.show_to(owner, null, href_list["viewruntime_linear"]) else if(href_list["showrelatedacc"]) + if(!check_rights(R_ADMIN)) + return var/client/C = locate(href_list["client"]) in GLOB.clients var/thing_to_check if(href_list["showrelatedacc"] == "cid") diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index 1e7f89fc8d..779ea64640 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -34,7 +34,7 @@ log_admin("[key_name(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]") message_admins("[key_name_admin(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]") - usr.loc = T + usr.forceMove(T) SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Turf") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return @@ -137,7 +137,7 @@ admin_ticket_log(M, msg) if(M) M.forceMove(get_turf(usr)) - usr.loc = M.loc + usr.forceMove(M.loc) SSblackbox.record_feedback("tally", "admin_verb", 1, "Get Key") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/sendmob(mob/M in sortmobs()) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index b96c8f4bdc..b02fe03c18 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -739,7 +739,7 @@ GLOBAL_PROTECT(LastAdminCalledProc) Plasma.air_contents.gases[/datum/gas/plasma][MOLES] = 70 Rad.drainratio = 0 Rad.loaded_tank = Plasma - Plasma.loc = Rad + Plasma.forceMove(Rad) if(!Rad.active) Rad.toggle_power() diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index b929e83ada..6ac1ef093d 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -88,10 +88,10 @@ return 0 if(a_left) a_left.holder = null - a_left.loc = T + a_left.forceMove(T) if(a_right) a_right.holder = null - a_right.loc = T + a_right.forceMove(T) qdel(src) else ..() diff --git a/code/modules/assembly/shock_kit.dm b/code/modules/assembly/shock_kit.dm index 1b21738391..174312df1e 100644 --- a/code/modules/assembly/shock_kit.dm +++ b/code/modules/assembly/shock_kit.dm @@ -1,42 +1,39 @@ -/obj/item/assembly/shock_kit - name = "electrohelmet assembly" - desc = "This appears to be made from both an electropack and a helmet." - icon = 'icons/obj/assemblies.dmi' - icon_state = "shock_kit" - var/obj/item/clothing/head/helmet/part1 = null - var/obj/item/device/electropack/part2 = null - w_class = WEIGHT_CLASS_HUGE +/obj/item/assembly/shock_kit + name = "electrohelmet assembly" + desc = "This appears to be made from both an electropack and a helmet." + icon = 'icons/obj/assemblies.dmi' + icon_state = "shock_kit" + var/obj/item/clothing/head/helmet/part1 = null + var/obj/item/device/electropack/part2 = null + w_class = WEIGHT_CLASS_HUGE flags_1 = CONDUCT_1 - -/obj/item/assembly/shock_kit/Destroy() - qdel(part1) - qdel(part2) - return ..() - -/obj/item/assembly/shock_kit/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/wrench)) - var/turf/T = loc - if(ismob(T)) - T = T.loc - part1.loc = T - part2.loc = T - part1.master = null - part2.master = null - part1 = null - part2 = null - qdel(src) - return - add_fingerprint(user) - return - -/obj/item/assembly/shock_kit/attack_self(mob/user) - part1.attack_self(user) - part2.attack_self(user) - add_fingerprint(user) - return - -/obj/item/assembly/shock_kit/receive_signal() - if(istype(loc, /obj/structure/chair/e_chair)) - var/obj/structure/chair/e_chair/C = loc - C.shock() - return + +/obj/item/assembly/shock_kit/Destroy() + qdel(part1) + qdel(part2) + return ..() + +/obj/item/assembly/shock_kit/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/wrench)) + part1.forceMove(drop_location()) + part2.forceMove(drop_location()) + part1.master = null + part2.master = null + part1 = null + part2 = null + qdel(src) + return + add_fingerprint(user) + return + +/obj/item/assembly/shock_kit/attack_self(mob/user) + part1.attack_self(user) + part2.attack_self(user) + add_fingerprint(user) + return + +/obj/item/assembly/shock_kit/receive_signal() + if(istype(loc, /obj/structure/chair/e_chair)) + var/obj/structure/chair/e_chair/C = loc + C.shock() + return diff --git a/code/modules/atmospherics/machinery/portable/pump.dm b/code/modules/atmospherics/machinery/portable/pump.dm index 807759e43c..36dd30731e 100644 --- a/code/modules/atmospherics/machinery/portable/pump.dm +++ b/code/modules/atmospherics/machinery/portable/pump.dm @@ -135,7 +135,7 @@ investigate_log("was set to [pump.target_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS) if("eject") if(holding) - holding.loc = get_turf(src) + holding.forceMove(drop_location()) holding = null . = TRUE update_icon() diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm index 564e6d294f..3ba7e0a110 100644 --- a/code/modules/atmospherics/machinery/portable/scrubber.dm +++ b/code/modules/atmospherics/machinery/portable/scrubber.dm @@ -96,7 +96,7 @@ . = TRUE if("eject") if(holding) - holding.loc = get_turf(src) + holding.forceMove(drop_location()) holding = null . = TRUE if("toggle_filter") diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index 15c5deb4cb..90b2e3a02e 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -199,9 +199,9 @@ GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation) active = 1 update_icon() -/obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/carbon/C) - for(var/obj/item/implant/exile/E in C.implants)//Checking that there is an exile implant - to_chat(C, "\black The station gate has detected your exile implant and is blocking your entry.") +/obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/L) + for(var/obj/item/implant/exile/E in L.implants)//Checking that there is an exile implant + to_chat(L, "\black The station gate has detected your exile implant and is blocking your entry.") return TRUE return FALSE @@ -212,17 +212,17 @@ GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation) return if(!stationgate || QDELETED(stationgate)) return - if(istype(AM, /mob/living/carbon)) + if(isliving(AM)) if(check_exile_implant(AM)) return else - for(var/mob/living/carbon/C in AM.contents) - if(check_exile_implant(C)) + for(var/mob/living/L in AM.contents) + if(check_exile_implant(L)) say("Rejecting [AM]: Exile implant detected in contained lifeform.") return if(AM.has_buckled_mobs()) - for(var/mob/living/carbon/C in AM.buckled_mobs) - if(check_exile_implant(C)) + for(var/mob/living/L in AM.buckled_mobs) + if(check_exile_implant(L)) say("Rejecting [AM]: Exile implant detected in close proximity lifeform.") return AM.forceMove(get_step(stationgate.loc, SOUTH)) diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm index 5af834955f..bf256fecbd 100644 --- a/code/modules/awaymissions/mission_code/Academy.dm +++ b/code/modules/awaymissions/mission_code/Academy.dm @@ -207,7 +207,7 @@ //Swarm of creatures for(var/direction in GLOB.alldirs) var/turf/T = get_turf(src) - new /mob/living/simple_animal/hostile/creature(get_step(T,direction)) + new /mob/living/simple_animal/hostile/netherworld(get_step(T,direction)) if(4) //Destroy Equipment for (var/obj/item/I in user) diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 5691dbb782..15d4579d33 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -283,7 +283,7 @@ for(var/obj/item/device/flashlight/seclite/S in src) to_chat(user, "You unscrew the seclite from [src].") F = null - S.loc = get_turf(user) + S.forceMove(user.drop_location()) update_helmlight(user) S.update_brightness(user) update_icon() diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm index 1715636b57..2b25188b80 100644 --- a/code/modules/clothing/spacesuits/chronosuit.dm +++ b/code/modules/clothing/spacesuits/chronosuit.dm @@ -98,7 +98,7 @@ I.flags_1 &= ~NODROP_1 if(camera) camera.remove_target_ui() - camera.loc = user + camera.forceMove(user) teleport_now.UpdateButtonIcon() /obj/item/clothing/suit/space/chronos/proc/chronowalk(atom/location) @@ -278,19 +278,19 @@ if(loc == user) forceMove(get_turf(user)) if(user.client && user.client.eye != src) - src.loc = get_turf(user) + src.forceMove(user.drop_location()) user.reset_perspective(src) user.set_machine(src) var/atom/step = get_step(src, direction) if(step) if((step.x <= TRANSITIONEDGE) || (step.x >= (world.maxx - TRANSITIONEDGE - 1)) || (step.y <= TRANSITIONEDGE) || (step.y >= (world.maxy - TRANSITIONEDGE - 1))) if(!src.Move(step)) - src.loc = step + src.forceMove(step) else - src.loc = step + src.forceMove(step) if((x == holder.x) && (y == holder.y) && (z == holder.z)) remove_target_ui() - loc = user + forceMove(user) else if(!target_ui) create_target_ui() phase_time = world.time + phase_time_length diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 73d7ee04e8..58eac96f78 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -136,7 +136,7 @@ return jetpack.turn_off() - jetpack.loc = get_turf(src) + jetpack.forceMove(drop_location()) jetpack = null to_chat(user, "You successfully remove the jetpack from [src].") diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm index f983ca2563..94ca764384 100644 --- a/code/modules/clothing/under/accessories.dm +++ b/code/modules/clothing/under/accessories.dm @@ -15,11 +15,11 @@ if(U.pockets) // storage items conflict return FALSE - pockets.loc = U + pockets.forceMove(U) U.pockets = pockets U.attached_accessory = src - loc = U + forceMove(U) layer = FLOAT_LAYER plane = FLOAT_PLANE if(minimize_when_attached) @@ -39,7 +39,7 @@ /obj/item/clothing/accessory/proc/detach(obj/item/clothing/under/U, user) if(pockets && pockets == U.pockets) - pockets.loc = src + pockets.forceMove(src) U.pockets = null for(var/armor_type in armor) diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm index dbde34d84d..1eae6c7899 100644 --- a/code/modules/events/disease_outbreak.dm +++ b/code/modules/events/disease_outbreak.dm @@ -10,6 +10,8 @@ var/virus_type + var/max_severity = 3 + /datum/round_event/disease_outbreak/announce(fake) priority_announce("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak7.ogg') @@ -17,6 +19,7 @@ /datum/round_event/disease_outbreak/setup() announceWhen = rand(15, 30) + /datum/round_event/disease_outbreak/start() var/advanced_virus = FALSE max_severity = 3 + max(FLOOR((world.time - control.earliest_start)/6000, 1),0) //3 symptoms at 20 minutes, plus 1 per 10 minutes @@ -46,16 +49,48 @@ continue var/datum/disease/D - if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work. - if(!H.dna || (H.disabilities & BLIND)) //A blindness disease would be the worst. - continue - D = new virus_type() - var/datum/disease/dnaspread/DS = D - DS.strain_data["name"] = H.real_name - DS.strain_data["UI"] = H.dna.uni_identity - DS.strain_data["SE"] = H.dna.struc_enzymes + if(!advanced_virus) + if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work. + if(!H.dna || (H.has_disability(BLIND))) //A blindness disease would be the worst. + continue + D = new virus_type() + var/datum/disease/dnaspread/DS = D + DS.strain_data["name"] = H.real_name + DS.strain_data["UI"] = H.dna.uni_identity + DS.strain_data["SE"] = H.dna.struc_enzymes + else + D = new virus_type() else - D = new virus_type() + D = make_virus(max_severity, max_severity) D.carrier = TRUE H.AddDisease(D) + + if(advanced_virus) + var/datum/disease/advance/A = D + var/list/name_symptoms = list() //for feedback + for(var/datum/symptom/S in A.symptoms) + name_symptoms += S.name + message_admins("An event has triggered a random advanced virus outbreak on [key_name_admin(H)]! It has these symptoms: [english_list(name_symptoms)]") + log_game("An event has triggered a random advanced virus outbreak on [key_name(H)]! It has these symptoms: [english_list(name_symptoms)]") break + +/datum/round_event/disease_outbreak/proc/make_virus(max_symptoms, max_level) + if(max_symptoms > SYMPTOM_LIMIT) + max_symptoms = SYMPTOM_LIMIT + var/datum/disease/advance/A = new(FALSE, null) + A.symptoms = list() + var/list/datum/symptom/possible_symptoms = list() + for(var/symptom in subtypesof(/datum/symptom)) + var/datum/symptom/S = symptom + if(initial(S.level) > max_level) + continue + if(initial(S.level) <= 0) //unobtainable symptoms + continue + possible_symptoms += S + for(var/i in 1 to max_symptoms) + var/datum/symptom/chosen_symptom = pick_n_take(possible_symptoms) + if(chosen_symptom) + var/datum/symptom/S = new chosen_symptom + A.symptoms += S + A.Refresh() //just in case someone already made and named the same disease + return A diff --git a/code/modules/events/wizard/race.dm b/code/modules/events/wizard/race.dm index 29773d95b2..5adc4bb851 100644 --- a/code/modules/events/wizard/race.dm +++ b/code/modules/events/wizard/race.dm @@ -12,7 +12,7 @@ for(var/speciestype in subtypesof(/datum/species)) var/datum/species/S = new speciestype() - if(!S.dangerous_existence) + if(!S.dangerous_existence && !S.blacklisted) all_species += speciestype var/datum/species/new_species = pick(all_species) diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index 7217fe0b28..6fb712ea41 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -393,6 +393,7 @@ container_type = NONE spillable = FALSE isGlass = FALSE + grind_results = list("aluminum" = 10) /obj/item/reagent_containers/food/drinks/soda_cans/attack(mob/M, mob/user) if(M == user && !src.reagents.total_volume && user.a_intent == INTENT_HARM && user.zone_selected == "head") diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm index 49f85a882d..7f574e0313 100644 --- a/code/modules/food_and_drinks/food/snacks.dm +++ b/code/modules/food_and_drinks/food/snacks.dm @@ -6,6 +6,7 @@ lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi' righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi' unique_rename = 1 + grind_results = list() //To let them be ground up to transfer their reagents var/bitesize = 2 var/bitecount = 0 var/trash = null diff --git a/code/modules/food_and_drinks/food/snacks_egg.dm b/code/modules/food_and_drinks/food/snacks_egg.dm index bfe181b419..10039f7a8b 100644 --- a/code/modules/food_and_drinks/food/snacks_egg.dm +++ b/code/modules/food_and_drinks/food/snacks_egg.dm @@ -20,6 +20,7 @@ filling_color = "#F0E68C" tastes = list("egg" = 1) foodtype = MEAT + grind_results = list("eggyolk" = 5) /obj/item/reagent_containers/food/snacks/egg/throw_impact(atom/hit_atom) if(!..()) //was it caught by a mob? diff --git a/code/modules/food_and_drinks/food/snacks_other.dm b/code/modules/food_and_drinks/food/snacks_other.dm index c32ebfb765..c7681fe807 100644 --- a/code/modules/food_and_drinks/food/snacks_other.dm +++ b/code/modules/food_and_drinks/food/snacks_other.dm @@ -28,6 +28,7 @@ filling_color = "#FF1493" tastes = list("watermelon" = 1) foodtype = FRUIT + juice_results = list("watermelonjuice" = 5) /obj/item/reagent_containers/food/snacks/candy_corn name = "candy corn" diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm index 9f76139151..dfa249c04d 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm @@ -277,9 +277,9 @@ operating = FALSE // Turn it off again aferwards icon_state = "mw" updateUsrDialog() + soundloop.stop() /obj/machinery/microwave/proc/stop() - soundloop.stop() abort() /obj/machinery/microwave/proc/dispose() @@ -293,7 +293,6 @@ icon_state = "mwbloody1" // Make it look dirty!! /obj/machinery/microwave/proc/muck_finish() - playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) visible_message("The microwave gets covered in muck!") dirty = 100 // Make it dirty so it can't be used util cleaned icon_state = "mwbloody" // Make it look dirty too @@ -303,6 +302,7 @@ if(prob(50)) new /obj/item/reagent_containers/food/snacks/badrecipe(src) qdel(S) + soundloop.stop() /obj/machinery/microwave/proc/broke() var/datum/effect_system/spark_spread/s = new @@ -314,6 +314,7 @@ flags_1 = null //So you can't add condiments operating = FALSE // Turn it off again aferwards updateUsrDialog() + soundloop.stop() /obj/machinery/microwave/Topic(href, href_list) if(..() || panel_open) diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm index 89f6316297..bceaf6d7dd 100644 --- a/code/modules/games/cards.dm +++ b/code/modules/games/cards.dm @@ -187,7 +187,7 @@ ASSERT(H) usr.visible_message("\The [usr] plays \the [card.name].") - H.loc = get_step(usr,usr.dir) + H.forceMove(get_step(usr,usr.dir)) src.update_icon() diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css index 4d31d082c6..3403253c07 100644 --- a/code/modules/goonchat/browserassets/css/browserOutput.css +++ b/code/modules/goonchat/browserassets/css/browserOutput.css @@ -38,6 +38,19 @@ img.icon { vertical-align: bottom; } + +.r:before { /* "repeated" badge class for combined messages */ + content: 'x'; +} +.r { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: 700; + line-height: 1; + color: #f00; +} + a {color: #0000ff;} a.visited {color: #ff00ff;} a:visited {color: #ff00ff;} @@ -377,6 +390,7 @@ h1.alert, h2.alert {color: #000000;} .memo {color: #638500; text-align: center;} .memoedit {text-align: center; font-size: 16px;} .abductor {color: #800080; font-style: italic;} +.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} .slime {color: #00CED1;} .drone {color: #848482;} .monkey {color: #975032;} diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html index 7b2d3ecfe0..82a1ed4885 100644 --- a/code/modules/goonchat/browserassets/html/browserOutput.html +++ b/code/modules/goonchat/browserassets/html/browserOutput.html @@ -39,6 +39,7 @@ Toggle ping display Highlight string Save chat log + Toggle line combining Clear all messages