diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index f5fa86a76d..a1c37bc290 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,3 +1,3 @@ -[Note]: # (Please enter the commit hash and active testmerge numbers from the "Show Server Revision" verb if you can. If you believe the issue to be caused by a testmerge, please report it in its relative PR thread. State what the issue is from a "whats wrong" prospective. Issue reports should clearly allow maintainers to understand whats wrong and how to test/reproduce if that is not obvious. Avoid ambiguity. Start your issue report below both of these lines (or remove them)) +[Note]: # (State what the issue is from a "whats wrong" perspective. Issue reports should clearly allow maintainers to understand whats wrong and how to test/reproduce if that is not obvious. Avoid ambiguity. Please enter the commit hash from the "Show Server Revision" verb if you can. Remove these notes before submitting your report.) -[Admins]: # (If you are reporting a bug that occured AFTER you used varedit/admin buttons to alter an object out of normal operating conditions, please verify that you can re-create the bug without the varedit usage/admin buttons before reporting the issue.) +[GameAdmins]: # (If you are reporting a bug that occurred AFTER you used varedit/admin buttons to alter an object out of normal operating conditions, please verify that you can re-create the bug without the varedit usage/admin buttons before reporting the issue.) diff --git a/Test.txt b/Test.txt index f052ebb735..68db24f630 100644 --- a/Test.txt +++ b/Test.txt @@ -1 +1 @@ -Ignore this again \ No newline at end of file +~~ \ No newline at end of file diff --git a/_maps/map_files/Cerestation/cerestation.dmm b/_maps/map_files/Cerestation/cerestation.dmm index f10211f5b1..860ff65d60 100644 --- a/_maps/map_files/Cerestation/cerestation.dmm +++ b/_maps/map_files/Cerestation/cerestation.dmm @@ -7034,8 +7034,8 @@ "anI" = ( /obj/docking_port/stationary/random{ dir = 1; - id = "pod_asteroid1"; - name = "asteroid" + id = "pod_lavaland1"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -8103,7 +8103,7 @@ /obj/machinery/computer/shuttle/pod{ pixel_x = -32; pixel_y = 0; - possible_destinations = "pod_asteroid1"; + possible_destinations = "pod_lavaland1"; shuttleId = "pod1" }, /obj/machinery/light/small{ @@ -40738,7 +40738,7 @@ /obj/machinery/computer/shuttle/pod{ pixel_x = 0; pixel_y = 32; - possible_destinations = "pod_asteroid3"; + possible_destinations = "pod_lavaland3"; shuttleId = "pod3" }, /obj/item/device/radio/intercom{ @@ -40760,8 +40760,8 @@ "btw" = ( /obj/docking_port/stationary/random{ dir = 4; - id = "pod_asteroid3"; - name = "asteroid" + id = "pod_lavaland3"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -68963,8 +68963,8 @@ "crd" = ( /obj/docking_port/stationary/random{ dir = 8; - id = "pod_asteroid2"; - name = "asteroid" + id = "pod_lavaland2"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -68979,7 +68979,7 @@ /obj/machinery/computer/shuttle/pod{ pixel_x = 0; pixel_y = -32; - possible_destinations = "pod_asteroid2"; + possible_destinations = "pod_lavaland2"; shuttleId = "pod2" }, /obj/structure/chair{ diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index c46f6ea830..d9122fa8b1 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -142,15 +142,15 @@ /area/solar/auxstarboard) "aap" = ( /obj/docking_port/stationary/random{ - id = "pod_asteroid1"; - name = "asteroid" + id = "pod_lavaland1"; + name = "lavaland" }, /turf/open/space, /area/space) "aaq" = ( /obj/docking_port/stationary/random{ - id = "pod_asteroid2"; - name = "asteroid" + id = "pod_lavaland2"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -203,7 +203,7 @@ }, /obj/machinery/computer/shuttle/pod{ pixel_x = -32; - possible_destinations = "pod_asteroid1"; + possible_destinations = "pod_lavaland1"; shuttleId = "pod1" }, /obj/effect/turf_decal/stripes/line{ @@ -226,7 +226,7 @@ }, /obj/machinery/computer/shuttle/pod{ pixel_x = -32; - possible_destinations = "pod_asteroid2"; + possible_destinations = "pod_lavaland2"; shuttleId = "pod2" }, /obj/effect/turf_decal/stripes/line{ @@ -25977,7 +25977,7 @@ }, /obj/machinery/computer/shuttle/pod{ pixel_y = -32; - possible_destinations = "pod_asteroid3"; + possible_destinations = "pod_lavaland3"; shuttleId = "pod3" }, /obj/effect/turf_decal/stripes/line{ @@ -25996,8 +25996,8 @@ "aXK" = ( /obj/docking_port/stationary/random{ dir = 4; - id = "pod_asteroid4"; - name = "asteroid" + id = "pod_lavaland4"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -34793,7 +34793,6 @@ dir = 4 }, /turf/open/floor/plasteel{ - desc = ""; icon_state = "L14" }, /area/hallway/primary/central) @@ -70986,7 +70985,6 @@ "cDW" = ( /obj/machinery/atmospherics/pipe/manifold/supply/hidden, /turf/open/floor/plasteel{ - desc = ""; icon_state = "L13"; name = "floor" }, @@ -79512,8 +79510,13 @@ name = "Medbay Central" }) "cUf" = ( -/obj/machinery/smartfridge/chemistry, -/turf/closed/wall, +/obj/structure/grille, +/obj/machinery/door/poddoor/shutters/preopen{ + id = "chemisttop"; + name = "Chemisty Lobby Shutters" + }, +/obj/structure/window/reinforced/fulltile, +/turf/open/floor/plating, /area/medical/medbay{ name = "Medbay Central" }) @@ -79536,14 +79539,9 @@ name = "Medbay Central" }) "cUh" = ( -/obj/structure/grille, -/obj/structure/window/reinforced/fulltile, -/obj/machinery/door/poddoor/shutters/preopen{ - id = "chemisttop"; - name = "Chemisty Lobby Shutters" - }, /obj/structure/disposalpipe/segment, -/turf/open/floor/plating, +/obj/machinery/smartfridge/chemistry, +/turf/closed/wall, /area/medical/medbay{ name = "Medbay Central" }) @@ -82189,6 +82187,7 @@ /obj/item/weapon/grenade/chem_grenade, /obj/item/weapon/grenade/chem_grenade, /obj/item/weapon/grenade/chem_grenade, +/obj/item/weapon/screwdriver, /turf/open/floor/plasteel/whiteyellow/corner{ icon_state = "whiteyellowcorner"; dir = 8 @@ -96353,7 +96352,6 @@ }, /area/medical/morgue) "dAn" = ( -/turf/open/floor/plating, /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/manifold/supply/hidden{ icon_state = "manifold"; diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 320823a490..a26ea928ec 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -1910,8 +1910,8 @@ /area/shuttle/pod_3) "adG" = ( /obj/docking_port/stationary/random{ - id = "pod_asteroid2"; - name = "asteroid" + id = "pod_lavaland2"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -1927,7 +1927,7 @@ }, /obj/machinery/computer/shuttle/pod{ pixel_x = -32; - possible_destinations = "pod_asteroid2"; + possible_destinations = "pod_lavaland2"; shuttleId = "pod2" }, /turf/open/floor/mineral/titanium/blue, @@ -23696,7 +23696,7 @@ }, /obj/machinery/computer/shuttle/pod{ pixel_y = -32; - possible_destinations = "pod_asteroid3"; + possible_destinations = "pod_lavaland3"; shuttleId = "pod3" }, /turf/open/floor/mineral/titanium/blue, @@ -27963,7 +27963,6 @@ dir = 4 }, /turf/open/floor/plasteel{ - desc = ""; icon_state = "L13"; name = "floor" }, @@ -28813,7 +28812,6 @@ icon_state = "4-8" }, /turf/open/floor/plasteel{ - desc = ""; icon_state = "L14" }, /area/hallway/primary/central) @@ -34140,8 +34138,8 @@ "bii" = ( /obj/docking_port/stationary/random{ dir = 4; - id = "pod_asteroid3"; - name = "asteroid" + id = "pod_lavaland3"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -86084,8 +86082,8 @@ /area/toxins/xenobiology) "cSP" = ( /obj/docking_port/stationary/random{ - id = "pod_asteroid1"; - name = "asteroid" + id = "pod_lavaland1"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -86175,7 +86173,7 @@ }, /obj/machinery/computer/shuttle/pod{ pixel_x = -32; - possible_destinations = "pod_asteroid1"; + possible_destinations = "pod_lavaland1"; shuttleId = "pod1" }, /turf/open/floor/mineral/titanium/blue, @@ -86368,7 +86366,7 @@ }, /obj/machinery/computer/shuttle/pod{ pixel_y = -32; - possible_destinations = "pod_asteroid4"; + possible_destinations = "pod_lavaland4"; shuttleId = "pod4" }, /turf/open/floor/mineral/titanium/blue, @@ -87162,8 +87160,8 @@ "cUL" = ( /obj/docking_port/stationary/random{ dir = 4; - id = "pod_asteroid4"; - name = "asteroid" + id = "pod_lavaland4"; + name = "lavaland" }, /turf/open/space, /area/space) diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm index 0e3fea852f..dae6f8e837 100644 --- a/_maps/map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/map_files/OmegaStation/OmegaStation.dmm @@ -7303,7 +7303,6 @@ icon_state = "1-2" }, /turf/open/floor/plasteel{ - desc = ""; icon_state = "L14" }, /area/hallway/primary/central{ @@ -16523,6 +16522,9 @@ /obj/machinery/status_display{ pixel_x = -32 }, +/obj/machinery/light{ + dir = 8 + }, /turf/open/floor/mineral/plastitanium/brig, /area/shuttle/escape) "aAb" = ( @@ -16558,6 +16560,9 @@ "aAf" = ( /obj/structure/table/reinforced, /obj/item/weapon/storage/fancy/donut_box, +/obj/machinery/light{ + dir = 4 + }, /turf/open/floor/plasteel/vault{ dir = 8 }, @@ -24133,6 +24138,9 @@ }, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, +/obj/machinery/light{ + dir = 8 + }, /turf/open/floor/plasteel, /area/shuttle/escape) "aME" = ( @@ -24187,6 +24195,9 @@ /obj/machinery/status_display{ pixel_x = 32 }, +/obj/machinery/light{ + dir = 4 + }, /turf/open/floor/plasteel/whiteblue/side{ dir = 5 }, @@ -25964,7 +25975,6 @@ icon_state = "4-8" }, /turf/open/floor/plasteel{ - desc = ""; icon_state = "L13"; name = "floor" }, @@ -41920,6 +41930,38 @@ /area/ruin/unpowered{ name = "Asteroid" }) +"bvO" = ( +/obj/machinery/light{ + dir = 1 + }, +/turf/open/floor/plasteel/neutral/side{ + dir = 1 + }, +/area/shuttle/escape) +"bvP" = ( +/obj/structure/chair{ + dir = 8 + }, +/obj/effect/turf_decal/bot, +/obj/machinery/light/small{ + dir = 4 + }, +/turf/open/floor/plasteel, +/area/shuttle/escape) +"bvQ" = ( +/obj/structure/chair{ + dir = 4 + }, +/obj/effect/turf_decal/bot, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/open/floor/plasteel, +/area/shuttle/escape) +"bvR" = ( +/obj/machinery/light, +/turf/open/floor/plasteel/neutral/side, +/area/shuttle/escape) (1,1,1) = {" aaa @@ -94203,7 +94245,7 @@ aAb axY aDl aEi -aEi +bvP aEi aEi aEi @@ -94715,13 +94757,13 @@ axY aAc axY aCp -aDl +bvO aEk aEj aGd aEl aEk -aJf +bvR aKn aLz axY @@ -95231,7 +95273,7 @@ aAd aCq aDl aEm -aEm +bvQ aEm aEm aEm diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index e0e721840d..8310ff2f50 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -32850,10 +32850,6 @@ /turf/open/floor/plasteel/white, /area/toxins/xenobiology) "bnU" = ( -/obj/machinery/door/airlock/research{ - name = "Kill Room Access"; - req_access_txt = "55" - }, /obj/structure/disposalpipe/segment{ dir = 4 }, diff --git a/_maps/map_files/TgStation/tgstation.2.1.3.dmm b/_maps/map_files/TgStation/tgstation.2.1.3.dmm index f2bf5eb504..da42611e13 100644 --- a/_maps/map_files/TgStation/tgstation.2.1.3.dmm +++ b/_maps/map_files/TgStation/tgstation.2.1.3.dmm @@ -2501,7 +2501,7 @@ "afq" = ( /obj/machinery/computer/shuttle/pod{ pixel_y = -32; - possible_destinations = "pod_asteroid3"; + possible_destinations = "pod_lavaland3"; shuttleId = "pod3" }, /obj/structure/chair{ @@ -7787,8 +7787,8 @@ "aqG" = ( /obj/docking_port/stationary/random{ dir = 4; - id = "pod_asteroid3"; - name = "asteroid" + id = "pod_lavaland3"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -17330,7 +17330,6 @@ /area/hallway/primary/central) "aMf" = ( /turf/open/floor/plasteel{ - desc = ""; icon_state = "L13"; name = "floor" }, @@ -17836,7 +17835,6 @@ /area/hallway/primary/central) "aNB" = ( /turf/open/floor/plasteel{ - desc = ""; icon_state = "L14" }, /area/hallway/primary/central) @@ -53823,8 +53821,8 @@ "cpe" = ( /obj/docking_port/stationary/random{ dir = 8; - id = "pod_asteroid2"; - name = "asteroid" + id = "pod_lavaland2"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -54079,7 +54077,7 @@ /obj/machinery/computer/shuttle/pod{ pixel_x = 0; pixel_y = -32; - possible_destinations = "pod_asteroid2"; + possible_destinations = "pod_lavaland2"; shuttleId = "pod2" }, /obj/structure/chair{ @@ -57394,8 +57392,8 @@ "cwV" = ( /obj/docking_port/stationary/random{ dir = 8; - id = "pod_asteroid1"; - name = "asteroid" + id = "pod_lavaland1"; + name = "lavaland" }, /turf/open/space, /area/space) @@ -57508,7 +57506,7 @@ /obj/machinery/computer/shuttle/pod{ pixel_x = 0; pixel_y = -32; - possible_destinations = "pod_asteroid1"; + possible_destinations = "pod_lavaland1"; shuttleId = "pod1" }, /obj/structure/chair{ @@ -58424,7 +58422,7 @@ "czL" = ( /obj/machinery/computer/shuttle/pod{ pixel_y = -32; - possible_destinations = "pod_asteroid4"; + possible_destinations = "pod_lavaland4"; shuttleId = "pod4" }, /obj/structure/chair{ @@ -58455,8 +58453,8 @@ "czN" = ( /obj/docking_port/stationary/random{ dir = 4; - id = "pod_asteroid4"; - name = "asteroid" + id = "pod_lavaland4"; + name = "lavaland" }, /turf/open/space, /area/space) diff --git a/code/__DEFINES/clockcult.dm b/code/__DEFINES/clockcult.dm index 9c86e031ab..acc0cdc9ab 100644 --- a/code/__DEFINES/clockcult.dm +++ b/code/__DEFINES/clockcult.dm @@ -37,15 +37,15 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us #define JUDGEMENT_CV_REQ 300 //general component/cooldown things -#define SLAB_PRODUCTION_TIME 900 //how long(deciseconds) slabs require to produce a single component; defaults to 1 minute 30 seconds +#define SLAB_PRODUCTION_TIME 450 //how long(deciseconds) slabs require to produce a single component; defaults to 45 seconds -#define SLAB_SERVANT_SLOWDOWN 300 //how much each servant above 5 slows down slab-based generation; defaults to 30 seconds per sevant +#define SLAB_SERVANT_SLOWDOWN 150 //how much each servant above 5 slows down slab-based generation; defaults to 15 seconds per sevant -#define SLAB_SLOWDOWN_MAXIMUM 2700 //maximum slowdown from additional servants; defaults to 4 minutes 30 seconds +#define SLAB_SLOWDOWN_MAXIMUM 1350 //maximum slowdown from additional servants; defaults to 2 minutes 15 seconds -#define CACHE_PRODUCTION_TIME 600 //how long(deciseconds) caches require to produce a component; defaults to 1 minute +#define CACHE_PRODUCTION_TIME 300 //how long(deciseconds) caches require to produce a component; defaults to 30 seconds -#define ACTIVE_CACHE_SLOWDOWN 100 //how many additional deciseconds caches take to produce a component for each linked cache; defaults to 10 seconds +#define ACTIVE_CACHE_SLOWDOWN 50 //how many additional deciseconds caches take to produce a component for each linked cache; defaults to 5 seconds #define LOWER_PROB_PER_COMPONENT 10 //how much each component in the cache reduces the weight of getting another of that component type @@ -87,9 +87,9 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us #define GATEWAY_RATVAR_ARRIVAL 300 //when progress is at or above this, game over ratvar's here everybody go home -#define ARK_SUMMON_COST 3 //how many of each component an Ark costs to summon +#define ARK_SUMMON_COST 5 //how many of each component an Ark costs to summon -#define ARK_CONSUME_COST 7 //how many of each component an Ark needs to consume to activate +#define ARK_CONSUME_COST 15 //how many of each component an Ark needs to consume to activate //Objective text define #define CLOCKCULT_OBJECTIVE "Construct the Ark of the Clockwork Justicar and free Ratvar." diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 1da1b50aa3..d0fcb3bcbe 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1342,6 +1342,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) //This prevents RCEs from badmins //kevinz000 if you touch this I will hunt you down GLOBAL_VAR_INIT(valid_HTTPSGet, FALSE) +GLOBAL_PROTECT(valid_HTTPSGet) /proc/HTTPSGet(url) if(findtext(url, "\"")) GLOB.valid_HTTPSGet = FALSE diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index be771e0676..e82976d4a3 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -29,6 +29,7 @@ GLOBAL_LIST_EMPTY(zombie_infection_list) // A list of all zombie_infection org GLOBAL_LIST_EMPTY(meteor_list) // List of all meteors. GLOBAL_LIST_EMPTY(active_jammers) // List of active radio jammers GLOBAL_LIST_EMPTY(ladders) +GLOBAL_LIST_EMPTY(trophy_cases) GLOBAL_LIST_EMPTY(wire_color_directory) GLOBAL_LIST_EMPTY(wire_name_directory) \ No newline at end of file diff --git a/code/controllers/subsystem/persistence.dm b/code/controllers/subsystem/persistence.dm index e1cf992e8b..6b3e47054c 100644 --- a/code/controllers/subsystem/persistence.dm +++ b/code/controllers/subsystem/persistence.dm @@ -11,10 +11,14 @@ SUBSYSTEM_DEF(persistence) var/list/saved_messages = list() var/savefile/chisel_messages_sav + var/savefile/trophy_sav + var/list/saved_trophies = list() + /datum/controller/subsystem/persistence/Initialize() LoadSatchels() LoadPoly() LoadChiselMessages() + LoadTrophies() ..() /datum/controller/subsystem/persistence/proc/LoadSatchels() @@ -105,10 +109,49 @@ SUBSYSTEM_DEF(persistence) M.persists = FALSE qdel(M) +/datum/controller/subsystem/persistence/proc/LoadTrophies() + trophy_sav = new /savefile("data/npc_saves/TrophyItems.sav") + var/saved_json + trophy_sav >> saved_json + + var/decoded_json = json_decode(saved_json) + + if(!islist(decoded_json)) + return + + saved_trophies = decoded_json + + SetUpTrophies(saved_trophies.Copy()) + +/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items) + for(var/A in GLOB.trophy_cases) + var/obj/structure/displaycase/trophy/T = A + T.added_roundstart = TRUE + + var/trophy_data = pick_n_take(trophy_items) + + if(!islist(trophy_data)) + continue + + var/list/chosen_trophy = trophy_data + + if(!chosen_trophy || isemptylist(chosen_trophy)) //Malformed + continue + + var/path = text2path(chosen_trophy["path"]) //If the item no longer exist, this returns null + if(!path) + continue + + T.showpiece = new /obj/item/showpiece_dummy(T, path) + T.trophy_message = chosen_trophy["message"] + T.placer_key = chosen_trophy["placer_key"] + T.update_icon() + /datum/controller/subsystem/persistence/proc/CollectData() CollectChiselMessages() CollectSecretSatchels() + CollectTrophies() /datum/controller/subsystem/persistence/proc/CollectSecretSatchels() for(var/A in new_secret_satchels) @@ -135,4 +178,16 @@ SUBSYSTEM_DEF(persistence) chisel_messages_sav[SSmapping.config.map_name] << json_encode(saved_messages) /datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M) - saved_messages += list(M.pack()) // dm eats one list. + saved_messages += list(M.pack()) // dm eats one list + + +/datum/controller/subsystem/persistence/proc/CollectTrophies() + trophy_sav << json_encode(saved_trophies) + +/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T) + if(!T.added_roundstart && T.showpiece) + var/list/data = list() + data["path"] = T.showpiece.type + data["message"] = T.trophy_message + data["placer_key"] = T.placer_key + saved_trophies += list(data) \ No newline at end of file diff --git a/code/controllers/subsystem/processing/flightpacks.dm b/code/controllers/subsystem/processing/flightpacks.dm index 1d85811878..0639f64810 100644 --- a/code/controllers/subsystem/processing/flightpacks.dm +++ b/code/controllers/subsystem/processing/flightpacks.dm @@ -5,7 +5,7 @@ PROCESSING_SUBSYSTEM_DEF(flightpacks) stat_tag = "FM" flags = SS_NO_INIT|SS_TICKER|SS_KEEP_TIMING - var/flightsuit_processing = FLIGHTSUIT_PROCESSING_FULL + var/flightsuit_processing = FLIGHTSUIT_PROCESSING_NONE /datum/controller/subsystem/processing/flightpacks/Initialize() sync_flightsuit_processing() diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index f3ac66e001..abf05aad72 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -625,8 +625,8 @@ SUBSYSTEM_DEF(ticker) if(selected_tip) m = selected_tip else - var/list/randomtips = world.file2list("config/tips.txt") - var/list/memetips = world.file2list("config/sillytips.txt") + var/list/randomtips = world.file2list("strings/tips.txt") + var/list/memetips = world.file2list("strings/sillytips.txt") if(randomtips.len && prob(95)) m = pick(randomtips) else if(memetips.len) diff --git a/code/datums/antagonists/antag_datum.dm b/code/datums/antagonists/antag_datum.dm index deee1111c0..396c185961 100644 --- a/code/datums/antagonists/antag_datum.dm +++ b/code/datums/antagonists/antag_datum.dm @@ -8,13 +8,26 @@ var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum var/list/typecache_datum_blacklist = list() //List of datums this type can't coexist with - /datum/antagonist/New(datum/mind/new_owner) - . = ..() typecache_datum_blacklist = typecacheof(typecache_datum_blacklist) if(new_owner) owner = new_owner +/datum/antagonist/Destroy() + if(owner) + LAZYREMOVE(owner.antag_datums, src) + owner = null + return ..() + +/datum/antagonist/proc/can_be_owned(datum/mind/new_owner) + . = TRUE + if(owner.has_antag_datum(type)) + return FALSE + for(var/i in owner.antag_datums) + var/datum/antagonist/A = i + if(is_type_in_typecache(src, A.typecache_datum_blacklist)) + return FALSE + /datum/antagonist/proc/on_body_transfer(mob/living/old_body, mob/living/new_body) remove_innate_effects(old_body) apply_innate_effects(new_body) @@ -37,7 +50,7 @@ /datum/antagonist/proc/on_removal() remove_innate_effects() if(owner) - owner.antag_datums -= src + LAZYREMOVE(owner.antag_datums, src) if(!silent && owner.current) farewell() qdel(src) @@ -46,4 +59,4 @@ return /datum/antagonist/proc/farewell() - return \ No newline at end of file + return diff --git a/code/datums/antagonists/datum_clockcult.dm b/code/datums/antagonists/datum_clockcult.dm index ba18e76f02..b8dfa00f23 100644 --- a/code/datums/antagonists/datum_clockcult.dm +++ b/code/datums/antagonists/datum_clockcult.dm @@ -9,23 +9,49 @@ qdel(hierophant_network) return ..() +/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner) + . = ..() + if(.) + if(iscyborg(new_owner.current)) + var/mob/living/silicon/robot/R = new_owner.current + if(R.deployed) + var/mob/living/silicon/ai/AI = R.mainframe + R.undeploy() + to_chat(AI, "Anomaly Detected. Returned to core!") //The AI needs to be in its core to properly be converted + . = is_eligible_servant(new_owner.current) + if(!silent && new_owner.current) + if(issilicon(new_owner.current)) + to_chat(new_owner.current, "You are unable to compute this truth. Your vision glows a brilliant yellow, and all at once it comes to you. Ratvar, the \ + Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm.") + else + to_chat(new_owner.current, "[iscarbon(new_owner.current) ? "Your mind is racing! Your body feels incredibly light! ":""]Your world glows a brilliant \ + yellow! All at once it comes to you. Ratvar, the Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm.") + if(!.) + new_owner.current.visible_message("[new_owner.current] seems to resist an unseen force!") + to_chat(new_owner.current, "And yet, you somehow push it all away.") + +/datum/antagonist/clockcult/greet() + if(!owner.current || silent) + return + owner.current.visible_message("[owner.current]'s eyes glow a blazing yellow!") + to_chat(owner.current, "Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork \ + Justiciar above all else. Perform his every whim without hesitation.") + /datum/antagonist/clockcult/on_gain() - if(!owner) - return var/mob/living/current = owner.current - if(!istype(current)) - return + SSticker.mode.servants_of_ratvar += owner + SSticker.mode.update_servant_icons_added(owner) if(jobban_isbanned(current, ROLE_SERVANT_OF_RATVAR)) - addtimer(CALLBACK(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, owner, ROLE_SERVANT_OF_RATVAR, ROLE_SERVANT_OF_RATVAR), 0) + addtimer(CALLBACK(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, current, ROLE_SERVANT_OF_RATVAR, ROLE_SERVANT_OF_RATVAR), 0) + owner.special_role = "Servant of Ratvar" owner.current.log_message("Has been converted to the cult of Ratvar!", INDIVIDUAL_ATTACK_LOG) if(issilicon(current)) - var/mob/living/silicon/S = owner - if(iscyborg(S) && !silent) - to_chat(S, "You have been desynced from your master AI.") - to_chat(S, "In addition, your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.") - if(isAI(S)) - to_chat(S, "You are able to use your cameras to listen in on conversations.") - to_chat(S, "You can communicate with other servants by using the Hierophant Network action button in the upper left.") + if(iscyborg(current) && !silent) + to_chat(current, "You have been desynced from your master AI.") + to_chat(current, "In addition, your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.") + if(isAI(current)) + to_chat(current, "You are able to use your cameras to listen in on conversations.") + to_chat(current, "You can communicate with other servants by using the Hierophant Network action button in the upper left.") else if(isbrain(current) || isclockmob(current)) to_chat(current, "You can communicate with other servants by using the Hierophant Network action button in the upper left.") ..() @@ -39,7 +65,6 @@ if(istype(mob_override)) current = mob_override GLOB.all_clockwork_mobs += current - SSticker.mode.update_servant_icons_added(owner) current.faction |= "ratvar" current.grant_language(/datum/language/ratvar) current.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons @@ -47,11 +72,17 @@ var/mob/living/silicon/S = current if(iscyborg(S)) var/mob/living/silicon/robot/R = S - R.UnlinkSelf() + if(!R.shell) + R.UnlinkSelf() R.module.rebuild_modules() else if(isAI(S)) var/mob/living/silicon/ai/A = S + A.can_be_carded = FALSE A.requires_power = POWER_REQ_CLOCKCULT + var/list/AI_frame = list(mutable_appearance('icons/mob/clockwork_mobs.dmi', "aiframe")) //make the AI's cool frame + for(var/d in GLOB.cardinal) + AI_frame += image('icons/mob/clockwork_mobs.dmi', A, "eye[rand(1, 10)]", dir = d) //the eyes are randomly fast or slow + A.add_overlay(AI_frame) if(!A.lacks_power()) A.ai_restore_power() if(A.eyeobj) @@ -84,8 +115,6 @@ current.throw_alert("clockinfo", /obj/screen/alert/clockwork/infodump) if(!GLOB.clockwork_gateway_activated) current.throw_alert("scripturereq", /obj/screen/alert/clockwork/scripture_reqs) - update_slab_info() - /datum/antagonist/clockcult/remove_innate_effects(mob/living/mob_override) var/mob/living/current = owner.current @@ -102,7 +131,9 @@ var/mob/living/silicon/S = current if(isAI(S)) var/mob/living/silicon/ai/A = S + A.can_be_carded = initial(A.can_be_carded) A.requires_power = initial(A.requires_power) + A.cut_overlays() S.make_laws() S.update_icons() S.show_laws() @@ -113,13 +144,16 @@ R.module.rebuild_modules() if(temp_owner) temp_owner.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them, we need to update buttons - update_slab_info() /datum/antagonist/clockcult/on_removal() - . = ..() + SSticker.mode.servants_of_ratvar -= owner + SSticker.mode.update_servant_icons_removed(owner) if(!silent) owner.current.visible_message("[owner] seems to have remembered their true allegiance!", \ "A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.") owner.current.log_message("Has renounced the cult of Ratvar!", INDIVIDUAL_ATTACK_LOG) + owner.wipe_memory() + owner.special_role = null if(iscyborg(owner.current)) - to_chat(owner.current, "Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.") \ No newline at end of file + to_chat(owner.current, "Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.") + . = ..() diff --git a/code/datums/antagonists/datum_cult.dm b/code/datums/antagonists/datum_cult.dm index 69c9849782..30c0aa8450 100644 --- a/code/datums/antagonists/datum_cult.dm +++ b/code/datums/antagonists/datum_cult.dm @@ -5,29 +5,46 @@ qdel(communion) return ..() +/datum/antagonist/cult/can_be_owned(datum/mind/new_owner) + . = ..() + if(.) + . = is_convertable_to_cult(new_owner.current) + /datum/antagonist/cult/on_gain() . = ..() - if(!owner) - return + SSticker.mode.cult += owner + SSticker.mode.update_cult_icons_added(owner) + if(istype(SSticker.mode, /datum/game_mode/cult)) + var/datum/game_mode/cult/C = SSticker.mode + C.memorize_cult_objectives(owner) if(jobban_isbanned(owner.current, ROLE_CULTIST)) - addtimer(CALLBACK(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, owner, ROLE_CULTIST, ROLE_CULTIST), 0) + addtimer(CALLBACK(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, owner.current, ROLE_CULTIST, ROLE_CULTIST), 0) owner.current.log_message("Has been converted to the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG) -/datum/antagonist/cult/apply_innate_effects() +/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override) . = ..() - owner.current.faction |= "cult" - owner.current.verbs += /mob/living/proc/cult_help - communion.Grant(owner) + var/mob/living/current = owner.current + if(mob_override) + current = mob_override + current.faction |= "cult" + current.verbs += /mob/living/proc/cult_help + communion.Grant(current) -/datum/antagonist/cult/remove_innate_effects() +/datum/antagonist/cult/remove_innate_effects(mob/living/mob_override) . = ..() - owner.current.faction -= "cult" - owner.current.verbs -= /mob/living/proc/cult_help - + var/mob/living/current = owner.current + if(mob_override) + current = mob_override + current.faction -= "cult" + current.verbs -= /mob/living/proc/cult_help + communion.Remove(current) /datum/antagonist/cult/on_removal() - . = ..() + owner.wipe_memory() + SSticker.mode.cult -= owner + SSticker.mode.update_cult_icons_removed(owner) to_chat(owner, "An unfamiliar white light flashes through your mind, cleansing the taint of the Dark One and all your memories as its servant.") owner.current.log_message("Has renounced the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG) if(!silent) - owner.current.visible_message("[owner] looks like [owner.current.p_they()] just reverted to their old faith!") \ No newline at end of file + owner.current.visible_message("[owner] looks like [owner.current.p_they()] just reverted to their old faith!") + . = ..() diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm new file mode 100644 index 0000000000..6d6b1104dc --- /dev/null +++ b/code/datums/holocall.dm @@ -0,0 +1,159 @@ +#define HOLOPAD_MAX_DIAL_TIME 200 + +/mob/camera/aiEye/remote/holo/setLoc() + . = ..() + var/obj/machinery/holopad/H = origin + H.move_hologram(eye_user, loc) + +//this datum manages it's own references + +/datum/holocall + var/mob/living/user //the one that called + var/obj/machinery/holopad/calling_holopad //the one that sent the call + var/obj/machinery/holopad/connected_holopad //the one that answered the call (may be null) + var/list/dialed_holopads //all things called, will be cleared out to just connected_holopad once answered + + var/mob/camera/aiEye/remote/holo/eye //user's eye, once connected + var/obj/effect/overlay/holo_pad_hologram/hologram //user's hologram, once connected + + var/call_start_time + +//creates a holocall made by `caller` from `calling_pad` to `callees` +/datum/holocall/New(mob/living/caller, obj/machinery/holopad/calling_pad, list/callees) + call_start_time = world.time + user = caller + calling_pad.outgoing_call = src + calling_holopad = calling_pad + dialed_holopads = list() + + for(var/I in callees) + var/obj/machinery/holopad/H = I + if(!QDELETED(H) && H.is_operational()) + dialed_holopads += H + LAZYADD(H.holo_calls, src) + + if(!dialed_holopads.len) + calling_pad.say("Connection failure.") + qdel(src) + + testing("Holocall started") + +//cleans up ALL references :) +/datum/holocall/Destroy() + QDEL_NULL(eye) + + user.reset_perspective() + + user = null + hologram.HC = null + hologram = null + calling_holopad.outgoing_call = null + + for(var/I in dialed_holopads) + var/obj/machinery/holopad/H = I + LAZYREMOVE(H.holo_calls, src) + dialed_holopads.Cut() + + if(calling_holopad) + calling_holopad.SetLightsAndPower() + calling_holopad = null + if(connected_holopad) + connected_holopad.SetLightsAndPower() + connected_holopad = null + + testing("Holocall destroyed") + + return ..() + +//Gracefully disconnects a holopad `H` from a call. Pads not in the call are ignored. Notifies participants of the disconnection +/datum/holocall/proc/Disconnect(obj/machinery/holopad/H) + testing("Holocall disconnect") + if(H == connected_holopad) + calling_holopad.say("[usr] disconnected.") + else if(H == calling_holopad && connected_holopad) + connected_holopad.say("[usr] disconnected.") + + ConnectionFailure(H, TRUE) + +//Forcefully disconnects a holopad `H` from a call. Pads not in the call are ignored. +/datum/holocall/proc/ConnectionFailure(obj/machinery/holopad/H, graceful = FALSE) + testing("Holocall connection failure: graceful [graceful]") + if(H == connected_holopad || H == calling_holopad) + if(!graceful) + calling_holopad.say("Connection failure.") + qdel(src) + return + + LAZYREMOVE(H.holo_calls, src) + dialed_holopads -= H + if(!dialed_holopads.len) + if(graceful) + calling_holopad.say("Call rejected.") + testing("No recipients, terminating") + qdel(src) + +//Answers a call made to a holopad `H` which cannot be the calling holopad. Pads not in the call are ignored +/datum/holocall/proc/Answer(obj/machinery/holopad/H) + testing("Holocall answer") + if(H == calling_holopad) + CRASH("How cute, a holopad tried to answer itself.") + + if(!(H in dialed_holopads)) + return + + if(connected_holopad) + CRASH("Multi-connection holocall") + + connected_holopad = H + for(var/I in dialed_holopads) + if(I == H) + continue + var/obj/machinery/holopad/Holo = I + LAZYREMOVE(Holo.holo_calls, src) + dialed_holopads -= Holo + + for(var/I in H.holo_calls) + var/datum/holocall/HC = I + if(HC != src) + HC.Disconnect(H) + + if(!Check()) + return + + hologram = H.activate_holo(user) + hologram.HC = src + + //eyeobj code is horrid, this is the best copypasta I could make + eye = new + eye.origin = H + eye.eye_initialized = TRUE + eye.eye_user = user + eye.name = "Camera Eye ([user.name])" + user.remote_control = eye + user.reset_perspective(eye) + eye.setLoc(H.loc) + +//Checks the validity of a holocall and qdels itself if it's not. Returns TRUE if valid, FALSE otherwise +/datum/holocall/proc/Check() + for(var/I in dialed_holopads) + var/obj/machinery/holopad/H = I + if(!H.is_operational()) + ConnectionFailure(H) + + if(QDELETED(src)) + return FALSE + + . = !QDELETED(user) && !user.incapacitated() && !QDELETED(calling_holopad) && calling_holopad.is_operational() && user.loc == calling_holopad.loc + + if(.) + if(connected_holopad) + . = !QDELETED(connected_holopad) && connected_holopad.is_operational() + else + . = world.time < (call_start_time + HOLOPAD_MAX_DIAL_TIME) + if(!.) + calling_holopad.say("No answer recieved.") + calling_holopad.temp = "" + + if(!.) + testing("Holocall Check fail") + qdel(src) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 0acd33ad69..e99d5bb59a 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -44,9 +44,7 @@ var/datum/job/assigned_job var/list/datum/objective/objectives = list() - var/list/datum/objective/special_verbs = list() - var/list/cult_words = list() var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button. var/datum/faction/faction //associated faction @@ -54,7 +52,7 @@ var/linglink var/miming = 0 // Mime's vow of silence - var/list/antag_datums = list() + var/list/antag_datums var/antag_hud_icon_state = null //this mind's ANTAG_HUD should have this icon_state var/datum/atom_hud/antag/antag_hud = null //this mind's antag HUD var/datum/gang/gang_datum //Which gang this mind belongs to, if any @@ -71,6 +69,10 @@ /datum/mind/Destroy() SSticker.minds -= src + if(islist(antag_datums)) + for(var/i in antag_datums) + qdel(i) + antag_datums = null return ..() /datum/mind/proc/transfer_to(mob/new_character, var/force_key_move = 0) @@ -110,15 +112,16 @@ memory = null // Datum antag mind procs -/datum/mind/proc/add_antag_datum(datum_type, on_gain = TRUE) +/datum/mind/proc/add_antag_datum(datum_type) if(!datum_type) return - if(!can_hold_antag_datum(datum_type)) - return var/datum/antagonist/A = new datum_type(src) - antag_datums += A - if(on_gain) - A.on_gain() + if(!A.can_be_owned(src)) + qdel(A) + return + LAZYADD(antag_datums, A) + A.on_gain() + return A /datum/mind/proc/remove_antag_datum(datum_type) if(!datum_type) @@ -126,6 +129,7 @@ var/datum/antagonist/A = has_antag_datum(datum_type) if(A) A.on_removal() + return TRUE /datum/mind/proc/remove_all_antag_datums() //For the Lazy amongst us. for(var/a in antag_datums) @@ -143,18 +147,6 @@ else if(A.type == datum_type) return A -/datum/mind/proc/can_hold_antag_datum(datum_type) - if(!datum_type) - return - . = TRUE - if(has_antag_datum(datum_type)) - return FALSE - for(var/i in antag_datums) - var/datum/antagonist/A = i - if(is_type_in_typecache(A, A.typecache_datum_blacklist)) - return FALSE - - /* Removes antag type's references from a mind. objectives, uplinks, powers etc are all handled. diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm index 3a54db4e0a..011363f001 100644 --- a/code/datums/ruins/lavaland.dm +++ b/code/datums/ruins/lavaland.dm @@ -42,6 +42,7 @@ However, all the inhabitants seem to do is grow drugs and guns." suffix = "lavaland_surface_seed_vault.dmm" cost = 10 + allow_duplicates = FALSE /datum/map_template/ruin/lavaland/ash_walker name = "Ash Walker Nest" diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm index 51b4f8fc5f..ec725885a9 100644 --- a/code/datums/status_effects/status_effect.dm +++ b/code/datums/status_effects/status_effect.dm @@ -10,6 +10,7 @@ var/status_type = STATUS_EFFECT_UNIQUE //How many of the effect can be on one mob, and what happens when you try to add another var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted var/alert_type = /obj/screen/alert/status_effect //the alert thrown by the status effect, contains name and description + var/obj/screen/alert/status_effect/linked_alert = null //the alert itself, if it exists /datum/status_effect/New(mob/living/new_owner) if(new_owner) @@ -40,6 +41,7 @@ if(alert_type) var/obj/screen/alert/status_effect/A = owner.throw_alert(id, alert_type) A.attached_effect = src //so the alert can reference us, if it needs to + linked_alert = A //so we can reference the alert, if we need to START_PROCESSING(SSfastprocess, src) /datum/status_effect/process() diff --git a/code/game/gamemodes/changeling/changeling_power.dm b/code/game/gamemodes/changeling/changeling_power.dm index 67eb216d58..489228a30c 100644 --- a/code/game/gamemodes/changeling/changeling_power.dm +++ b/code/game/gamemodes/changeling/changeling_power.dm @@ -13,8 +13,6 @@ var/req_dna = 0 //amount of dna needed to use this ability. Changelings always have atleast 1 var/req_human = 0 //if you need to be human to use this ability var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD - var/genetic_damage = 0 // genetic damage caused by using the sting. Nothing to do with cloneloss. - var/max_genetic_damage = 100 // hard counter for spamming abilities. Not used/balanced much yet. var/always_keep = 0 // important for abilities like revive that screw you if you lose them. var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag @@ -39,7 +37,7 @@ if(sting_action(user, target)) SSblackbox.add_details("changeling_powers",name) sting_feedback(user, target) - take_chemical_cost(c) + c.chem_charges -= chemical_cost /obj/effect/proc_holder/changeling/proc/sting_action(mob/user, mob/target) return 0 @@ -47,10 +45,6 @@ /obj/effect/proc_holder/changeling/proc/sting_feedback(mob/user, mob/target) return 0 -/obj/effect/proc_holder/changeling/proc/take_chemical_cost(datum/changeling/changeling) - changeling.chem_charges -= chemical_cost - changeling.geneticdamage += genetic_damage - //Fairly important to remember to return 1 on success >.< /obj/effect/proc_holder/changeling/proc/can_sting(mob/user, mob/target) if(!ishuman(user) && !ismonkey(user)) //typecast everything from mob to carbon from this point onwards @@ -71,9 +65,6 @@ if((user.status_flags & FAKEDEATH) && (!ignores_fakedeath)) to_chat(user, "We are incapacitated.") return 0 - if(c.geneticdamage > max_genetic_damage) - to_chat(user, "Our genomes are still reassembling. We need time to recover first.") - return 0 return 1 //used in /mob/Stat() diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm index 6a52ab9312..b6b3372ae3 100644 --- a/code/game/gamemodes/changeling/powers/absorb.dm +++ b/code/game/gamemodes/changeling/powers/absorb.dm @@ -4,7 +4,6 @@ chemical_cost = 0 dna_cost = 0 req_human = 1 - max_genetic_damage = 100 /obj/effect/proc_holder/changeling/absorbDNA/can_sting(mob/living/carbon/user) if(!..()) diff --git a/code/game/gamemodes/changeling/powers/biodegrade.dm b/code/game/gamemodes/changeling/powers/biodegrade.dm index 453dec9375..6e2d6b0ddd 100644 --- a/code/game/gamemodes/changeling/powers/biodegrade.dm +++ b/code/game/gamemodes/changeling/powers/biodegrade.dm @@ -5,9 +5,6 @@ chemical_cost = 30 //High cost to prevent spam dna_cost = 2 req_human = 1 - genetic_damage = 10 - max_genetic_damage = 0 - /obj/effect/proc_holder/changeling/biodegrade/sting_action(mob/living/carbon/human/user) var/used = FALSE // only one form of shackles removed per use diff --git a/code/game/gamemodes/changeling/powers/chameleon_skin.dm b/code/game/gamemodes/changeling/powers/chameleon_skin.dm index 1f18f628a8..3be5103105 100644 --- a/code/game/gamemodes/changeling/powers/chameleon_skin.dm +++ b/code/game/gamemodes/changeling/powers/chameleon_skin.dm @@ -5,9 +5,6 @@ dna_cost = 2 chemical_cost = 25 req_human = 1 - genetic_damage = 10 - max_genetic_damage = 50 - /obj/effect/proc_holder/changeling/chameleon_skin/sting_action(mob/user) var/mob/living/carbon/human/H = user //SHOULD always be human, because req_human = 1 diff --git a/code/game/gamemodes/changeling/powers/fakedeath.dm b/code/game/gamemodes/changeling/powers/fakedeath.dm index 798f8030e0..e35f04d9e7 100644 --- a/code/game/gamemodes/changeling/powers/fakedeath.dm +++ b/code/game/gamemodes/changeling/powers/fakedeath.dm @@ -5,8 +5,6 @@ dna_cost = 0 req_dna = 1 req_stat = DEAD - max_genetic_damage = 100 - //Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay. /obj/effect/proc_holder/changeling/fakedeath/sting_action(mob/living/user) diff --git a/code/game/gamemodes/changeling/powers/humanform.dm b/code/game/gamemodes/changeling/powers/humanform.dm index 743dbc91e9..d92e622c2d 100644 --- a/code/game/gamemodes/changeling/powers/humanform.dm +++ b/code/game/gamemodes/changeling/powers/humanform.dm @@ -2,10 +2,7 @@ name = "Human Form" desc = "We change into a human." chemical_cost = 5 - genetic_damage = 3 req_dna = 1 - max_genetic_damage = 3 - //Transform into a human. /obj/effect/proc_holder/changeling/humanform/sting_action(mob/living/carbon/user) diff --git a/code/game/gamemodes/changeling/powers/lesserform.dm b/code/game/gamemodes/changeling/powers/lesserform.dm index 538803de00..06824f9bed 100644 --- a/code/game/gamemodes/changeling/powers/lesserform.dm +++ b/code/game/gamemodes/changeling/powers/lesserform.dm @@ -3,7 +3,6 @@ desc = "We debase ourselves and become lesser. We become a monkey." chemical_cost = 5 dna_cost = 1 - genetic_damage = 3 req_human = 1 //Transform into a monkey. diff --git a/code/game/gamemodes/changeling/powers/linglink.dm b/code/game/gamemodes/changeling/powers/linglink.dm index fc4b91b650..232774c937 100644 --- a/code/game/gamemodes/changeling/powers/linglink.dm +++ b/code/game/gamemodes/changeling/powers/linglink.dm @@ -4,7 +4,6 @@ chemical_cost = 0 dna_cost = 0 req_human = 1 - max_genetic_damage = 100 /obj/effect/proc_holder/changeling/linglink/can_sting(mob/living/carbon/user) if(!..()) diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm index 54e8ea1e38..aef9b6f1d2 100644 --- a/code/game/gamemodes/changeling/powers/mutations.dm +++ b/code/game/gamemodes/changeling/powers/mutations.dm @@ -16,7 +16,6 @@ helptext = "Yell at Miauw and/or Perakp" chemical_cost = 1000 dna_cost = -1 - genetic_damage = 1000 var/silent = FALSE var/weapon_type @@ -67,7 +66,6 @@ helptext = "Yell at Miauw and/or Perakp" chemical_cost = 1000 dna_cost = -1 - genetic_damage = 1000 var/helmet_type = /obj/item var/suit_type = /obj/item @@ -89,7 +87,7 @@ return 1 var/mob/living/carbon/human/H = user if(istype(H.wear_suit, suit_type) || istype(H.head, helmet_type)) - H.visible_message("[H] casts off their [suit_name_simple]!", "We cast off our [suit_name_simple][genetic_damage > 0 ? ", temporarily weakening our genomes." : "."]", "You hear the organic matter ripping and tearing!") + H.visible_message("[H] casts off their [suit_name_simple]!", "We cast off our [suit_name_simple].", "You hear the organic matter ripping and tearing!") H.temporarilyRemoveItemFromInventory(H.head, TRUE) //The qdel on dropped() takes care of it H.temporarilyRemoveItemFromInventory(H.wear_suit, TRUE) H.update_inv_wear_suit() @@ -100,7 +98,6 @@ H.add_splatter_floor() playsound(H.loc, 'sound/effects/splat.ogg', 50, 1) //So real sounds - changeling.geneticdamage += genetic_damage //Casting off a space suit leaves you weak for a few seconds. changeling.chem_recharge_slowdown -= recharge_slowdown return 1 @@ -139,9 +136,7 @@ helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form." chemical_cost = 20 dna_cost = 2 - genetic_damage = 10 req_human = 1 - max_genetic_damage = 20 weapon_type = /obj/item/weapon/melee/arm_blade weapon_name_simple = "blade" @@ -217,9 +212,7 @@ and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form." chemical_cost = 10 dna_cost = 2 - genetic_damage = 5 req_human = 1 - max_genetic_damage = 10 weapon_type = /obj/item/weapon/gun/magic/tentacle weapon_name_simple = "tentacle" silent = TRUE @@ -381,9 +374,7 @@ helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form." chemical_cost = 20 dna_cost = 1 - genetic_damage = 12 req_human = 1 - max_genetic_damage = 20 weapon_type = /obj/item/weapon/shield/changeling weapon_name_simple = "shield" @@ -430,12 +421,10 @@ /obj/effect/proc_holder/changeling/suit/organic_space_suit name = "Organic Space Suit" desc = "We grow an organic suit to protect ourselves from space exposure." - helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Retreating the suit damages our genomes. Cannot be used in lesser form." + helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Cannot be used in lesser form." chemical_cost = 20 dna_cost = 2 - genetic_damage = 8 req_human = 1 - max_genetic_damage = 20 suit_type = /obj/item/clothing/suit/space/changeling helmet_type = /obj/item/clothing/head/helmet/space/changeling @@ -477,12 +466,10 @@ /obj/effect/proc_holder/changeling/suit/armor name = "Chitinous Armor" desc = "We turn our skin into tough chitin to protect us from damage." - helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Retreating the armor damages our genomes. Cannot be used in lesser form." + helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form." chemical_cost = 20 dna_cost = 1 - genetic_damage = 11 req_human = 1 - max_genetic_damage = 20 recharge_slowdown = 0.25 suit_type = /obj/item/clothing/suit/armor/changeling diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm index c44a32c24d..ad6bf81e7c 100644 --- a/code/game/gamemodes/changeling/powers/tiny_prick.dm +++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm @@ -40,10 +40,9 @@ return if(!AStar(user, target.loc, /turf/proc/Distance, user.mind.changeling.sting_range, simulated_only = 0)) return - if(target.mind && target.mind.changeling) - sting_feedback(user,target) - take_chemical_cost(user.mind.changeling) - return + if(target.mind && target.mind.changeling) + sting_feedback(user, target) + user.mind.changeling.chem_charges -= chemical_cost return 1 /obj/effect/proc_holder/changeling/sting/sting_feedback(mob/user, mob/target) @@ -62,7 +61,6 @@ sting_icon = "sting_transform" chemical_cost = 40 dna_cost = 3 - genetic_damage = 100 var/datum/changelingprofile/selected_dna = null /obj/effect/proc_holder/changeling/sting/transformation/Click() @@ -117,8 +115,6 @@ sting_icon = "sting_armblade" chemical_cost = 20 dna_cost = 1 - genetic_damage = 20 - max_genetic_damage = 10 /obj/item/weapon/melee/arm_blade/false desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless." diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm index f9aca83d04..9d0b095cc2 100644 --- a/code/game/gamemodes/changeling/powers/transform.dm +++ b/code/game/gamemodes/changeling/powers/transform.dm @@ -5,7 +5,6 @@ dna_cost = 0 req_dna = 1 req_human = 1 - max_genetic_damage = 3 /obj/item/clothing/glasses/changeling name = "flesh" diff --git a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm index 6c56295c05..3c9a0d5d99 100644 --- a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm +++ b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm @@ -54,8 +54,11 @@ clockwork_desc = "A sigil that will stun the next non-Servant to cross it." icon_state = "sigildull" layer = HIGH_SIGIL_LAYER - alpha = 60 + alpha = 75 color = "#FAE48C" + light_range = 1.4 + light_power = 0.4 + light_color = "#FAE48C" sigil_name = "Sigil of Transgression" /obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L) diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm index 35caabab5a..8b3aa01533 100644 --- a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm +++ b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm @@ -326,13 +326,19 @@ if(production_time != SLAB_PRODUCTION_TIME+SLAB_SLOWDOWN_MAXIMUM) production_text_addon = ", which increases for each human or silicon servant above [SCRIPT_SERVANT_REQ]" production_time = production_time/600 - var/production_text = "[round(production_time)] minute\s" + var/list/production_text + if(round(production_time)) + production_text = list("[round(production_time)] minute\s") if(production_time != round(production_time)) production_time -= round(production_time) production_time *= 60 - production_text += " and [round(production_time, 1)] second\s" + if(!LAZYLEN(production_text)) + production_text = list("[round(production_time, 1)] second\s") + else + production_text += " and [round(production_time, 1)] second\s" production_text += "" production_text += production_text_addon + production_text = production_text.Join() textlist = list("
Chetr nyy hagehguf-naq-ubabe Ratvar.

\ \ diff --git a/code/game/gamemodes/clock_cult/clock_mobs.dm b/code/game/gamemodes/clock_cult/clock_mobs.dm index a5e7dee4cb..a86c00e4f6 100644 --- a/code/game/gamemodes/clock_cult/clock_mobs.dm +++ b/code/game/gamemodes/clock_cult/clock_mobs.dm @@ -13,6 +13,7 @@ speak_emote = list("clanks", "clinks", "clunks", "clangs") verb_ask = "requests" verb_exclaim = "proclaims" + verb_whisper = "imparts" verb_yell = "harangues" initial_languages = list(/datum/language/common, /datum/language/ratvar) only_speaks_language = /datum/language/ratvar diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm index 25576f5710..c1b5c0cfff 100644 --- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_applications.dm @@ -10,7 +10,7 @@ It will penetrate mindshield implants once before disappearing." invocations = list("Divinity, enslave...", "...all who trespass here!") channel_time = 70 - consumed_components = list(BELLIGERENT_EYE = 2, GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 1) + consumed_components = list(BELLIGERENT_EYE = 4, GEIS_CAPACITOR = 2, HIEROPHANT_ANSIBLE = 2) whispered = TRUE object_path = /obj/effect/clockwork/sigil/submission/accession prevent_path = /obj/effect/clockwork/sigil/submission @@ -32,7 +32,7 @@ It grows faster to invoke with more adjacent Servants." invocations = list("Shield us...", "...with the...", "... fragments of Engine!") channel_time = 100 - consumed_components = list(VANGUARD_COGWHEEL = 2, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1) + consumed_components = list(VANGUARD_COGWHEEL = 4, REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 2) usage_tip = "This scripture will replace all weaker armor worn by affected Servants." tier = SCRIPTURE_APPLICATION multiple_invokers_used = TRUE @@ -99,7 +99,7 @@ If it remains close to you, you will gradually regain health up to a low amount, but it will die if it goes too far from you." invocations = list("Fright's will...", "...call forth...") channel_time = 100 - consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 2) + consumed_components = list(BELLIGERENT_EYE = 2, VANGUARD_COGWHEEL = 2, GEIS_CAPACITOR = 4) usage_tip = "Marauders are useful as personal bodyguards and frontline warriors." tier = SCRIPTURE_APPLICATION primary_component = GEIS_CAPACITOR @@ -160,7 +160,7 @@ and exceptional speed, though taking damage will temporarily slow it down." invocations = list("Call forth...", "...the soldiers of Armorer.") channel_time = 80 - consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, REPLICANT_ALLOY = 2) + consumed_components = list(BELLIGERENT_EYE = 2, VANGUARD_COGWHEEL = 2, REPLICANT_ALLOY = 4) object_path = /obj/structure/destructible/clockwork/shell/fragment creator_message = "You form an anima fragment, a powerful soul vessel receptacle." observer_message = "The slab disgorges a puddle of black metal that expands and forms into a strange shell!" @@ -179,7 +179,7 @@ desc = "Places a sigil that stores energy to power clockwork structures." invocations = list("Divinity...", "...power our creations!") channel_time = 70 - consumed_components = list(VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 2) + consumed_components = list(VANGUARD_COGWHEEL = 2, GEIS_CAPACITOR = 2, HIEROPHANT_ANSIBLE = 4) whispered = TRUE object_path = /obj/effect/clockwork/sigil/transmission creator_message = "A sigil silently appears below you. It will automatically power clockwork structures near it." @@ -199,7 +199,7 @@ desc = "Creates a clockwork totem that sabotages nearby machinery and funnels drained power into nearby Sigils of Transmission or the area's APC." invocations = list("May this totem...", "...shroud the false suns!") channel_time = 80 - consumed_components = list(BELLIGERENT_EYE = 3, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1) + consumed_components = list(BELLIGERENT_EYE = 5, REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 2) object_path = /obj/structure/destructible/clockwork/powered/interdiction_lens creator_message = "You form an interdiction lens, which disrupts cameras and radios and drains power." observer_message = "A brass totem rises from the ground, a purple gem appearing in its center!" @@ -221,7 +221,7 @@ desc = "Creates a mania motor which will cause brain damage and hallucinations in nearby non-Servant humans. It will also try to convert humans directly adjecent to the motor." invocations = list("May this transmitter...", "...break the will of all who oppose us!") channel_time = 80 - consumed_components = list(GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1) + consumed_components = list(GEIS_CAPACITOR = 5, REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 2) object_path = /obj/structure/destructible/clockwork/powered/mania_motor creator_message = "You form a mania motor which will cause brain damage and hallucinations in nearby humans while active." observer_message = "A two-pronged machine rises from the ground!" @@ -244,7 +244,7 @@ and there is at least one existing cache." invocations = list("May this generator...", "...collect Engine parts that yet hold greatness!") channel_time = 80 - consumed_components = list(BELLIGERENT_EYE = 1, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 3) + consumed_components = list(BELLIGERENT_EYE = 2, GEIS_CAPACITOR = 2, REPLICANT_ALLOY = 5) object_path = /obj/structure/destructible/clockwork/powered/tinkerers_daemon creator_message = "You form a tinkerer's daemon which can rapidly collect components at a power cost." invokers_required = 2 @@ -278,7 +278,7 @@ desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living Servant or clockwork obelisk." invocations = list("May this obelisk...", "...take us to all places!") channel_time = 80 - consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, HIEROPHANT_ANSIBLE = 3) + consumed_components = list(BELLIGERENT_EYE = 2, VANGUARD_COGWHEEL = 2, HIEROPHANT_ANSIBLE = 5) object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk creator_message = "You form a clockwork obelisk which can broadcast messages or produce Spatial Gateways." observer_message = "A brass obelisk appears hanging in midair!" diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_drivers.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_drivers.dm index 023cd50dd1..f246034884 100644 --- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_drivers.dm +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_drivers.dm @@ -272,7 +272,7 @@ var/static/prev_cost = 0 /datum/clockwork_scripture/create_object/tinkerers_cache/creation_update() - var/cache_cost_increase = min(round(GLOB.clockwork_caches*0.25), 5) + var/cache_cost_increase = min(round(GLOB.clockwork_caches*0.4), 10) if(cache_cost_increase != prev_cost) prev_cost = cache_cost_increase consumed_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 0) diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm index 0dbd2d46e8..25bedd79d3 100644 --- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm @@ -9,7 +9,7 @@ desc = "Taps the limitless power of Inath-neq, one of Ratvar's four generals. The benevolence of Inath-Neq will grant complete invulnerability to all Servants in range for fifteen seconds." invocations = list("I call upon you, Vanguard!!", "Let the Resonant Cogs turn once more!!", "Grant me and my allies the strength to vanquish our foes!!") channel_time = 100 - consumed_components = list(VANGUARD_COGWHEEL = 4, GEIS_CAPACITOR = 2, REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 2) + consumed_components = list(VANGUARD_COGWHEEL = 10, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 3) usage_tip = "Servants affected by this scripture are only weak to things that outright destroy bodies, such as bombs or the singularity." tier = SCRIPTURE_REVENANT primary_component = VANGUARD_COGWHEEL @@ -44,7 +44,7 @@ for all non-servant humans on the same z-level as them. The power of this scripture falls off somewhat with distance, and certain things may reduce its effects." invocations = list("I call upon you, Fright!!", "Let your power shatter the sanity of the weak-minded!!", "Let your tendrils hold sway over all!!") channel_time = 150 - consumed_components = list(BELLIGERENT_EYE = 3, VANGUARD_COGWHEEL = 3, GEIS_CAPACITOR = 6, HIEROPHANT_ANSIBLE = 3) + consumed_components = list(BELLIGERENT_EYE = 6, VANGUARD_COGWHEEL = 6, GEIS_CAPACITOR = 10, HIEROPHANT_ANSIBLE = 6) usage_tip = "Causes brain damage, hallucinations, confusion, and dizziness in massive amounts." tier = SCRIPTURE_REVENANT sort_priority = 3 @@ -108,7 +108,7 @@ clockwork proselytizers will charge very rapidly." invocations = list("I call upon you, Armorer!!", "Let your machinations reign on this miserable station!!", "Let your power flow through the tools of your master!!") channel_time = 150 - consumed_components = list(BELLIGERENT_EYE = 3, VANGUARD_COGWHEEL = 3, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 6) + consumed_components = list(BELLIGERENT_EYE = 6, VANGUARD_COGWHEEL = 6, GEIS_CAPACITOR = 6, REPLICANT_ALLOY = 10) usage_tip = "Ocular wardens will become empowered, clockwork proselytizers will require no alloy, tinkerer's daemons will produce twice as quickly, \ and interdiction lenses, mania motors, tinkerer's daemons, and clockwork obelisks will all require no power." tier = SCRIPTURE_REVENANT @@ -153,7 +153,7 @@ will be struck by devastating lightning bolts." invocations = list("I call upon you, Amperage!!", "Let your energy flow through me!!", "Let your boundless power shatter stars!!") channel_time = 100 - consumed_components = list(BELLIGERENT_EYE = 2, GEIS_CAPACITOR = 2, REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 4) + consumed_components = list(BELLIGERENT_EYE = 3, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 10) usage_tip = "Struck targets will also be knocked down for about sixteen seconds." tier = SCRIPTURE_REVENANT primary_component = HIEROPHANT_ANSIBLE diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm index f7fcc8c299..bc5ec1b9d8 100644 --- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm @@ -9,7 +9,7 @@ desc = "Forms an automatic short-range turret which will automatically attack nearby unrestrained non-Servants that can see it." invocations = list("Guardians...", "...of the Engine...", "...defend us!") channel_time = 120 - consumed_components = list(BELLIGERENT_EYE = 1, REPLICANT_ALLOY = 1) + consumed_components = list(BELLIGERENT_EYE = 2, REPLICANT_ALLOY = 1) object_path = /obj/structure/destructible/clockwork/ocular_warden creator_message = "You form an ocular warden, which will automatically attack nearby unrestrained non-Servants that can see it." observer_message = "A brass eye takes shape and slowly rises into the air, its red iris glaring!" @@ -36,7 +36,7 @@ desc = "Creates a small shell fitted for soul vessels. Adding an active soul vessel to it results in a small construct with tools and an inbuilt proselytizer." invocations = list("Call forth...", "...the workers of Armorer.") channel_time = 60 - consumed_components = list(BELLIGERENT_EYE = 1, HIEROPHANT_ANSIBLE = 1) + consumed_components = list(BELLIGERENT_EYE = 2, HIEROPHANT_ANSIBLE = 1) object_path = /obj/structure/destructible/clockwork/shell/cogscarab creator_message = "You form a cogscarab, a constructor soul vessel receptacle." observer_message = "The slab disgorges a puddle of black metal that contracts and forms into a strange shell!" @@ -56,7 +56,7 @@ Matrices have drained from non-Servants. Dead Servants can be revived by this sigil if there is vitality equal to the target Servant's non-oxygen damage." invocations = list("Divinity...", "...steal their life...", "...for these shells!") channel_time = 60 - consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1) + consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 2) whispered = TRUE object_path = /obj/effect/clockwork/sigil/vitality creator_message = "A vitality matrix appears below you. It will drain life from non-Servants and heal Servants that cross it." @@ -77,7 +77,7 @@ chant_invocations = list("Mend our dents!", "Heal our scratches!", "Repair our gears!") chant_amount = 10 chant_interval = 20 - consumed_components = list(VANGUARD_COGWHEEL = 1, REPLICANT_ALLOY = 1) + consumed_components = list(VANGUARD_COGWHEEL = 2, REPLICANT_ALLOY = 1) usage_tip = "This is a very effective way to rapidly reinforce a base after an attack." tier = SCRIPTURE_SCRIPT primary_component = VANGUARD_COGWHEEL @@ -177,6 +177,7 @@ new /obj/effect/overlay/temp/heal(T, "#1E8CE1") else break + new /obj/effect/overlay/temp/ratvar/mending_mantra(get_turf(invoker)) return TRUE @@ -187,7 +188,7 @@ desc = "Places a luminous sigil that will enslave any valid beings standing on it after a time." invocations = list("Divinity, enlighten...", "...those who trespass here!") channel_time = 60 - consumed_components = list(BELLIGERENT_EYE = 1, GEIS_CAPACITOR = 1) + consumed_components = list(BELLIGERENT_EYE = 1, GEIS_CAPACITOR = 2) whispered = TRUE object_path = /obj/effect/clockwork/sigil/submission creator_message = "A luminous sigil appears below you. The next non-servant to cross it will be enslaved after a brief time if they do not move." @@ -207,7 +208,7 @@ desc = "Forms an ancient positronic brain with an overriding directive to serve Ratvar." invocations = list("Herd the souls of...", "...the blasphemous damned!") channel_time = 30 - consumed_components = list(VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 1) + consumed_components = list(VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 2) whispered = TRUE object_path = /obj/item/device/mmi/posibrain/soul_vessel creator_message = "You form a soul vessel, which can be used in-hand to attract spirits, or used on an unconscious or dead human to extract their consciousness." @@ -227,7 +228,7 @@ desc = "Forms a device that, when used on certain objects, converts them into their Ratvarian equivalents. It requires power to function." invocations = list("With this device...", "...his presence shall be made known.") channel_time = 20 - consumed_components = list(GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1) + consumed_components = list(GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 2) whispered = TRUE object_path = /obj/item/clockwork/clockwork_proselytizer/preloaded creator_message = "You form a clockwork proselytizer." @@ -248,7 +249,7 @@ vanish three minutes after being summoned." invocations = list("Grant me...", "...the might of brass!") channel_time = 20 - consumed_components = list(REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1) + consumed_components = list(REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 1) whispered = TRUE usage_tip = "You can impale human targets with the spear by pulling them, then attacking. Throwing the spear at a mob will do massive damage and stun them, but break the spear." tier = SCRIPTURE_SCRIPT @@ -307,7 +308,7 @@ Each servant assisting in the invocation adds one additional use and four additional seconds to the gateway's uses and duration." invocations = list("Spatial Gateway...", "...activate!") channel_time = 80 - consumed_components = list(VANGUARD_COGWHEEL = 1, HIEROPHANT_ANSIBLE = 1) + consumed_components = list(VANGUARD_COGWHEEL = 1, HIEROPHANT_ANSIBLE = 2) multiple_invokers_used = TRUE multiple_invokers_optional = TRUE usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal." @@ -356,7 +357,7 @@ chant_invocations = list("Use charge to kill!", "Slay with power!", "Hunt with energy!") chant_amount = 4 chant_interval = 5 - consumed_components = list(GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 1) + consumed_components = list(GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 2) usage_tip = "Though it requires you to stand still, this scripture can do massive damage." tier = SCRIPTURE_SCRIPT primary_component = HIEROPHANT_ANSIBLE diff --git a/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm b/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm index 614a22a6f5..4beaf226d6 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm @@ -28,7 +28,7 @@ var/mutable_appearance/alert_overlay = mutable_appearance('icons/effects/clockwork_effects.dmi', "ratvar_alert") var/area/A = get_area(src) notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [A.name] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay) - INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency..proc/request, null, 0) + INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency..proc/request, null, 0, 0) /obj/structure/destructible/clockwork/massive/ratvar/Destroy() GLOB.ratvar_awakens-- diff --git a/code/game/gamemodes/clock_cult/clock_structures/tinkerers_daemon.dm b/code/game/gamemodes/clock_cult/clock_structures/tinkerers_daemon.dm index 22ea9e2ce5..b0a17338ff 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/tinkerers_daemon.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/tinkerers_daemon.dm @@ -18,7 +18,7 @@ var/static/mutable_appearance/component_glow = mutable_appearance('icons/obj/clockwork_objects.dmi', "t_random_component") var/component_id_to_produce var/production_time = 0 //last time we produced a component - var/production_cooldown = 120 + var/production_cooldown = 60 /obj/structure/destructible/clockwork/powered/tinkerers_daemon/Initialize() . = ..() diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index 843d16592a..ce4abced72 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -133,7 +133,7 @@ This file contains the arcane tome files. text += "Talisman of Armaments
The Talisman of Arming will equip the user with armored robes, a backpack, an eldritch longsword, an empowered bola, and a pair of boots. Any items that cannot \ be equipped will not be summoned. Attacking a fellow cultist with it will instead equip them.

" - text += "Talisman of Horrors
The Talisman of Horror must be applied directly to the victim, it will shatter your victim's mind with visions of the endtimes that may incapitate them.

" + text += "Talisman of Horrors
The Talisman of Horror, unlike other talismans, can be applied at range, without the victim noticing. It will cause the victim to have severe hallucinations after a short while.

" text += "Talisman of Shackling
The Talisman of Shackling must be applied directly to the victim, it has 4 uses and cuffs victims with magic shackles that disappear when removed.

" diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm index 2411f0c40d..9645b4bbce 100644 --- a/code/game/gamemodes/cult/talisman.dm +++ b/code/game/gamemodes/cult/talisman.dm @@ -293,12 +293,12 @@ invocation = "Lo'Nab Na'Dm!" creation_time = 80 -/obj/item/weapon/paper/talisman/horror/attack(mob/living/target, mob/living/user) - if(iscultist(user)) - to_chat(user, "You disturb [target] with visons of the end!") +/obj/item/weapon/paper/talisman/horror/afterattack(mob/living/target, mob/living/user) + if(iscultist(user) && (get_dist(user, target) < 7)) + to_chat(user, "You disturb [target] with visions of madness!") if(iscarbon(target)) var/mob/living/carbon/H = target - H.reagents.add_reagent("mindbreaker", 25) + H.reagents.add_reagent("mindbreaker", 12) if(is_servant_of_ratvar(target)) to_chat(target, "You see a brief but horrible vision of Ratvar, rusted and scrapped, being torn apart.") target.emote("scream") diff --git a/code/game/gamemodes/gang/gang_datum.dm b/code/game/gamemodes/gang/gang_datum.dm index 3c54d5436b..805cac552f 100644 --- a/code/game/gamemodes/gang/gang_datum.dm +++ b/code/game/gamemodes/gang/gang_datum.dm @@ -13,6 +13,7 @@ var/list/territory = list() var/list/territory_new = list() var/list/territory_lost = list() + var/recalls = 1 var/dom_attempts = 2 var/points = 15 var/datum/atom_hud/antag/gang/ganghud @@ -262,4 +263,4 @@ ganghud = new() /datum/gang/multiverse/income() - return \ No newline at end of file + return diff --git a/code/game/gamemodes/gang/recaller.dm b/code/game/gamemodes/gang/recaller.dm index 0885b32612..f67bcad50a 100644 --- a/code/game/gamemodes/gang/recaller.dm +++ b/code/game/gamemodes/gang/recaller.dm @@ -168,6 +168,9 @@ if(recalling) to_chat(usr, "Error: Recall already in progress.") return 0 + + if(!gang.recalls) + to_chat(usr, "Error: Unable to access communication arrays. Firewall has logged our signature and is blocking all further attempts.") gang.message_gangtools("[usr] is attempting to recall the emergency shuttle.") recalling = 1 @@ -209,6 +212,7 @@ userturf = get_turf(user) if(userturf.z == 1) //Check one more time that they are on station. if(SSshuttle.cancelEvac(user)) + gang.recalls -= 1 return 1 to_chat(loc, "\icon[src]No response recieved. Emergency shuttle cannot be recalled at this time.") diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm index 7260d8221f..265688a15b 100644 --- a/code/game/gamemodes/miniantags/revenant/revenant.dm +++ b/code/game/gamemodes/miniantags/revenant/revenant.dm @@ -14,6 +14,7 @@ var/icon_reveal = "revenant_revealed" var/icon_stun = "revenant_stun" var/icon_drain = "revenant_draining" + var/stasis = 0 incorporeal_move = 3 invisibility = INVISIBILITY_REVENANT health = INFINITY //Revenants don't use health, they use essence instead @@ -94,6 +95,8 @@ //Life, Stat, Hud Updates, and Say /mob/living/simple_animal/revenant/Life() + if(stasis) + return if(revealed && essence <= 0) death() if(unreveal_time && world.time >= unreveal_time) @@ -200,9 +203,8 @@ death() /mob/living/simple_animal/revenant/death() - if(!revealed || stat == DEAD) //Revenants cannot die if they aren't revealed //or are already dead + if(!revealed || stasis) //Revenants cannot die if they aren't revealed //or are already dead return 0 - ..(1) to_chat(src, "NO! No... it's too late, you can feel your essence [pick("breaking apart", "drifting away")]...") notransform = TRUE revealed = TRUE @@ -217,9 +219,12 @@ var/reforming_essence = essence_regen_cap //retain the gained essence capacity var/obj/item/weapon/ectoplasm/revenant/R = new(get_turf(src)) R.essence = max(reforming_essence - 15 * perfectsouls, 75) //minus any perfect souls - R.client_to_revive = src.client //If the essence reforms, the old revenant is put back in the body - ghostize() - qdel(src) + R.client_to_revive = client //If the essence reforms, the old revenant is put back in the body + R.revenant = src + invisibility = INVISIBILITY_ABSTRACT + revealed = 0 + stasis = 1 + ghostize(0)//Don't re-enter invisible corpse return @@ -302,6 +307,18 @@ to_chat(src, "Lost [essence_amt]E[source ? " from [source]":""].") return 1 +/mob/living/simple_animal/revenant/proc/death_reset() + revealed = FALSE + unreveal_time = 0 + notransform = 0 + unstun_time = 0 + inhibited = FALSE + draining = FALSE + incorporeal_move = 3 + invisibility = INVISIBILITY_REVENANT + alpha=255 + stasis = 0 + //reforming /obj/item/weapon/ectoplasm/revenant @@ -314,11 +331,15 @@ var/reforming = TRUE var/inert = FALSE var/client/client_to_revive + var/mob/living/simple_animal/revenant/revenant /obj/item/weapon/ectoplasm/revenant/New() ..() addtimer(CALLBACK(src, .proc/try_reform), 600) +/obj/item/weapon/ectoplasm/revenant/proc/scatter() + qdel(src) + /obj/item/weapon/ectoplasm/revenant/proc/try_reform() if(reforming) reforming = FALSE @@ -333,14 +354,14 @@ user.visible_message("[user] scatters [src] in all directions.", \ "You scatter [src] across the area. The particles slowly fade away.") user.drop_item() - qdel(src) + scatter() /obj/item/weapon/ectoplasm/revenant/throw_impact(atom/hit_atom) ..() if(inert) return visible_message("[src] breaks into particles upon impact, which fade away to nothingness.") - qdel(src) + scatter() /obj/item/weapon/ectoplasm/revenant/examine(mob/user) ..() @@ -350,47 +371,51 @@ to_chat(user, "It is shifting and distorted. It would be wise to destroy this.") /obj/item/weapon/ectoplasm/revenant/proc/reform() - if(QDELETED(src) || inert) + if(QDELETED(src) || QDELETED(revenant) || inert) 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 - var/mob/living/simple_animal/revenant/R = new(get_turf(src)) + revenant.forceMove(loc) if(client_to_revive) for(var/mob/M in GLOB.dead_mob_list) if(M.client == client_to_revive) //Only recreates the mob if the mob the client is in is dead - R.client = client_to_revive + revenant.client = client_to_revive key_of_revenant = client_to_revive.key if(!key_of_revenant) message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...") - var/list/candidates = get_candidates(ROLE_REVENANT) + var/list/candidates = pollCandidatesForMob("Do you want to be [revenant.name] (reforming)?", "revenant", null, ROLE_REVENANT, 50, revenant) if(!candidates.len) - qdel(R) + qdel(revenant) message_admins("No candidates were found for the new revenant. Oh well!") inert = TRUE visible_message("[src] settles down and seems lifeless.") return var/client/C = pick(candidates) + revenant.client = C key_of_revenant = C.key if(!key_of_revenant) - qdel(R) + qdel(revenant) message_admins("No ckey was found for the new revenant. Oh well!") inert = TRUE visible_message("[src] settles down and seems lifeless.") return - var/datum/mind/player_mind = new /datum/mind(key_of_revenant) - R.essence_regen_cap = essence - R.essence = R.essence_regen_cap - player_mind.active = 1 - player_mind.transfer_to(R) - player_mind.assigned_role = "revenant" - player_mind.special_role = "Revenant" - SSticker.mode.traitors |= player_mind + message_admins("[key_of_revenant] has been [client_to_revive ? "re":""]made into a revenant by reforming ectoplasm.") log_game("[key_of_revenant] was [client_to_revive ? "re":""]made as a revenant by reforming ectoplasm.") visible_message("[src] suddenly rises into the air before fading away.") + + revenant.essence = essence + revenant.essence_regen_cap = essence + revenant.death_reset() + revenant.key = key_of_revenant + revenant = null qdel(src) +/obj/item/weapon/ectoplasm/revenant/Destroy() + if(!QDELETED(revenant)) + qdel(revenant) + ..() //objectives /datum/objective/revenant diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm index c66b48a6c8..f3ddb6d4be 100644 --- a/code/game/gamemodes/nuclear/pinpointer.dm +++ b/code/game/gamemodes/nuclear/pinpointer.dm @@ -17,6 +17,7 @@ var/atom/movable/constant_target = null //The thing we're always focused on, if we're in the right mode var/target_x = 0 //The target coordinates if we're tracking those var/target_y = 0 + var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination var/nuke_warning = FALSE // If we've set off a miniature alarm about an armed nuke var/mode = TRACK_NUKE_DISK //What are we looking for? @@ -111,7 +112,7 @@ var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here) if(closest_operative) target = closest_operative - if(TRACK_ATOM) + if(TRACK_ATOM) if(constant_target) target = constant_target if(TRACK_COORDINATES) @@ -129,7 +130,7 @@ if(here.z != there.z) icon_state = "pinon[nuke_warning ? "alert" : ""]null" return - if(here == there) + if(get_dist_euclidian(here,there)<=minimum_range) icon_state = "pinon[nuke_warning ? "alert" : ""]direct" else setDir(get_dir(here, there)) @@ -171,3 +172,6 @@ desc = "An integrated tracking device, jury-rigged to search for living Syndicate operatives." mode = TRACK_OPERATIVES flags = NODROP + + + diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 6ac0ab8c7c..039b4cc3a4 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -67,7 +67,14 @@ /datum/objective/proc/update_explanation_text() //Default does nothing, override where needed -/datum/objective/proc/give_special_equipment() +/datum/objective/proc/give_special_equipment(special_equipment) + if(owner && owner.current) + if(ishuman(owner.current)) + var/mob/living/carbon/human/H = owner.current + var/list/slots = list ("backpack" = slot_in_backpack) + for(var/eq_path in special_equipment) + var/obj/O = new eq_path + H.equip_in_one_of_slots(O, slots) /datum/objective/assassinate var/target_role_type=0 @@ -94,6 +101,14 @@ else explanation_text = "Free Objective" +/datum/objective/assassinate/internal + var/stolen = 0 //Have we already eliminated this target? + +/datum/objective/assassinate/internal/update_explanation_text() + ..() + if(target && !target.current) + explanation_text = "Assassinate [target.name], who was obliterated" + /datum/objective/mutiny var/target_role_type=0 @@ -468,7 +483,7 @@ GLOBAL_LIST_EMPTY(possible_items) steal_target = targetinfo.targetitem explanation_text = "Steal [targetinfo.name]." dangerrating = targetinfo.difficulty - give_special_equipment() + give_special_equipment(targetinfo.special_equipment) return steal_target else explanation_text = "Free objective" @@ -511,15 +526,6 @@ GLOBAL_LIST_EMPTY(possible_items) return 1 return 0 -/datum/objective/steal/give_special_equipment() - if(owner && owner.current && targetinfo) - if(ishuman(owner.current)) - var/mob/living/carbon/human/H = owner.current - var/list/slots = list ("backpack" = slot_in_backpack) - for(var/eq_path in targetinfo.special_equipment) - var/obj/O = new eq_path - H.equip_in_one_of_slots(O, slots) - GLOBAL_LIST_EMPTY(possible_items_special) /datum/objective/steal/special //ninjas are so special they get their own subtype good for them @@ -695,6 +701,9 @@ GLOBAL_LIST_EMPTY(possible_items_special) explanation_text = "Destroy [target.name], the experimental AI." else explanation_text = "Free Objective" + +/datum/objective/destroy/internal + var/stolen = FALSE //Have we already eliminated this target? /datum/objective/steal_five_of_type explanation_text = "Steal at least five items!" diff --git a/code/game/gamemodes/traitor/double_agents.dm b/code/game/gamemodes/traitor/double_agents.dm index cb6609ebe6..2ee546c7aa 100644 --- a/code/game/gamemodes/traitor/double_agents.dm +++ b/code/game/gamemodes/traitor/double_agents.dm @@ -1,9 +1,13 @@ +#define PINPOINTER_MINIMUM_RANGE 15 +#define PINPOINTER_EXTRA_RANDOM_RANGE 10 +#define PINPOINTER_PING_TIME 40 + /datum/game_mode/traitor/internal_affairs name = "Internal Affairs" config_tag = "internal_affairs" employer = "Internal Affairs" - required_players = 25 - required_enemies = 5 + required_players = 25 + required_enemies = 5 recommended_enemies = 8 reroll_friendly = 0 traitor_name = "Nanotrasen Internal Affairs Agent" @@ -18,15 +22,189 @@ var/list/target_list = list() var/list/late_joining_list = list() + /datum/game_mode/traitor/internal_affairs/post_setup() var/i = 0 for(var/datum/mind/traitor in traitors) i++ if(i + 1 > traitors.len) i = 0 - target_list[traitor] = traitors[i + 1] + target_list[traitor] = traitors[i+1] ..() + +/datum/status_effect/agent_pinpointer + id = "agent_pinpointer" + duration = -1 + tick_interval = PINPOINTER_PING_TIME + alert_type = /obj/screen/alert/status_effect/agent_pinpointer + var/minimum_range = PINPOINTER_MINIMUM_RANGE + var/mob/scan_target = null + +/obj/screen/alert/status_effect/agent_pinpointer + name = "Internal Affairs Integrated Pinpointer" + desc = "Even stealthier than a normal implant." + icon = 'icons/obj/device.dmi' + icon_state = "pinon" + +/datum/status_effect/agent_pinpointer/proc/point_to_target() //If we found what we're looking for, show the distance and direction + if(!scan_target) + linked_alert.icon_state = "pinonnull" + return + var/turf/here = get_turf(owner) + var/turf/there = get_turf(scan_target) + if(here.z != there.z) + linked_alert.icon_state = "pinonnull" + return + if(get_dist_euclidian(here,there)<=minimum_range + rand(0, PINPOINTER_EXTRA_RANDOM_RANGE)) + linked_alert.icon_state = "pinondirect" + else + linked_alert.setDir(get_dir(here, there)) + switch(get_dist(here, there)) + if(1 to 8) + linked_alert.icon_state = "pinonclose" + if(9 to 16) + linked_alert.icon_state = "pinonmedium" + if(16 to INFINITY) + linked_alert.icon_state = "pinonfar" + + +/datum/status_effect/agent_pinpointer/proc/scan_for_target() + scan_target = null + if(owner) + if(owner.mind) + if(owner.mind.objectives) + for(var/datum/objective/objective_ in owner.mind.objectives) + if(!is_internal_objective(objective_)) + continue + var/datum/objective/assassinate/internal/objective = objective_ + var/mob/current = objective.target.current + if(current&¤t.stat!=DEAD) + scan_target = current + break + + +/datum/status_effect/agent_pinpointer/tick() + if(!owner) + qdel(src) + return + scan_for_target() + point_to_target() + +/proc/give_pinpointer(datum/mind/owner) + if(owner && owner.current) + owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer) + + +/datum/internal_agent_state + var/traitored = FALSE + var/datum/mind/owner = null + var/list/datum/mind/targets_stolen = list() + +/proc/is_internal_objective(datum/objective/O) + return (istype(O, /datum/objective/assassinate/internal)||istype(O, /datum/objective/destroy/internal)) + +/proc/replace_escape_objective(datum/mind/owner) + if(!owner||!owner.objectives) + return + for (var/objective_ in owner.objectives) + if(!(istype(objective_, /datum/objective/escape)||istype(objective_,/datum/objective/survive))) + continue + owner.objectives -= objective_ + var/datum/objective/martyr/martyr_objective = new + martyr_objective.owner = owner + owner.objectives += martyr_objective + +/proc/reinstate_escape_objective(datum/mind/owner) + if(!owner||!owner.objectives) + return + for (var/objective_ in owner.objectives) + if(!istype(objective_, /datum/objective/martyr)) + continue + owner.objectives -= objective_ + if(issilicon(owner)) + var/datum/objective/survive/survive_objective = new + survive_objective.owner = owner + owner.objectives += survive_objective + else + var/datum/objective/escape/escape_objective = new + escape_objective.owner = owner + owner.objectives += escape_objective + +/datum/internal_agent_state/proc/steal_targets(datum/mind/victim) + if(!owner.current||owner.current.stat==DEAD) //Should already be guaranteed if this is only called from steal_targets_timer_func, but better to be safe code than sorry code + return + var/already_traitored = traitored + to_chat(owner.current, " Target eliminated: [victim.name]") + for(var/objective_ in victim.objectives) + if(istype(objective_, /datum/objective/assassinate/internal)) + var/datum/objective/assassinate/internal/objective = objective_ + if(objective.target==owner) + traitored = TRUE + else if(targets_stolen.Find(objective.target) == 0) + var/datum/objective/assassinate/internal/new_objective = new + new_objective.owner = owner + new_objective.target = objective.target + new_objective.update_explanation_text() + owner.objectives += new_objective + targets_stolen += objective.target + var/status_text = objective.check_completion() ? "neutralised" : "active" + to_chat(owner.current, " New target added to database: [objective.target.name] ([status_text]) ") + else if(istype(objective_, /datum/objective/destroy/internal)) + var/datum/objective/destroy/internal/objective = objective_ + var/datum/objective/destroy/internal/new_objective = new + if(objective.target==owner) + traitored = TRUE + else if(targets_stolen.Find(objective.target) == 0) + new_objective.owner = owner + new_objective.target = objective.target + new_objective.update_explanation_text() + owner.objectives += new_objective + targets_stolen += objective.target + var/status_text = objective.check_completion() ? "neutralised" : "active" + to_chat(owner.current, " New target added to database: [objective.target.name] ([status_text]) ") + if(traitored&&!already_traitored) + for(var/objective_ in owner.objectives) + if(!is_internal_objective(objective_)) + continue + var/datum/objective/assassinate/internal/objective = objective_ + if(!objective.check_completion()) + traitored = FALSE + return + to_chat(owner.current," All the other agents are dead, and you're the last loose end. Stage a Syndicate terrorist attack to cover up for today's events. You no longer have any limits on collateral damage.") + replace_escape_objective(owner) + + + +/datum/internal_agent_state/proc/steal_targets_timer_func() + if(owner&&owner.current&&owner.current.stat!=DEAD) + for(var/objective_ in owner.objectives) + if(!is_internal_objective(objective_)) + continue + var/datum/objective/assassinate/internal/objective = objective_ + if(!objective.target) + continue + if(objective.check_completion()) + if(objective.stolen) + continue + else + steal_targets(objective.target) + objective.stolen = TRUE + else + if(objective.stolen) + var/fail_msg = "Your sensors tell you that [objective.target.current.real_name], one of the targets you were meant to have killed, pulled one over on you, and is still alive - do the job properly this time! " + if(traitored) + fail_msg += " The truth could still slip out! Cease any terrorist actions as soon as possible, unneeded property damage or loss of employee life will lead to your contract being terminated." + reinstate_escape_objective(owner) + traitored = FALSE + to_chat(owner.current, fail_msg) + objective.stolen = FALSE + add_steal_targets_timer(owner) + +/datum/internal_agent_state/proc/add_steal_targets_timer() + var/datum/callback/C = new(src, .steal_targets_timer_func) + addtimer(C, 30) + /datum/game_mode/traitor/internal_affairs/forge_traitor_objectives(datum/mind/traitor) if(target_list.len && target_list[traitor]) // Is a double agent @@ -34,13 +212,13 @@ // Assassinate var/datum/mind/target_mind = target_list[traitor] if(issilicon(target_mind.current)) - var/datum/objective/destroy/destroy_objective = new + var/datum/objective/destroy/internal/destroy_objective = new destroy_objective.owner = traitor destroy_objective.target = target_mind destroy_objective.update_explanation_text() traitor.objectives += destroy_objective else - var/datum/objective/assassinate/kill_objective = new + var/datum/objective/assassinate/internal/kill_objective = new kill_objective.owner = traitor kill_objective.target = target_mind kill_objective.update_explanation_text() @@ -55,6 +233,11 @@ var/datum/objective/escape/escape_objective = new escape_objective.owner = traitor traitor.objectives += escape_objective + var/datum/internal_agent_state/state = new + state.owner=traitor + state.add_steal_targets_timer() + if(!issilicon(traitor.current)) + give_pinpointer(traitor) else ..() // Give them standard objectives. @@ -106,14 +289,18 @@ /datum/game_mode/traitor/internal_affairs/greet_traitor(datum/mind/traitor) var/crime = pick("distribution of contraband" , "unauthorized erotic action on duty", "embezzlement", "piloting under the influence", "dereliction of duty", "syndicate collaboration", "mutiny", "multiple homicides", "corporate espionage", "recieving bribes", "malpractice", "worship of prohbited life forms", "possession of profane texts", "murder", "arson", "insulting their manager", "grand theft", "conspiracy", "attempting to unionize", "vandalism", "gross incompetence") - to_chat(traitor.current, "You are the [traitor_name].") - to_chat(traitor.current, "Your target is suspected of [crime], and you have been tasked with eliminating them by any means necessary to avoid a costly and embarrassing public trial.") + to_chat(traitor.current, "You are the [traitor_name].") + to_chat(traitor.current, "Your target is suspected of [crime], and you have been tasked with eliminating them by any means necessary to avoid a costly and embarrassing public trial.") to_chat(traitor.current, "While you have a license to kill, unneeded property damage or loss of employee life will lead to your contract being terminated.") - to_chat(traitor.current, "For the sake of plausible deniability, you have been equipped with an array of captured Syndicate weaponry available via uplink.") - to_chat(traitor.current, "Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them.") + to_chat(traitor.current, "For the sake of plausible deniability, you have been equipped with an array of captured Syndicate weaponry available via uplink.") + to_chat(traitor.current, "Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them.") traitor.announce_objectives() /datum/game_mode/traitor/internal_affairs/give_codewords(mob/living/traitor_mob) - return \ No newline at end of file + return + +#undef PINPOINTER_EXTRA_RANDOM_RANGE +#undef PINPOINTER_MINIMUM_RANGE +#undef PINPOINTER_PING_TIME diff --git a/code/game/machinery/computer/telecrystalconsoles.dm b/code/game/machinery/computer/telecrystalconsoles.dm index 4bb872b347..fd026e4686 100644 --- a/code/game/machinery/computer/telecrystalconsoles.dm +++ b/code/game/machinery/computer/telecrystalconsoles.dm @@ -58,7 +58,12 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E /obj/machinery/computer/telecrystals/uplinker/proc/donateTC(amt, addLog = 1) if(uplinkholder && linkedboss) - if(amt <= uplinkholder.hidden_uplink.telecrystals) + if(amt < 0) + linkedboss.storedcrystals += uplinkholder.hidden_uplink.telecrystals + if(addLog) + linkedboss.logTransfer("[src] donated [uplinkholder.hidden_uplink.telecrystals] telecrystals to [linkedboss].") + uplinkholder.hidden_uplink.telecrystals = 0 + else if(amt <= uplinkholder.hidden_uplink.telecrystals) uplinkholder.hidden_uplink.telecrystals -= amt linkedboss.storedcrystals += amt if(addLog) @@ -66,7 +71,12 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E /obj/machinery/computer/telecrystals/uplinker/proc/giveTC(amt, addLog = 1) if(uplinkholder && linkedboss) - if(amt <= linkedboss.storedcrystals) + if(amt < 0) + uplinkholder.hidden_uplink.telecrystals += linkedboss.storedcrystals + if(addLog) + linkedboss.logTransfer("[src] received [linkedboss.storedcrystals] telecrystals from [linkedboss].") + linkedboss.storedcrystals = 0 + else if(amt <= linkedboss.storedcrystals) uplinkholder.hidden_uplink.telecrystals += amt linkedboss.storedcrystals -= amt if(addLog) @@ -89,7 +99,7 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E if(uplinkholder) dat += "[uplinkholder.hidden_uplink.telecrystals] telecrystals remain in this uplink.
" if(linkedboss) - dat += "Donate TC: 1 | 5" + dat += "Donate TC: 1 | 5 | All" dat += "
Eject Uplink" @@ -103,11 +113,9 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E if(..()) return - if(href_list["donate1"]) - donateTC(1) - - if(href_list["donate5"]) - donateTC(5) + if(href_list["donate"]) + var/tcamt = text2num(href_list["donate"]) + donateTC(tcamt) if(href_list["eject"]) ejectuplink() @@ -162,7 +170,7 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E var/dat = "" dat += "Scan for TC stations.
" - dat += "This [src] has [storedcrystals] telecrystals available for distribution.
" + dat += "[storedcrystals] telecrystals are available for distribution.
" dat += "

" @@ -171,10 +179,10 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E if(A.uplinkholder) dat += "[A.uplinkholder.hidden_uplink.telecrystals] telecrystals." if(storedcrystals) - dat+= "
Add TC: 1 | 5" + dat+= "
Add TC: 1 | 5 | 10 | All" dat += "
" - if(TCstations.len) + if(TCstations.len && storedcrystals) dat += "

Evenly distribute remaining TC.

" @@ -195,13 +203,11 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E if(href_list["scan"]) scanUplinkers() - if(href_list["give1"]) - var/obj/machinery/computer/telecrystals/uplinker/A = locate(href_list["give1"]) - A.giveTC(1) - - if(href_list["give5"]) - var/obj/machinery/computer/telecrystals/uplinker/A = locate(href_list["give5"]) - A.giveTC(5) + if(href_list["give"]) + var/tcamt = text2num(href_list["give"]) + if(TCstations.len) // sanity + var/obj/machinery/computer/telecrystals/uplinker/A = locate(href_list["target"]) in TCstations + A.giveTC(tcamt) if(href_list["distrib"]) var/sanity = 0 diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index ae8c1ac1c4..30ff4c23a0 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -26,14 +26,13 @@ Possible to do for anyone motivated enough: #define HOLOPAD_PASSIVE_POWER_USAGE 1 #define HOLOGRAM_POWER_USAGE 2 -#define RANGE_BASED 4 -#define AREA_BASED 6 +GLOBAL_LIST_EMPTY(holopads) #define HOLOPAD_MODE RANGE_BASED /obj/machinery/holopad - name = "\improper AI holopad" - desc = "It's a floor-mounted device for projecting holographic images. It is activated remotely." + name = "Holopad" + desc = "It's a floor-mounted device for projecting holographic images." icon_state = "holopad0" layer = LOW_OBJ_LAYER flags = HEAR @@ -44,21 +43,32 @@ Possible to do for anyone motivated enough: obj_integrity = 300 max_integrity = 300 armor = list(melee = 50, bullet = 20, laser = 20, energy = 20, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 0) - var/list/masters = list()//List of AIs that use the holopad + var/list/masters = list()//List of living mobs that use the holopad var/last_request = 0 //to prevent request spam. ~Carn var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating. var/temp = "" + var/list/holo_calls //array of /datum/holocalls + var/datum/holocall/outgoing_call //do not modify the datums only check and call the public procs + var/static/force_answer_call = FALSE //Calls will be automatically answered after a couple rings, here for debugging var/static/list/holopads = list() -/obj/machinery/holopad/New() +/obj/machinery/holopad/Initialize() ..() var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/holopad(null) B.apply_default_parts(src) holopads += src /obj/machinery/holopad/Destroy() - for (var/mob/living/silicon/ai/master in masters) - clear_holo(master) + if(outgoing_call) + LAZYADD(holo_calls, outgoing_call) + + for(var/I in holo_calls) + var/datum/holocall/HC = I + HC.ConnectionFailure(src) + LAZYCLEARLIST(holo_calls) + + for (var/I in masters) + clear_holo(I) holopads -= src return ..() @@ -91,20 +101,58 @@ Possible to do for anyone motivated enough: return return ..() +/obj/machinery/holopad/proc/CheckCallClose() + for(var/I in holo_calls) + var/datum/holocall/HC = I + if(usr == HC.eye) + HC.Disconnect(HC.calling_holopad) //disconnect via clicking the called holopad + return TRUE + return FALSE + +/obj/machinery/holopad/Click(location,control,params) + if(!CheckCallClose()) + return ..() + /obj/machinery/holopad/AltClick(mob/living/carbon/human/user) - interact(user) + if(!CheckCallClose()) + interact(user) /obj/machinery/holopad/interact(mob/living/carbon/human/user) //Carn: Hologram requests. if(!istype(user)) return - if(user.stat || !is_operational()) + + if(outgoing_call || user.incapacitated() || !is_operational()) return + user.set_machine(src) var/dat if(temp) dat = temp else - dat = "request an AI's presence." + dat = "Request an AI's presence.
" + dat += "Call another holopad.
" + + if(LAZYLEN(holo_calls)) + dat += "=====================================================
" + + var/one_answered_call = FALSE + var/one_unanswered_call = FALSE + for(var/I in holo_calls) + var/datum/holocall/HC = I + if(HC.connected_holopad != src) + dat += "Answer call from [get_area(HC.calling_holopad)].
" + one_unanswered_call = TRUE + else + one_answered_call = TRUE + + if(one_answered_call && one_unanswered_call) + dat += "=====================================================
" + //we loop twice for formatting + for(var/I in holo_calls) + var/datum/holocall/HC = I + if(HC.connected_holopad == src) + dat += "Disconnect call from [HC.user].
" + var/datum/browser/popup = new(user, "holopad", name, 300, 130) popup.set_content(dat) @@ -112,7 +160,10 @@ Possible to do for anyone motivated enough: popup.open() /obj/machinery/holopad/Topic(href, href_list) - if(..() || !is_operational()) + if(..() || isAI(usr)) + return + add_fingerprint(usr) + if(!is_operational()) return if (href_list["AIrequest"]) if(last_request + 200 < world.time) @@ -120,7 +171,7 @@ Possible to do for anyone motivated enough: temp = "You requested an AI's presence.
" temp += "Main Menu" var/area/area = get_area(src) - for(var/mob/living/silicon/ai/AI in GLOB.living_mob_list) + for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs) if(!AI.client) continue to_chat(AI, "Your presence is requested at \the [area].") @@ -128,12 +179,49 @@ Possible to do for anyone motivated enough: temp = "A request for AI presence was already sent recently.
" temp += "Main Menu" - else if(href_list["mainmenu"]) + else if(href_list["Holocall"]) + if(outgoing_call) + return + + temp = "You must stand on the holopad to make a call!
" + temp += "Main Menu" + if(usr.loc == loc) + var/list/callnames = list() + for(var/I in holopads) + var/area/A = get_area(I) + if(A) + LAZYADD(callnames[A], I) + callnames -= get_area(src) + + var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in callnames + if(QDELETED(usr) || !result || outgoing_call) + return + + if(usr.loc == loc) + temp = "Dialing...
" + temp += "Main Menu" + new /datum/holocall(usr, src, callnames[result]) + + else if(href_list["connectcall"]) + var/datum/holocall/call_to_connect = locate(href_list["connectcall"]) + if(!QDELETED(call_to_connect)) + call_to_connect.Answer(src) temp = "" - updateDialog() - add_fingerprint(usr) + else if(href_list["disconnectcall"]) + var/datum/holocall/call_to_disconnect = locate(href_list["disconnectcall"]) + if(!QDELETED(call_to_disconnect)) + call_to_disconnect.Disconnect(src) + temp = "" + else if(href_list["mainmenu"]) + temp = "" + if(outgoing_call) + outgoing_call.Disconnect() + + updateDialog() + +//do not allow AIs to answer calls or people will use it to meta the AI sattelite /obj/machinery/holopad/attack_ai(mob/living/silicon/ai/user) if (!istype(user)) return @@ -148,39 +236,75 @@ Possible to do for anyone motivated enough: clear_holo(user) /obj/machinery/holopad/process() - if(masters.len)//If there is a hologram. - for (var/mob/living/silicon/ai/master in masters) - if(master && !master.stat && master.client && master.eyeobj)//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector. - if(!(stat & NOPOWER))//If the machine has power. - if(HOLOPAD_MODE == RANGE_BASED) - if(get_dist(master.eyeobj, src) <= holo_range) - return TRUE - else - var/obj/machinery/holopad/pad_close = get_closest_atom(/obj/machinery/holopad, holopads, master.eyeobj) - if(get_dist(pad_close, master.eyeobj) <= holo_range) - var/obj/effect/overlay/holo_pad_hologram/h = masters[master] - unset_holo(master) - pad_close.set_holo(master, h) - return TRUE + for(var/I in masters) + var/mob/living/master = I + var/mob/living/silicon/ai/AI = master + if(!istype(AI)) + AI = null - else if (HOLOPAD_MODE == AREA_BASED) + if(!QDELETED(master) && !master.incapacitated() && master.client && (!AI || AI.eyeobj))//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector. + if(is_operational())//If the machine has power. + if(AI) //ais are range based + if(get_dist(AI.eyeobj, src) <= holo_range) + continue + else + var/obj/machinery/holopad/pad_close = get_closest_atom(/obj/machinery/holopad, holopads, AI.eyeobj) + if(get_dist(pad_close, AI.eyeobj) <= holo_range) + var/obj/effect/overlay/holo_pad_hologram/h = masters[master] + unset_holo(master) + pad_close.set_holo(master, h) + continue + else + continue + clear_holo(master)//If not, we want to get rid of the hologram. - var/area/holo_area = get_area(src) - var/area/eye_area = get_area(master.eyeobj) + if(outgoing_call) + outgoing_call.Check() - if(eye_area in holo_area.related) - return TRUE + for(var/I in holo_calls) + var/datum/holocall/HC = I + if(HC.connected_holopad != src) + if(force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2))) + HC.Answer(src) + break + if(outgoing_call) + HC.Disconnect(src)//can't answer calls while calling + else + playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring! - clear_holo(master)//If not, we want to get rid of the hologram. - return TRUE +/obj/machinery/holopad/proc/activate_holo(mob/living/user) + var/mob/living/silicon/ai/AI = user + if(!istype(AI)) + AI = null -/obj/machinery/holopad/proc/activate_holo(mob/living/silicon/ai/user) - if(!(stat & NOPOWER) && user.eyeobj.loc == src.loc)//If the projector has power and client eye is on it - if (istype(user.current, /obj/machinery/holopad)) + if(is_operational() && (!AI || AI.eyeobj.loc == loc))//If the projector has power and client eye is on it + if (AI && istype(AI.current, /obj/machinery/holopad)) to_chat(user, "ERROR: \black Image feed in progress.") return - create_holo(user)//Create one. - src.visible_message("A holographic image of [user] flicks to life right before your eyes!") + + var/obj/effect/overlay/holo_pad_hologram/Hologram = new(loc)//Spawn a blank effect at the location. + if(AI) + Hologram.icon = AI.holo_icon + else //make it like real life + Hologram.icon = user.icon + Hologram.icon_state = user.icon_state + Hologram.copy_overlays(user, TRUE) + //codersprite some holo effects here + Hologram.alpha = 100 + Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY) + Hologram.Impersonation = user + + Hologram.languages = user.languages + Hologram.mouse_opacity = 0//So you can't click on it. + Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them. + Hologram.anchored = 1//So space wind cannot drag it. + Hologram.name = "[user.name] (Hologram)"//If someone decides to right click. + Hologram.set_light(2) //hologram lighting + + set_holo(user, Hologram) + visible_message("A holographic image of [user] flicks to life right before your eyes!") + + return Hologram else to_chat(user, "ERROR: \black Unable to project hologram.") @@ -192,58 +316,80 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ if(masters[master] && speaker != master) master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode) -/obj/machinery/holopad/proc/create_holo(mob/living/silicon/ai/A, turf/T = loc) - var/obj/effect/overlay/holo_pad_hologram/h = new(T)//Spawn a blank effect at the location. - h.icon = A.holo_icon - h.mouse_opacity = 0//So you can't click on it. - h.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them. - h.anchored = 1//So space wind cannot drag it. - h.name = "[A.name] (Hologram)"//If someone decides to right click. - h.set_light(2) //hologram lighting - set_holo(A, h) + for(var/I in holo_calls) + var/datum/holocall/HC = I + if(HC.connected_holopad == src && speaker != HC.hologram) + HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode) + + if(outgoing_call && speaker == outgoing_call.user) + outgoing_call.hologram.say(raw_message) + +/obj/machinery/holopad/proc/SetLightsAndPower() + var/total_users = masters.len + LAZYLEN(holo_calls) + use_power = HOLOPAD_PASSIVE_POWER_USAGE + HOLOGRAM_POWER_USAGE * total_users + if(total_users) + set_light(2) + icon_state = "holopad1" + else + set_light(0) + icon_state = "holopad0" + +/obj/machinery/holopad/proc/set_holo(mob/living/user, var/obj/effect/overlay/holo_pad_hologram/h) + masters[user] = h + var/mob/living/silicon/ai/AI = user + if(istype(AI)) + AI.current = src + SetLightsAndPower() return TRUE -/obj/machinery/holopad/proc/set_holo(mob/living/silicon/ai/A, var/obj/effect/overlay/holo_pad_hologram/h) - masters[A] = h - set_light(2) // pad lighting - icon_state = "holopad1" - A.current = src - use_power += HOLOGRAM_POWER_USAGE - return TRUE - -/obj/machinery/holopad/proc/clear_holo(mob/living/silicon/ai/user) +/obj/machinery/holopad/proc/clear_holo(mob/living/user) qdel(masters[user]) // Get rid of user's hologram unset_holo(user) return TRUE -/obj/machinery/holopad/proc/unset_holo(mob/living/silicon/ai/user) - if(user.current == src) - user.current = null +/obj/machinery/holopad/proc/unset_holo(mob/living/user) + var/mob/living/silicon/ai/AI = user + if(istype(AI) && AI.current == src) + AI.current = null masters -= user // Discard AI from the list of those who use holopad - use_power = max(HOLOPAD_PASSIVE_POWER_USAGE, use_power - HOLOGRAM_POWER_USAGE)//Reduce power usage - if (!masters.len) // If no users left - set_light(0) // pad lighting (hologram lighting will be handled automatically since its owner was deleted) - icon_state = "holopad0" - use_power = HOLOPAD_PASSIVE_POWER_USAGE + SetLightsAndPower() return TRUE -/obj/machinery/holopad/proc/move_hologram(mob/living/silicon/ai/user) +/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf) if(masters[user]) - step_to(masters[user], user.eyeobj) var/obj/effect/overlay/holo_pad_hologram/H = masters[user] - H.loc = get_turf(user.eyeobj) + step_to(H, new_turf) + H.loc = new_turf + var/area/holo_area = get_area(src) + var/area/eye_area = new_turf.loc + + if(!(eye_area in holo_area.related)) + clear_holo(user) return TRUE +/obj/effect/overlay/holo_pad_hologram + var/mob/living/Impersonation + var/datum/holocall/HC + +/obj/effect/overlay/holo_pad_hologram/Destroy() + Impersonation = null + if(HC) + HC.Disconnect(HC.calling_holopad) + return ..() + /obj/effect/overlay/holo_pad_hologram/Process_Spacemove(movement_dir = 0) return 1 +/obj/effect/overlay/holo_pad_hologram/examine(mob/user) + if(Impersonation) + return Impersonation.examine(user) + return ..() + /obj/item/weapon/circuitboard/machine/holopad name = "AI Holopad (Machine Board)" build_path = /obj/machinery/holopad origin_tech = "programming=1" req_components = list(/obj/item/weapon/stock_parts/capacitor = 1) -#undef RANGE_BASED -#undef AREA_BASED #undef HOLOPAD_PASSIVE_POWER_USAGE -#undef HOLOGRAM_POWER_USAGE +#undef HOLOGRAM_POWER_USAGE \ No newline at end of file diff --git a/code/game/machinery/hologram.dm.rej b/code/game/machinery/hologram.dm.rej new file mode 100644 index 0000000000..c1334f9646 --- /dev/null +++ b/code/game/machinery/hologram.dm.rej @@ -0,0 +1,44 @@ +diff a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm (rejected hunks) +@@ -152,7 +152,7 @@ GLOBAL_LIST_EMPTY(holopads) + var/datum/holocall/HC = I + if(HC.connected_holopad == src) + dat += "Disconnect call from [HC.user].
" +- ++ + + var/datum/browser/popup = new(user, "holopad", name, 300, 130) + popup.set_content(dat) +@@ -192,7 +192,7 @@ GLOBAL_LIST_EMPTY(holopads) + if(A) + LAZYADD(callnames[A], I) + callnames -= get_area(src) +- ++ + var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in callnames + if(QDELETED(usr) || !result || outgoing_call) + return +@@ -201,7 +201,7 @@ GLOBAL_LIST_EMPTY(holopads) + temp = "Dialing...
" + temp += "Main Menu" + new /datum/holocall(usr, src, callnames[result]) +- ++ + else if(href_list["connectcall"]) + var/datum/holocall/call_to_connect = locate(href_list["connectcall"]) + if(!QDELETED(call_to_connect)) +@@ -315,12 +315,12 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ + for(var/mob/living/silicon/ai/master in masters) + if(masters[master] && speaker != master) + master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode) +- ++ + for(var/I in holo_calls) + var/datum/holocall/HC = I + if(HC.connected_holopad == src && speaker != HC.hologram) +- HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans) +- ++ HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode) ++ + if(outgoing_call && speaker == outgoing_call.user) + outgoing_call.hologram.say(raw_message) + diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index 6735aa7609..2d3765a934 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -251,6 +251,8 @@ GLOBAL_LIST_INIT(pipeID2State, list( var/mob/living/carbon/C = user for(var/i=1 to 20) C.vomit(0,1,0,4,0) + if(prob(20)) + C.spew_organ() sleep(5) C.blood_volume = 0 return(OXYLOSS|BRUTELOSS) diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index b8ba21fd35..727124276b 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -364,6 +364,10 @@ var/list/targets = list() var/turretview = view(scan_range, base) for(var/A in turretview) + var/atom/AA = A + if(AA.invisibility>SEE_INVISIBLE_LIVING) + continue + if(check_anomalies)//if it's set to check for simple animals if(istype(A, /mob/living/simple_animal)) var/mob/living/simple_animal/SA = A diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 7d02e70671..aad16f7e24 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -56,6 +56,7 @@ var/dish_quants = list() //used by the snack machine's custom compartment to count dishes. var/obj/item/weapon/vending_refill/refill_canister = null //The type of refill canisters used by this machine. + var/refill_count = 3 //The number of canisters the vending machine uses /obj/machinery/vending/Initialize() ..() @@ -88,7 +89,9 @@ /obj/machinery/vending/cola = "Robust Softdrinks", /obj/machinery/vending/cigarette = "ShadyCigs Deluxe", /obj/machinery/vending/autodrobe = "AutoDrobe", - /obj/machinery/vending/clothing = "ClothesMate") + /obj/machinery/vending/clothing = "ClothesMate", + /obj/machinery/vending/medical = "NanoMed Plus", + /obj/machinery/vending/wallmed = "NanoMed") /obj/item/weapon/circuitboard/machine/vendor/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/weapon/screwdriver)) @@ -104,7 +107,7 @@ /obj/item/weapon/circuitboard/machine/vendor/proc/set_type(var/obj/machinery/vending/typepath) build_path = typepath name = "[names_paths[build_path]] Vendor (Machine Board)" - req_components = list(initial(typepath.refill_canister) = 3) + req_components = list(initial(typepath.refill_canister) = initial(typepath.refill_count)) /obj/item/weapon/circuitboard/machine/vendor/apply_default_parts(obj/machinery/M) for(var/typepath in names_paths) @@ -113,7 +116,6 @@ break ..() - /obj/machinery/vending/Destroy() qdel(wires) wires = null @@ -307,7 +309,10 @@ if(panel_open) attack_hand(user) return - else if(istype(W, /obj/item/weapon/coin) && premium.len > 0) + else if(istype(W, /obj/item/weapon/coin)) + if(!premium.len) + to_chat(user, "[src] doesn't have a coin slot.") + return if(!user.drop_item()) return W.loc = src @@ -874,6 +879,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C premium = list(/obj/item/weapon/storage/box/hug/medical = 1,/obj/item/weapon/reagent_containers/hypospray/medipen = 3, /obj/item/weapon/storage/belt/medical = 3, /obj/item/weapon/wrench/medical = 1) armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) resistance_flags = FIRE_PROOF + refill_canister = /obj/item/weapon/vending_refill/medical //This one's from bay12 /obj/machinery/vending/plasmaresearch @@ -896,6 +902,8 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C contraband = list(/obj/item/weapon/reagent_containers/pill/tox = 2,/obj/item/weapon/reagent_containers/pill/morphine = 2) armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50) resistance_flags = FIRE_PROOF + refill_canister = /obj/item/weapon/vending_refill/medical + refill_count = 1 /obj/machinery/vending/security name = "\improper SecTech" diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 7a9d01bb7f..658a6a7692 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -107,7 +107,7 @@ icon_state = "mecha_ion" origin_tech = "materials=4;engineering=4;combat=6;magnets=6" energy_drain = 500 - projectile = /obj/item/projectile/energy/tesla_cannon + projectile = /obj/item/projectile/energy/tesla/cannon fire_sound = 'sound/magic/lightningbolt.ogg' diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 3935b86c92..a6517ccdb5 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -323,11 +323,30 @@ /obj/effect/overlay/temp/ratvar/grille/broken icon_state = "ratvarbrokengrilleglow" +/obj/effect/overlay/temp/ratvar/mending_mantra + layer = ABOVE_MOB_LAYER + duration = 20 + alpha = 200 + icon_state = "mending_mantra" + light_range = 1.5 + light_color = "#1E8CE1" + +/obj/effect/overlay/temp/ratvar/mending_mantra/Initialize(mapload) + . = ..() + transform = matrix()*2 + var/matrix/M = transform + M.Turn(90) + animate(src, alpha = 20, time = duration, easing = BOUNCE_EASING, flags = ANIMATION_PARALLEL) + animate(src, transform = M, time = duration, flags = ANIMATION_PARALLEL) + /obj/effect/overlay/temp/ratvar/volt_hit name = "volt blast" layer = ABOVE_MOB_LAYER duration = 5 icon_state = "volt_hit" + light_range = 1.5 + light_power = 2 + light_color = LIGHT_COLOR_ORANGE var/mob/user var/damage = 20 @@ -336,7 +355,6 @@ damage *= multiplier duration = max(round(damage * 0.2), 1) . = ..() - set_light(1.5, 2, LIGHT_COLOR_ORANGE) /obj/effect/overlay/temp/ratvar/volt_hit/true/Initialize(mapload, caster, multiplier) . = ..() diff --git a/code/game/objects/effects/proximity.dm b/code/game/objects/effects/proximity.dm index 8a6893c887..bfa6cd8fa9 100644 --- a/code/game/objects/effects/proximity.dm +++ b/code/game/objects/effects/proximity.dm @@ -9,10 +9,12 @@ host = _host last_host_loc = _host.loc ignore_if_not_on_turf = _ignore_if_not_on_turf + checkers = list() SetRange(range) /datum/proximity_monitor/Destroy() host = null + last_host_loc = null QDEL_LIST(checkers) return ..() @@ -34,46 +36,47 @@ current_range = range - var/list/old_checkers = checkers - var/old_checkers_len = LAZYLEN(old_checkers) + var/list/checkers_local = checkers + var/old_checkers_len = checkers_local.len - var/atom/host_loc = host.loc + var/atom/_host = host - var/atom/loc_to_use = ignore_if_not_on_turf ? host_loc : get_turf(host) + var/atom/loc_to_use = ignore_if_not_on_turf ? _host.loc : get_turf(_host) if(!isturf(loc_to_use)) //only check the host's loc if(range) var/obj/effect/abstract/proximity_checker/pc if(old_checkers_len) - pc = old_checkers[old_checkers_len] - --old_checkers.len + pc = checkers_local[old_checkers_len] + --checkers_local.len + QDEL_LIST(checkers_local) else - pc = new(host_loc, src) + pc = new(loc_to_use, src) - checkers = list(pc) //only check the host's loc + checkers_local += pc //only check the host's loc return var/list/turfs = RANGE_TURFS(range, loc_to_use) - var/old_checkers_used = min(turfs.len, old_checkers_len) + var/turfs_len = turfs.len + var/old_checkers_used = min(turfs_len, old_checkers_len) //reuse what we can for(var/I in 1 to old_checkers_len) if(I <= old_checkers_used) - var/obj/effect/abstract/proximity_checker/pc = old_checkers[I] + var/obj/effect/abstract/proximity_checker/pc = checkers_local[I] pc.loc = turfs[I] else - qdel(old_checkers[I]) //delete the leftovers + qdel(checkers_local[I]) //delete the leftovers - LAZYCLEARLIST(old_checkers) - - //create what we lack - var/list/checkers_local = list() - for(var/I in (old_checkers_used + 1) to turfs.len) - checkers_local += new /obj/effect/abstract/proximity_checker(turfs[I], src) - - checkers = checkers_local + if(old_checkers_len < turfs_len) + //create what we lack + for(var/I in (old_checkers_used + 1) to turfs_len) + checkers_local += new /obj/effect/abstract/proximity_checker(turfs[I], src) + else + checkers_local.Cut(old_checkers_used + 1, old_checkers_len) /obj/effect/abstract/proximity_checker invisibility = INVISIBILITY_ABSTRACT + anchored = TRUE var/datum/proximity_monitor/monitor /obj/effect/abstract/proximity_checker/Initialize(mapload, datum/proximity_monitor/_monitor) @@ -81,8 +84,8 @@ if(_monitor) monitor = _monitor else - stack_trace("proximity_checker created without proximity_monitor") - qdel(src) + stack_trace("proximity_checker created without host") + return INITIALIZE_HINT_QDEL /obj/effect/abstract/proximity_checker/Destroy() monitor = null @@ -90,9 +93,6 @@ /obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM) set waitfor = FALSE - var/datum/proximity_monitor/M = monitor - if(!M.current_range) - return - var/atom/H = M.host + var/atom/H = monitor.host testing("HasProx: [H] -> [AM]") H.HasProximity(AM) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 6955872c27..9131c02240 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -37,9 +37,9 @@ return 1 -/obj/item/device/flashlight/attack(mob/living/carbon/human/M, mob/living/carbon/human/user) +/obj/item/device/flashlight/attack(mob/living/carbon/M, mob/living/carbon/human/user) add_fingerprint(user) - if(on && user.zone_selected == "eyes") + if(istype(M) && on && user.zone_selected in list("eyes", "mouth")) if((user.disabilities & CLUMSY || user.getBrainLoss() >= 60) && prob(50)) //too dumb to use flashlight properly return ..() //just hit them in the head @@ -48,28 +48,101 @@ to_chat(user, "You don't have the dexterity to do this!") return - var/mob/living/carbon/human/H = M //mob has protective eyewear - if(ishuman(M) && ((H.head && H.head.flags_cover & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) || (H.glasses && H.glasses.flags_cover & GLASSESCOVERSEYES))) - to_chat(user, "You're going to need to remove that [(H.head && H.head.flags_cover & HEADCOVERSEYES) ? "helmet" : (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) ? "mask": "glasses"] first.") + if(!M.get_bodypart("head")) + to_chat(user, "[M] doesn't have a head!") return - if(M == user) //they're using it on themselves - if(M.flash_act(visual = 1)) - M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "You wave the light in front of your eyes! Trippy!") - else - M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "You wave the light in front of your eyes.") - else - user.visible_message("[user] directs [src] to [M]'s eyes.", \ - "You direct [src] to [M]'s eyes.") - var/mob/living/carbon/C = M - if(istype(C)) - if(C.stat == DEAD || (C.disabilities & BLIND)) //mob is dead or fully blind - to_chat(user, "[C] pupils don't react to the light!") - else if(C.dna.check_mutation(XRAY)) //mob has X-RAY vision - to_chat(user, "[C] pupils give an eerie glow!") - else //they're okay! - if(C.flash_act(visual = 1)) - to_chat(user, "[C]'s pupils narrow.") + switch(user.zone_selected) + if("eyes") + if((M.head && M.head.flags_cover & HEADCOVERSEYES) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) || (M.glasses && M.glasses.flags_cover & GLASSESCOVERSEYES)) + to_chat(user, "You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSEYES) ? "helmet" : (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) ? "mask": "glasses"] first.") + return + + var/obj/item/organ/eyes/E = M.getorganslot("eye_sight") + if(!E) + to_chat(user, "[M] doesn't have any eyes!") + return + + if(M == user) //they're using it on themselves + if(M.flash_act(visual = 1)) + M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "You wave the light in front of your eyes! Trippy!") + else + M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "You wave the light in front of your eyes.") + else + user.visible_message("[user] directs [src] to [M]'s eyes.", \ + "You direct [src] to [M]'s eyes.") + if(M.stat == DEAD || (M.disabilities & BLIND) || !M.flash_act(visual = 1)) //mob is dead or fully blind + to_chat(user, "[M]'s pupils don't react to the light!") + else if(M.dna && M.dna.check_mutation(XRAY)) //mob has X-RAY vision + to_chat(user, "[M]'s pupils give an eerie glow!") + else //they're okay! + to_chat(user, "[M]'s pupils narrow.") + + if("mouth") + + if((M.head && M.head.flags_cover & HEADCOVERSMOUTH) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH)) + to_chat(user, "You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSMOUTH) ? "helmet" : "mask"] first.") + return + + var/their = M.p_their() + + var/list/mouth_organs = new + for(var/obj/item/organ/O in M.internal_organs) + if(O.zone == "mouth") + mouth_organs.Add(O) + var/organ_list = "" + var/organ_count = LAZYLEN(mouth_organs) + if(organ_count) + for(var/I in 1 to organ_count) + if(I > 1) + if(I == mouth_organs.len) + organ_list += ", and " + else + organ_list += ", " + var/obj/item/organ/O = mouth_organs[I] + organ_list += (O.gender == "plural" ? O.name : "\an [O.name]") + + var/pill_count = 0 + for(var/datum/action/item_action/hands_free/activate_pill/AP in M.actions) + pill_count++ + + if(M == user) + var/can_use_mirror = FALSE + if(isturf(user.loc)) + var/obj/structure/mirror/mirror = locate(/obj/structure/mirror, user.loc) + if(mirror) + switch(user.dir) + if(NORTH) + can_use_mirror = mirror.pixel_y > 0 + if(SOUTH) + can_use_mirror = mirror.pixel_y < 0 + if(EAST) + can_use_mirror = mirror.pixel_x > 0 + if(WEST) + can_use_mirror = mirror.pixel_x < 0 + + M.visible_message("[M] directs [src] to [their] mouth.", \ + "You point [src] into your mouth.") + if(!can_use_mirror) + to_chat(user, "You can't see anything without a mirror.") + return + if(organ_count) + to_chat(user, "Inside your mouth [organ_count > 1 ? "are" : "is"] [organ_list].") + else + to_chat(user, "There's nothing inside your mouth.") + if(pill_count) + to_chat(user, "You have [pill_count] implanted pill[pill_count > 1 ? "s" : ""].") + + else + user.visible_message("[user] directs [src] to [M]'s mouth.",\ + "You direct [src] to [M]'s mouth.") + if(organ_count) + to_chat(user, "Inside [their] mouth [organ_count > 1 ? "are" : "is"] [organ_list].") + else + to_chat(user, "[M] doesn't have any organs in [their] mouth.") + if(pill_count) + to_chat(user, "[M] has [pill_count] pill[pill_count > 1 ? "s" : ""] implanted in [their] teeth.") + else return ..() @@ -280,7 +353,7 @@ return TRUE /obj/item/device/flashlight/emp/attack(mob/living/M, mob/living/user) - if(on && user.zone_selected == "eyes") // call original attack proc only if aiming at the eyes + if(on && user.zone_selected in list("eyes", "mouth")) // call original attack when examining organs ..() return diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 2aee5acdd9..29463b5a5c 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -237,6 +237,7 @@ /obj/item/borg/upgrade/selfrepair/proc/check_dropped() if(loc != cyborg) toggle_action.Remove(cyborg) + QDEL_NULL(toggle_action) cyborg = null deactivate() @@ -399,4 +400,4 @@ return R.make_shell(src) - return TRUE \ No newline at end of file + return TRUE diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index 611ef76eb4..f32fc2cea4 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -29,6 +29,7 @@ Mineral Sheets GLOBAL_LIST_INIT(sandstone_recipes, list ( \ new/datum/stack_recipe("pile of dirt", /obj/machinery/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("sandstone door", /obj/structure/mineral_door/sandstone, 10, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("aesthetic volcanic floor tile", /obj/item/stack/tile/basalt, 2, 2, 4, 20), \ new/datum/stack_recipe("Assistant Statue", /obj/structure/statue/sandstone/assistant, 5, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("Breakdown into sand", /obj/item/weapon/ore/glass, 1, one_per_turf = 0, on_floor = 1), \ /* new/datum/stack_recipe("sandstone wall", ???), \ diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index f2432cee3d..1737699e5b 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -88,6 +88,14 @@ turf_type = /turf/open/floor/wood resistance_flags = FLAMMABLE +//Basalt +/obj/item/stack/tile/basalt + name = "basalt tile" + singular_name = "basalt floor tile" + desc = "Artificially made ashy soil themed on a hostile enviroment." + icon_state = "tile_basalt" + origin_tech = "materials=1" + turf_type = /turf/open/floor/grass/fakebasalt //Carpets /obj/item/stack/tile/carpet diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm index 2d5c4707a6..86c01d745e 100644 --- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -1,5 +1,5 @@ /obj/item/weapon/grenade/spawnergrenade - desc = "It will unleash unleash an unspecified anomaly into the vicinity." + desc = "It will unleash an unspecified anomaly into the vicinity." name = "delivery grenade" icon = 'icons/obj/grenade.dmi' icon_state = "delivery" diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index 335545e8c9..9cf806f6b3 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -219,7 +219,8 @@ new /obj/item/weapon/reagent_containers/glass/bottle/polonium(src) new /obj/item/weapon/reagent_containers/glass/bottle/venom(src) new /obj/item/weapon/reagent_containers/glass/bottle/neurotoxin2(src) - new /obj/item/weapon/reagent_containers/glass/bottle/formaldehyde(src) + new /obj/item/weapon/reagent_containers/glass/bottle/formaldehyde(src) + new /obj/item/weapon/reagent_containers/glass/bottle/spewium(src) new /obj/item/weapon/reagent_containers/glass/bottle/cyanide(src) new /obj/item/weapon/reagent_containers/glass/bottle/histamine(src) new /obj/item/weapon/reagent_containers/glass/bottle/initropidril(src) diff --git a/code/game/objects/items/weapons/vending_items.dm b/code/game/objects/items/weapons/vending_items.dm index 74ab7be4b6..c93dcaca3b 100644 --- a/code/game/objects/items/weapons/vending_items.dm +++ b/code/game/objects/items/weapons/vending_items.dm @@ -71,3 +71,9 @@ icon_state = "refill_clothes" charges = list(31, 4, 4)// of 101 standard, 12 contraband, 10 premium(?) init_charges = list(31, 4, 4) + +/obj/item/weapon/vending_refill/medical + machine_name = "NanoMed" + icon_state = "refill_medical" + charges = list(26, 5, 3)// of 76 standard, 13 contraband, 8 premium + init_charges = list(26, 5, 3) \ No newline at end of file diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index d46136a9ae..6212133b12 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -298,7 +298,7 @@ else for(var/mob/M in range(1,src)) if(CanHug(M)) - child.Attach(M) + child.Leap(M) break /obj/structure/alien/egg/obj_break(damage_flag) diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index be1b49074d..3817a16685 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -16,27 +16,25 @@ var/obj/item/weapon/electronics/airlock/electronics var/start_showpiece_type = null //add type for items on display -/obj/structure/displaycase/New() - ..() +/obj/structure/displaycase/Initialize() + . = ..() if(start_showpiece_type) showpiece = new start_showpiece_type (src) update_icon() /obj/structure/displaycase/Destroy() if(electronics) - qdel(electronics) - electronics = null + QDEL_NULL(electronics) if(showpiece) - qdel(showpiece) - showpiece = null + QDEL_NULL(showpiece) return ..() /obj/structure/displaycase/examine(mob/user) ..() - if(showpiece) - to_chat(user, "There's [showpiece] inside.") if(alert) to_chat(user, "Hooked up with an anti-theft system.") + if(showpiece) + to_chat(user, "There's [showpiece] inside.") /obj/structure/displaycase/proc/dump() @@ -176,8 +174,8 @@ /obj/structure/displaycase/attack_hand(mob/user) user.changeNext_move(CLICK_CD_MELEE) if (showpiece && (broken || open)) - dump() to_chat(user, "You deactivate the hover field built into the case.") + dump() src.add_fingerprint(user) update_icon() return @@ -249,3 +247,96 @@ desc = "A glass lab container for storing interesting creatures." start_showpiece_type = /obj/item/clothing/mask/facehugger/lamarr req_access = list(GLOB.access_rd) + + + +/obj/structure/displaycase/trophy + name = "trophy display case" + desc = "Store your trophies of accomplishment in here, and they will stay forever." + var/trophy_message = "" + var/placer_key = "" + var/added_roundstart = TRUE + alert = TRUE + integrity_failure = 0 + +/obj/structure/displaycase/trophy/Initialize() + . = ..() + GLOB.trophy_cases += src + +/obj/structure/displaycase/trophy/Destroy() + GLOB.trophy_cases -= src + return ..() + +/obj/structure/displaycase/trophy/examine(mob/user) + ..() + if(trophy_message) + to_chat(user, "The plaque reads:") + to_chat(user, trophy_message) + +/obj/structure/displaycase/trophy/attackby(obj/item/weapon/W, mob/user, params) + + if(!user.Adjacent(src)) //no TK museology + return + + if(!added_roundstart) + to_chat(user, "You've already put something new in this case.") + return + + if(is_type_in_typecache(W, GLOB.blacklisted_cargo_types)) + to_chat(user, "The case rejects the [W].") + return + + for(var/a in W.GetAllContents()) + if(is_type_in_typecache(a, GLOB.blacklisted_cargo_types)) + to_chat(user, "The case rejects the [W].") + return + + if(user.drop_item()) + + if(showpiece) + to_chat(user, "You press a button, and [showpiece] descends into the floor of the case.") + QDEL_NULL(showpiece) + + to_chat(user, "You insert [W] into the case.") + W.forceMove(src) + showpiece = W + added_roundstart = FALSE + update_icon() + + placer_key = user.ckey + + trophy_message = W.desc //default value + + var/chosen_plaque = stripped_input(user, "What would you like the plaque to say? Default value is item's description.", "Trophy Plaque") + if(chosen_plaque) + if(user.Adjacent(src)) + trophy_message = chosen_plaque + to_chat(user, "You set the plaque's text.") + else + to_chat(user, "You are too far to set the plaque's text.") + + SSpersistence.SaveTrophy(src) + + else + to_chat(user, "\The [W] is stuck to your hand, you can't put it in the [src.name]!") + + return + +/obj/structure/displaycase/trophy/dump() + if (showpiece) + if(added_roundstart) + visible_message("The [showpiece] crumbles to dust!") + new /obj/effect/decal/cleanable/ash(loc) + QDEL_NULL(showpiece) + else + ..() + +/obj/item/showpiece_dummy + name = "Cheap replica" + +/obj/item/showpiece_dummy/Initialize(mapload, path) + . = ..() + var/obj/item/I = path + name = initial(I.name) + icon = initial(I.icon) + icon_state = initial(I.icon_state) diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index cdd706e5df..c00348a2c6 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -88,7 +88,7 @@ pixel_y = -20 /obj/structure/flora/tree/jungle/Initialize() - icon_state = "[icon_state][rand(1, 3)]" + icon_state = "[icon_state][rand(1, 6)]" ..() //grass diff --git a/code/game/say.dm b/code/game/say.dm index deab83ad10..4bcc289be1 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -35,10 +35,10 @@ GLOBAL_LIST_INIT(freqtospan, list( return 1 /atom/movable/proc/send_speech(message, range = 7, obj/source = src, bubble_type, list/spans, datum/language/message_language = null, message_mode) - var/rendered = compose_message(src, message_language, message, , spans) + var/rendered = compose_message(src, message_language, message, , spans, message_mode) for(var/_AM in get_hearers_in_view(range, source)) var/atom/movable/AM = _AM - AM.Hear(rendered, src, message_language, message, , spans) + AM.Hear(rendered, src, message_language, message, , spans, message_mode) //To get robot span classes, stuff like that. /atom/movable/proc/get_spans() @@ -58,7 +58,7 @@ GLOBAL_LIST_INIT(freqtospan, list( var/endspanpart = "" //Message - var/messagepart = " [lang_treat(speaker, message_language, raw_message, spans)]" + var/messagepart = " [lang_treat(speaker, message_language, raw_message, spans, message_mode)]" var/languageicon = "" var/datum/language/D = get_language_instance(message_language) diff --git a/code/game/turfs/simulated/chasm.dm b/code/game/turfs/simulated/chasm.dm index 8890c50129..8b24a4c816 100644 --- a/code/game/turfs/simulated/chasm.dm +++ b/code/game/turfs/simulated/chasm.dm @@ -143,14 +143,14 @@ qdel(S.mmi) qdel(AM) - + if(AM && !QDELETED(AM)) //It's indestructible visible_message("[src] spits out the [AM]!") AM.alpha = oldalpha AM.color = oldcolor AM.transform = oldtransform AM.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1, 10),rand(1, 10)) - + /turf/open/chasm/straight_down/lava_land_surface/normal_air initial_gas_mix = "o2=22;n2=82;TEMP=293.15" @@ -158,3 +158,17 @@ /turf/open/chasm/CanPass(atom/movable/mover, turf/target, height=0) return 1 + + + +//Jungle + +/turf/open/chasm/jungle + icon = 'icons/turf/floors/junglechasm.dmi' + planetary_atmos = TRUE + initial_gas_mix = "o2=14;n2=23;TEMP=300" + +/turf/open/chasm/straight_down/jungle + icon = 'icons/turf/floors/junglechasm.dmi' + planetary_atmos = TRUE + initial_gas_mix = "o2=14;n2=23;TEMP=300" \ No newline at end of file diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index eaba3d50eb..cce7756892 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -1,6 +1,7 @@ /* In this file: * Wood floor * Grass floor + * Fake Basalt * Carpet floor * Fake pits * Fake space @@ -67,6 +68,7 @@ broken_states = list("sand") flags = NONE var/ore_type = /obj/item/weapon/ore/glass + var/turfverb = "uproot" /turf/open/floor/grass/Initialize() ..() @@ -76,7 +78,7 @@ if(istype(C, /obj/item/weapon/shovel) && params) new ore_type(src) new ore_type(src) //Make some sand if you shovel grass - user.visible_message("[user] digs up [src].", "You uproot [src].") + user.visible_message("[user] digs up [src].", "You [src.turfverb] [src].") playsound(src, 'sound/effects/shovel_dig.ogg', 50, 1) make_plating() if(..()) @@ -93,7 +95,6 @@ initial_gas_mix = "o2=22;n2=82;TEMP=180" slowdown = 2 - /turf/open/floor/grass/snow/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/weapon/crowbar))//You need to dig this turf out instead of crowbarring it return @@ -113,6 +114,24 @@ icon_state = "basalt[rand(0, 12)]" set_basalt_light(src) + +/turf/open/floor/grass/fakebasalt //Heart is not a real planeteer power + name = "aesthetic volcanic flooring" + desc = "Safely recreated turf for your hellplanet-scaping" + icon = 'icons/turf/floors.dmi' + icon_state = "basalt" + floor_tile = /obj/item/stack/tile/basalt + ore_type = /obj/item/weapon/ore/glass/basalt + turfverb = "dig up" + slowdown = 0 + +/turf/open/floor/grass/fakebasalt/Initialize() + ..() + if(prob(15)) + icon_state = "basalt[rand(0, 12)]" + set_basalt_light(src) + + /turf/open/floor/carpet name = "carpet" desc = "Soft velvet carpeting. Feels good between your toes." diff --git a/code/game/turfs/simulated/floor/plating/dirt.dm b/code/game/turfs/simulated/floor/plating/dirt.dm index 580aadc85f..0d13b93432 100644 --- a/code/game/turfs/simulated/floor/plating/dirt.dm +++ b/code/game/turfs/simulated/floor/plating/dirt.dm @@ -3,19 +3,9 @@ desc = "Upon closer examination, it's still dirt." icon = 'icons/turf/floors.dmi' icon_state = "dirt" - var/smooth_icon = 'icons/turf/floors/dirt.dmi' - canSmoothWith = list(/turf/closed, /turf/open/floor/plating/dirt) - smooth = SMOOTH_MORE|SMOOTH_BORDER - baseturf = /turf/open/chasm/straight_down/lava_land_surface + baseturf = /turf/open/chasm/straight_down/jungle initial_gas_mix = "o2=14;n2=23;TEMP=300" planetary_atmos = TRUE -/turf/open/floor/plating/dirt/Initialize() - pixel_y = -2 - pixel_x = -2 - icon = smooth_icon - ..() - /turf/open/floor/plating/dirt/dark - icon_state = "darkdirt" - smooth_icon = 'icons/turf/floors/darkdirt.dmi' + icon_state = "greenerdirt" diff --git a/code/modules/admin/topic.dm.rej b/code/modules/admin/topic.dm.rej deleted file mode 100644 index 041ae92107..0000000000 --- a/code/modules/admin/topic.dm.rej +++ /dev/null @@ -1,10 +0,0 @@ -diff a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm (rejected hunks) -@@ -8,7 +8,7 @@ - if(href_list["ahelp"]) - if(!check_rights(R_ADMIN)) - return -- -+ - var/ahelp_ref = href_list["ahelp"] - var/datum/admin_help/AH = locate(ahelp_ref) - if(AH) diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index b8df3c147d..6b642d4fdd 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -485,10 +485,6 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) current_ticket.AddInteraction("[key_name_admin(usr)] opened a new ticket.") current_ticket.Close() - if(!(/client/verb/adminhelp in verbs)) - to_chat(usr, "Nice try!") - return - new /datum/admin_help(msg, src, FALSE) //admin proc diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm index 37af9e8601..500edfe665 100644 --- a/code/modules/admin/verbs/deadsay.dm +++ b/code/modules/admin/verbs/deadsay.dm @@ -19,7 +19,7 @@ if (!msg) return - var/nicknames = world.file2list("config/admin_nicknames.txt") + var/static/nicknames = world.file2list("config/admin_nicknames.txt") var/rendered = "DEAD: ADMIN([src.holder.fakekey ? pick(nicknames) : src.key]) says, \"[msg]\"" diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index f417dfbad3..2397f6c4a5 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -21,7 +21,7 @@ var/res = alert(usr, "Show the title of this song to the players?",, "No", "Yes", "Cancel") switch(res) if("Yes") - to_chat(world, "An admin played: [S]") + to_chat(world, "An admin played: [S]") if("Cancel") return diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 547e8e1d03..f1bf4d6969 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -350,7 +350,6 @@ Traitors and the like can also be revived with the previous role mostly intact. if(G_found.mind && !G_found.mind.active) G_found.mind.transfer_to(new_character) //be careful when doing stuff like this! I've already checked the mind isn't in use - new_character.mind.special_verbs = list() else new_character.mind_initialize() if(!new_character.mind.assigned_role) diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index b7c7a7e377..5d9f29a374 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -828,6 +828,14 @@ /obj/item/weapon/defibrillator/loaded) crate_name = "defibrillator crate" +/datum/supply_pack/medical/vending + name = "Medical Vending Crate" + cost = 2000 + contains = list(/obj/item/weapon/vending_refill/medical, + /obj/item/weapon/vending_refill/medical, + /obj/item/weapon/vending_refill/medical) + crate_name = "medical vending crate" + ////////////////////////////////////////////////////////////////////////////// //////////////////////////// Science ///////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// diff --git a/code/modules/client/verbs/suicide.dm b/code/modules/client/verbs/suicide.dm index 6847a7c1f4..1f50a697c2 100644 --- a/code/modules/client/verbs/suicide.dm +++ b/code/modules/client/verbs/suicide.dm @@ -13,8 +13,8 @@ return if(confirm == "Yes") suiciding = 1 - log_game("[key_name(src)] (job: [job ? "[job]" : "None"]) commited suicide at [get_area(src)].") - message_admins("[key_name(src)] (job: [job ? "[job]" : "None"]) commited suicide at [get_area(src)].") + log_game("[key_name(src)] (job: [job ? "[job]" : "None"]) committed suicide at [get_area(src)].") + message_admins("[key_name(src)] (job: [job ? "[job]" : "None"]) committed suicide at [get_area(src)].") var/obj/item/held_item = get_active_held_item() if(held_item) var/damagetype = held_item.suicide_act(src) diff --git a/code/modules/clothing/spacesuits/flightsuit.dm b/code/modules/clothing/spacesuits/flightsuit.dm index 275ad542b5..479ad77742 100644 --- a/code/modules/clothing/spacesuits/flightsuit.dm +++ b/code/modules/clothing/spacesuits/flightsuit.dm @@ -326,9 +326,6 @@ disable_flight(1) if(!suit) disable_flight(1) - if(!resync) - addtimer(CALLBACK(src, .proc/resync), 600) - resync = 1 if(!wearer) //Oh god our user fell off! disable_flight(1) if(!pressure && brake) @@ -340,12 +337,6 @@ stabilizer = FALSE usermessage("Warning: Sensor data is not being recieved from flight shoes. Stabilizers and airbrake modules OFFLINE!", 2) -//Resync the suit -/obj/item/device/flightpack/proc/resync() - resync = FALSE - suit.resync() - -//How fast should the wearer be? /obj/item/device/flightpack/proc/update_slowdown() if(!flight) suit.slowdown = slowdown_ground @@ -356,20 +347,11 @@ /obj/item/device/flightpack/process() if(!suit || (processing_mode == FLIGHTSUIT_PROCESSING_NONE)) return FALSE - update_slowdown() - update_icon() check_conditions() calculate_momentum_speed() momentum_drift() handle_boost() handle_damage() - handle_flight() - -/obj/item/device/flightpack/proc/handle_flight() - if(!flight) - return FALSE - if(wearer) - wearer.float(TRUE) /obj/item/device/flightpack/proc/handle_damage() if(crash_damage) @@ -424,7 +406,6 @@ if(boost_charge < boost_maxcharge) boost_charge = Clamp(boost_charge+boost_chargerate, 0, boost_maxcharge) - /obj/item/device/flightpack/proc/cycle_power() if(powersetting < powersetting_high) powersetting++ @@ -654,6 +635,8 @@ wearer.movement_type |= FLYING wearer.pass_flags |= flight_passflags usermessage("ENGAGING FLIGHT ENGINES.") + update_slowdown() + wearer.floating = TRUE wearer.visible_message("[wearer]'s flight engines activate as they lift into the air!") //I DONT HAVE SOUND EFFECTS YET playsound( flight = TRUE @@ -670,6 +653,8 @@ momentum_x = 0 momentum_y = 0 usermessage("DISENGAGING FLIGHT ENGINES.") + update_slowdown() + wearer.floating = FALSE wearer.visible_message("[wearer] drops to the ground as their flight engines cut out!") //NO SOUND YET playsound( ion_trail.stop() @@ -749,11 +734,13 @@ wearer.visible_message("[wearer.name]'s flightpack engines flare in intensity as they are rocketed forward by the immense thrust!") boost = TRUE update_slowdown() + update_icon() /obj/item/device/flightpack/proc/deactivate_booster() usermessage("Boosters disengaged!") boost = FALSE update_slowdown() + update_icon() /obj/item/device/flightpack/proc/enable_airbrake() if(wearer) diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm index 92437a34c1..562f59290a 100644 --- a/code/modules/detectivework/scanner.dm +++ b/code/modules/detectivework/scanner.dm @@ -13,6 +13,8 @@ var/scanning = 0 var/list/log = list() origin_tech = "engineering=4;biotech=2;programming=5" + var/range = 8 + var/view_check = TRUE /obj/item/device/detective_scanner/attack_self(mob/user) if(log.len && !scanning) @@ -43,7 +45,7 @@ log = list() scanning = 0 -/obj/item/device/detective_scanner/pre_attackby(atom/A, mob/user, params) +/obj/item/device/detective_scanner/afterattack(atom/A, mob/user, params) scan(A, user) return FALSE @@ -51,9 +53,7 @@ set waitfor = 0 if(!scanning) // Can remotely scan objects and mobs. - if(!in_range(A, user) && !(A in view(world.view, user))) - return - if(loc != user) + if((get_dist(A, user) > range) || (!(A in view(range, user)) && view_check) || (loc != user)) return scanning = 1 diff --git a/code/modules/food_and_drinks/food/snacks_pastry.dm b/code/modules/food_and_drinks/food/snacks_pastry.dm index 76ef327bb6..6081838669 100644 --- a/code/modules/food_and_drinks/food/snacks_pastry.dm +++ b/code/modules/food_and_drinks/food/snacks_pastry.dm @@ -13,8 +13,8 @@ filling_color = "#D2691E" tastes = list("donut" = 1) -/obj/item/weapon/reagent_containers/food/snacks/donut/New() - ..() +/obj/item/weapon/reagent_containers/food/snacks/donut/Initialize() + . = ..() if(prob(30)) icon_state = "donut2" name = "frosted donut" @@ -28,8 +28,8 @@ bitesize = 10 tastes = list("donut" = 3, "chaos" = 1) -/obj/item/weapon/reagent_containers/food/snacks/donut/chaos/New() - ..() +/obj/item/weapon/reagent_containers/food/snacks/donut/chaos/Initialize() + . = ..() extra_reagent = pick("nutriment", "capsaicin", "frostoil", "krokodil", "plasma", "cocoa", "slimejelly", "banana", "berryjuice", "omnizine") reagents.add_reagent("[extra_reagent]", 3) bonus_reagents = list("[extra_reagent]" = 3, "sugar" = 1) @@ -48,8 +48,8 @@ extra_reagent = "berryjuice" tastes = list("jelly" = 1, "donut" = 3) -/obj/item/weapon/reagent_containers/food/snacks/donut/jelly/New() - ..() +/obj/item/weapon/reagent_containers/food/snacks/donut/jelly/Initialize() + . = ..() if(extra_reagent) reagents.add_reagent("[extra_reagent]", 3) if(prob(30)) @@ -210,13 +210,13 @@ filling_color = "#F0E68C" tastes = list("mushroom" = 1, "biscuit" = 1) -/obj/item/weapon/reagent_containers/food/snacks/plumphelmetbiscuit/New() +/obj/item/weapon/reagent_containers/food/snacks/plumphelmetbiscuit/Initialize() var/fey = prob(10) if(fey) name = "exceptional plump helmet biscuit" desc = "Microwave is taken by a fey mood! It has cooked an exceptional plump helmet biscuit!" bonus_reagents = list("omnizine" = 5, "nutriment" = 1, "vitamin" = 1) - ..() + . = ..() if(fey) reagents.add_reagent("omnizine", 5) diff --git a/code/modules/food_and_drinks/food/snacks_soup.dm b/code/modules/food_and_drinks/food/snacks_soup.dm index 79df428ebb..e11231fdfc 100644 --- a/code/modules/food_and_drinks/food/snacks_soup.dm +++ b/code/modules/food_and_drinks/food/snacks_soup.dm @@ -128,6 +128,13 @@ list_reagents = list("nutriment" = 5, "tomatojuice" = 10, "vitamin" = 3) tastes = list("tomato" = 1) +/obj/item/weapon/reagent_containers/food/snacks/soup/tomato/eyeball + name = "eyeball soup" + desc = "It looks back at you..." + icon_state = "eyeballsoup" + bonus_reagents = list("nutriment" = 1, "liquidgibs" = 3) + tastes = list("tomato" = 1, "squirming" = 1) + /obj/item/weapon/reagent_containers/food/snacks/soup/milo name = "milosoup" desc = "The universes best soup! Yum!!!" @@ -196,5 +203,3 @@ icon_state = "redbeetsoup" bonus_reagents = list("nutriment" = 4, "vitamin" = 6) tastes = list("beet" = 1) - - diff --git a/code/modules/food_and_drinks/food/snacks_spaghetti.dm b/code/modules/food_and_drinks/food/snacks_spaghetti.dm index fd17c0ebd5..dc3aa60115 100644 --- a/code/modules/food_and_drinks/food/snacks_spaghetti.dm +++ b/code/modules/food_and_drinks/food/snacks_spaghetti.dm @@ -83,5 +83,5 @@ icon = 'icons/obj/food/pizzaspaghetti.dmi' icon_state = "beefnoodle" trash = /obj/item/weapon/reagent_containers/glass/bowl - bonus_reagents = list("nutriment" = 5, "vitamin" = 6) + bonus_reagents = list("nutriment" = 5, "vitamin" = 6, "liquidgibs" = 3) tastes = list("noodle" = 1, "meat" = 1) diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm index 6d14d13254..fff76d630f 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm @@ -264,7 +264,7 @@ time = 40 reqs = list( /obj/item/weapon/reagent_containers/food/snacks/meat/steak/goliath = 1, - /obj/item/weapon/legion_skull = 1, + /obj/item/organ/hivelord_core/legion = 1, /datum/reagent/consumable/ketchup = 2, /datum/reagent/consumable/capsaicin = 2 ) @@ -325,3 +325,5 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/branrequests category = CAT_MISCFOOD + + diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm index 050beb8478..8ab865f65d 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_soup.dm @@ -91,6 +91,18 @@ result = /obj/item/weapon/reagent_containers/food/snacks/soup/tomato category = CAT_SOUP +/datum/crafting_recipe/food/eyeballsoup + name = "Eyeball soup" + reqs = list( + /datum/reagent/water = 10, + /obj/item/weapon/reagent_containers/glass/bowl = 1, + /obj/item/weapon/reagent_containers/food/snacks/grown/tomato = 2, + /obj/item/organ/eyes = 1 + ) + result = /obj/item/weapon/reagent_containers/food/snacks/soup/tomato/eyeball + category = CAT_SOUP + + /datum/crafting_recipe/food/milosoup name = "Milo soup" reqs = list( diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 555df764b8..5104ab333a 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -111,6 +111,7 @@ for(var/datum/plant_gene/trait/trait in seed.genes) trait.on_squash(src, target) + reagents.reaction(T) for(var/A in T) reagents.reaction(A) diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index d93bcb5028..f3b66d9172 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -84,7 +84,7 @@ if(D.make_reagents.len) return 0 - var/build_amount = 1 + var/build_amount = 0 for(var/mat_id in D.materials) var/M = D.materials[mat_id] @@ -93,7 +93,15 @@ if(!M || !redemption_mat) return 0 - build_amount = min(build_amount, round(redemption_mat.amount / M)) + var/smeltable_sheets = round(redemption_mat.amount / M) + + if(!smeltable_sheets) + return 0 + + if(!build_amount) + build_amount = smeltable_sheets + + build_amount = min(build_amount, smeltable_sheets) return build_amount @@ -152,6 +160,7 @@ if(exchange_parts(user, W)) return if(default_pry_open(W)) + materials.retrieve_all() return if(default_unfasten_wrench(user, W)) return diff --git a/code/modules/mob/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm index 8675049cee..0e7f5fcc1e 100644 --- a/code/modules/mob/dead/observer/say.dm +++ b/code/modules/mob/dead/observer/say.dm @@ -20,6 +20,6 @@ to_follow = V.source var/link = FOLLOW_LINK(src, to_follow) // Recompose the message, because it's scrambled by default - message = compose_message(speaker, message_language, raw_message, radio_freq, spans) + message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode) to_chat(src, "[link] [message]") diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index ca380170f7..ca8b8f2d9d 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -35,22 +35,21 @@ blood_volume += 0.1 // regenerate blood VERY slowly //Effects of bloodloss + var/word = pick("dizzy","woozy","faint") switch(blood_volume) if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE) if(prob(5)) - to_chat(src, "You feel [pick("dizzy","woozy","faint")].") + to_chat(src, "You feel [word].") adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1)) if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY) adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1)) if(prob(5)) blur_eyes(6) - var/word = pick("dizzy","woozy","faint") to_chat(src, "You feel very [word].") if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) adjustOxyLoss(5) if(prob(15)) Paralyse(rand(1,3)) - var/word = pick("dizzy","woozy","faint") to_chat(src, "You feel extremely [word].") if(0 to BLOOD_VOLUME_SURVIVE) death() @@ -70,7 +69,7 @@ bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases - if(bleed_rate && !bleedsuppress) + if(bleed_rate && !bleedsuppress && !(status_flags & FAKEDEATH)) bleed(bleed_rate) //Makes a blood drop, leaking amt units of blood from the mob diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm index 8a9ee012d9..f9bd64153e 100644 --- a/code/modules/mob/living/carbon/alien/organs.dm +++ b/code/modules/mob/living/carbon/alien/organs.dm @@ -87,6 +87,8 @@ owner.adjustFireLoss(-heal_amt) owner.adjustOxyLoss(-heal_amt) owner.adjustCloneLoss(-heal_amt) + else + owner.adjustPlasma(plasma_rate * 0.1) /obj/item/organ/alien/plasmavessel/Insert(mob/living/carbon/M, special = 0) ..() diff --git a/code/modules/mob/living/carbon/alien/say.dm b/code/modules/mob/living/carbon/alien/say.dm index 72162387ee..12c131b3cc 100644 --- a/code/modules/mob/living/carbon/alien/say.dm +++ b/code/modules/mob/living/carbon/alien/say.dm @@ -1,4 +1,4 @@ -/mob/living/proc/alien_talk(message, shown_name = name) +/mob/living/proc/alien_talk(message, shown_name = real_name) log_say("[key_name(src)] : [message]") message = trim(message) if(!message) return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 87cf246717..06145235a0 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -484,7 +484,7 @@ adjustBruteLoss(3) else if(T) - T.add_vomit_floor(src, 0)//toxic barf looks different + T.add_vomit_floor(src, toxic)//toxic barf looks different nutrition -= lost_nutrition adjustToxLoss(-3) T = get_step(T, dir) @@ -492,6 +492,16 @@ break return 1 +/mob/living/carbon/proc/spew_organ(power = 5) + if(!internal_organs.len) + return //Guess we're out of organs + var/obj/item/organ/guts = pick(internal_organs) + var/turf/T = get_turf(src) + guts.Remove(src) + guts.forceMove(T) + var/atom/throw_target = get_edge_target_turf(guts, dir) + guts.throw_at(throw_target, power, 4, src) + /mob/living/carbon/fully_replace_character_name(oldname,newname) ..() diff --git a/code/modules/mob/living/carbon/human/death.dm.rej b/code/modules/mob/living/carbon/human/death.dm.rej deleted file mode 100644 index a4a1fc5a7c..0000000000 --- a/code/modules/mob/living/carbon/human/death.dm.rej +++ /dev/null @@ -1,10 +0,0 @@ -diff a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm (rejected hunks) -@@ -32,7 +32,7 @@ - - dna.species.spec_death(gibbed, src) - -- if(SSticker && SSticker.mode) -+ if(SSticker.HasRoundStarted()) - SSblackbox.ReportDeath(src) - if(mind && mind.devilinfo) - INVOKE_ASYNC(mind.devilinfo, /datum/devilinfo.proc/beginResurrectionCheck, src) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 9081591395..a3bb2fefde 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -134,7 +134,7 @@ if(stat == DEAD || (status_flags & FAKEDEATH)) appears_dead = 1 if(suiciding) - msg += "[t_He] appear[p_s()] to have commited suicide... there is no hope of recovery.\n" + msg += "[t_He] appear[p_s()] to have committed suicide... there is no hope of recovery.\n" if(hellbound) msg += "[t_His] soul seems to have been ripped out of [t_his] body. Revival is impossible.\n" msg += "[t_He] [t_is] limp and unresponsive; there are no signs of life" diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index dce38bd664..0e45246a20 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -28,7 +28,7 @@ //Holopad if(istype(ai.current, /obj/machinery/holopad)) var/obj/machinery/holopad/H = ai.current - H.move_hologram(ai) + H.move_hologram(ai, T) /mob/camera/aiEye/Move() return 0 @@ -106,4 +106,4 @@ /mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker)) - ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans) + ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index 7cd6567ecb..1507c43912 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -108,6 +108,7 @@ speak_emote = list("clanks", "clinks", "clunks", "clangs") verb_ask = "requests" verb_exclaim = "proclaims" + verb_whisper = "imparts" verb_yell = "harangues" bubble_icon = "clock" initial_languages = list(/datum/language/common, /datum/language/ratvar) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index d822a05886..ec76c2176f 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -401,7 +401,7 @@ Difficulty: Very Hard to_chat(user, observer_desc) to_chat(user, "It is activated by [activation_method].") -/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans) +/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode) ..() if(isliving(speaker)) ActivationReaction(speaker, ACTIVATE_SPEECH) diff --git a/code/modules/mob/living/simple_animal/slime/say.dm b/code/modules/mob/living/simple_animal/slime/say.dm index ae7c14068f..60a25f90b7 100644 --- a/code/modules/mob/living/simple_animal/slime/say.dm +++ b/code/modules/mob/living/simple_animal/slime/say.dm @@ -1,4 +1,4 @@ -/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans) +/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode) if(speaker != src && !radio_freq && !stat) if (speaker in Friends) speech_buffer = list() diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 8971d33b28..f9bcfe1b6f 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -16,7 +16,7 @@ response_disarm = "shoos" response_harm = "stomps on" emote_see = list("jiggles", "bounces in place") - speak_emote = list("telepathically chirps") + speak_emote = list("blorbles") bubble_icon = "slime" initial_languages = list(/datum/language/common, /datum/language/slime) @@ -31,10 +31,10 @@ see_in_dark = 8 - verb_say = "telepathically chirps" - verb_ask = "telepathically asks" - verb_exclaim = "telepathically cries" - verb_yell = "telephatically cries" + verb_say = "blorbles" + verb_ask = "inquisitively blorbles" + verb_exclaim = "loudly blorbles" + verb_yell = "loudly blorbles" // canstun and canweaken don't affect slimes because they ignore stun and weakened variables // for the sake of cleanliness, though, here they are. diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 24b4d228cc..819f7f3db2 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -351,6 +351,8 @@ /mob/proc/spin(spintime, speed) set waitfor = 0 var/D = dir + if((spintime < 1)||(speed < 1)||!spintime||!speed) + return while(spintime >= speed) sleep(speed) switch(D) diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm index dfbf3fe50b..9fe043a4a0 100644 --- a/code/modules/power/generator.dm +++ b/code/modules/power/generator.dm @@ -28,11 +28,12 @@ /obj/machinery/power/generator/Initialize(mapload) - . = ..() + . = ..() var/obj/machinery/atmospherics/components/binary/circulator/circpath = /obj/machinery/atmospherics/components/binary/circulator cold_circ = locate(circpath) in get_step(src, cold_dir) hot_circ = locate(circpath) in get_step(src, hot_dir) connect_to_network() + SSair.atmos_machinery += src if(cold_circ) switch(cold_dir) @@ -55,6 +56,9 @@ update_icon() +/obj/machinery/power/generator/Destroy() + SSair.atmos_machinery -= src + return ..() /obj/machinery/power/generator/update_icon() @@ -63,21 +67,20 @@ else cut_overlays() - if(lastgenlev != 0) - add_overlay("teg-op[lastgenlev]") + var/L = min(round(lastgenlev/100000),11) + if(L != 0) + add_overlay(image('icons/obj/power.dmi', "teg-op[L]")) - add_overlay("teg-oc[lastcirc]") + add_overlay("teg-oc[lastcirc]") #define GENRATE 800 // generator output coefficient from Q -/obj/machinery/power/generator/process() +/obj/machinery/power/generator/process_atmos() if(!cold_circ || !hot_circ) return - lastgen = 0 - if(powernet) //to_chat(world, "cold_circ and hot_circ pass") @@ -104,7 +107,7 @@ var/energy_transfer = delta_temperature*hot_air_heat_capacity*cold_air_heat_capacity/(hot_air_heat_capacity+cold_air_heat_capacity) var/heat = energy_transfer*(1-efficiency) - lastgen = energy_transfer*efficiency + lastgen += energy_transfer*efficiency //to_chat(world, "lastgen = [lastgen]; heat = [heat]; delta_temperature = [delta_temperature]; hot_air_heat_capacity = [hot_air_heat_capacity]; cold_air_heat_capacity = [cold_air_heat_capacity];") @@ -113,7 +116,7 @@ //to_chat(world, "POWER: [lastgen] W generated at [efficiency*100]% efficiency and sinks sizes [cold_air_heat_capacity], [hot_air_heat_capacity]") - add_avail(lastgen) + //add_avail(lastgen) This is done in process now // update icon overlays only if displayed level has changed if(hot_air) @@ -124,15 +127,23 @@ var/datum/gas_mixture/cold_circ_air1 = cold_circ.AIR1 cold_circ_air1.merge(cold_air) - var/genlev = max(0, min( round(11*lastgen / 100000), 11)) + update_icon() + var/circ = "[cold_circ && cold_circ.last_pressure_delta > 0 ? "1" : "0"][hot_circ && hot_circ.last_pressure_delta > 0 ? "1" : "0"]" - if((genlev != lastgenlev) || (circ != lastcirc)) - lastgenlev = genlev + if(circ != lastcirc) lastcirc = circ update_icon() src.updateDialog() +/obj/machinery/power/generator/process() + //Setting this number higher just makes the change in power output slower, it doesnt actualy reduce power output cause **math** + var/power_output = round(lastgen / 10) + add_avail(power_output) + lastgenlev = power_output + lastgen -= power_output + ..() + /obj/machinery/power/generator/attack_hand(mob/user) if(..()) user << browse(null, "window=teg") @@ -151,7 +162,13 @@ t += "
" - t += "Output: [round(lastgen)] W" + var/displaygen = lastgenlev + if(displaygen < 1000000) //less than a MW + displaygen /= 1000 + t += "Output: [round(displaygen,0.01)] kW" + else + displaygen /= 1000000 + t += "Output: [round(displaygen,0.01)] MW" t += "
" diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 9deebdfe10..fb2df4deeb 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -14,6 +14,7 @@ light_power = 0.7 light_range = 15 light_color = rgb(255, 0, 0) + gender = FEMALE var/clashing = FALSE //If Nar-Sie is fighting Ratvar /obj/singularity/narsie/large @@ -26,8 +27,8 @@ grav_pull = 10 consume_range = 12 //How many tiles out do we eat -/obj/singularity/narsie/large/New() - ..() +/obj/singularity/narsie/large/Initialize() + . = ..() send_to_playing_players("NAR-SIE HAS RISEN") send_to_playing_players(pick('sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg')) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 3b0bc3087b..1a308ed471 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -29,12 +29,12 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF dangerous_possession = TRUE -/obj/singularity/New(loc, var/starting_energy = 50, var/temp = 0) +/obj/singularity/Initialize(mapload, starting_energy = 50) //CARN: admin-alert for chuckle-fuckery. admin_investigate_setup() src.energy = starting_energy - ..() + . = ..() START_PROCESSING(SSobj, src) GLOB.poi_list |= src GLOB.singularities |= src diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 4b48d19857..a580b63e55 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -129,6 +129,7 @@ /obj/machinery/power/supermatter_shard/Initialize() . = ..() + SSair.atmos_machinery += src countdown = new(src) countdown.start() GLOB.poi_list |= src @@ -139,6 +140,7 @@ /obj/machinery/power/supermatter_shard/Destroy() investigate_log("has been destroyed.", "supermatter") + SSair.atmos_machinery -= src QDEL_NULL(radio) GLOB.poi_list -= src QDEL_NULL(countdown) @@ -181,7 +183,7 @@ E.energy = power qdel(src) -/obj/machinery/power/supermatter_shard/process() +/obj/machinery/power/supermatter_shard/process_atmos() var/turf/T = loc if(isnull(T)) // We have a null turf...something is wrong, stop processing this entity. @@ -296,6 +298,7 @@ if(produces_gas) env.merge(removed) + air_update_turf() for(var/mob/living/carbon/human/l in view(src, HALLUCINATION_RANGE(power))) // If they can see it without mesons on. Bad on them. if(!istype(l.glasses, /obj/item/clothing/glasses/meson)) diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index fbb82cb36a..df08899140 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -40,6 +40,11 @@ GLOBAL_LIST_INIT(blacklisted_tesla_types, typecacheof(list(/obj/machinery/atmosp var/energy_to_raise = 32 var/energy_to_lower = -20 +/obj/singularity/energy_ball/Initialize(mapload, starting_energy = 50, is_miniball = FALSE) + . = ..() + if(!is_miniball) + set_light(10, 7, "#EEEEFF") + /obj/singularity/energy_ball/ex_act(severity, target) return @@ -54,6 +59,11 @@ GLOBAL_LIST_INIT(blacklisted_tesla_types, typecacheof(list(/obj/machinery/atmosp . = ..() +/obj/singularity/energy_ball/admin_investigate_setup() + if(istype(loc, /obj/singularity/energy_ball)) + return + ..() + /obj/singularity/energy_ball/process() if(!orbiting) handle_energy() @@ -117,7 +127,7 @@ GLOBAL_LIST_INIT(blacklisted_tesla_types, typecacheof(list(/obj/machinery/atmosp /obj/singularity/energy_ball/proc/new_mini_ball() if(!loc) return - var/obj/singularity/energy_ball/EB = new(loc) + var/obj/singularity/energy_ball/EB = new(loc, 0, TRUE) EB.transform *= pick(0.3, 0.4, 0.5, 0.6, 0.7) var/icon/I = icon(icon,icon_state,dir) diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm index a6440e32ed..b1fd49779f 100644 --- a/code/modules/projectiles/ammunition/energy.dm +++ b/code/modules/projectiles/ammunition/energy.dm @@ -191,7 +191,7 @@ fire_sound = 'sound/magic/lightningbolt.ogg' e_cost = 200 select_name = "stun" - projectile_type = /obj/item/projectile/energy/tesla_revolver + projectile_type = /obj/item/projectile/energy/tesla/revolver /obj/item/ammo_casing/energy/gravityrepulse projectile_type = /obj/item/projectile/gravityrepulse diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index dceed5b438..9835b1df21 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -179,6 +179,8 @@ return if(setAngle) Angle = setAngle + var/old_pixel_x = pixel_x + var/old_pixel_y = pixel_y if(!legacy) //new projectiles set waitfor = 0 var/next_run = world.time @@ -201,29 +203,30 @@ var/Pixel_x=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here var/Pixel_y=round((cos(Angle)+16*cos(Angle)*2), 1) - var/pixel_x_offset = pixel_x + Pixel_x - var/pixel_y_offset = pixel_y + Pixel_y + var/pixel_x_offset = old_pixel_x + Pixel_x + var/pixel_y_offset = old_pixel_y + Pixel_y var/new_x = x var/new_y = y while(pixel_x_offset > 16) pixel_x_offset -= 32 - pixel_x -= 32 + old_pixel_x -= 32 new_x++// x++ while(pixel_x_offset < -16) pixel_x_offset += 32 - pixel_x += 32 + old_pixel_x += 32 new_x-- - while(pixel_y_offset > 16) pixel_y_offset -= 32 - pixel_y -= 32 + old_pixel_y -= 32 new_y++ while(pixel_y_offset < -16) pixel_y_offset += 32 - pixel_y += 32 + old_pixel_y += 32 new_y-- - + + pixel_x = old_pixel_x + pixel_y = old_pixel_y step_towards(src, locate(new_x, new_y, z)) next_run += max(world.tick_lag, speed) var/delay = next_run - world.time @@ -232,7 +235,9 @@ pixel_y = pixel_y_offset else animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW) - + old_pixel_x = pixel_x_offset + old_pixel_y = pixel_y_offset + if(original && (original.layer>=2.75) || ismob(original)) if(loc == get_turf(original)) if(!(original in permutated)) diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm index c1a67f4c81..974ea935f2 100644 --- a/code/modules/projectiles/projectile/energy.dm +++ b/code/modules/projectiles/projectile/energy.dm @@ -159,44 +159,34 @@ /obj/item/projectile/energy/bolt/large damage = 20 -/obj/item/projectile/energy/tesla_revolver +/obj/item/projectile/energy/tesla name = "tesla bolt" icon_state = "tesla_projectile" impact_effect_type = /obj/effect/overlay/temp/impact_effect/blue_laser var/chain -/obj/item/projectile/energy/tesla_revolver/fire(setAngle) +/obj/item/projectile/energy/tesla/fire(setAngle) if(firer) chain = firer.Beam(src, icon_state = "lightning[rand(1, 12)]", time = INFINITY, maxdistance = INFINITY) ..() -/obj/item/projectile/energy/tesla_revolver/on_hit(atom/target) - . = ..() - if(isliving(target)) - tesla_zap(src, 3, 10000) - qdel(src) - -/obj/item/projectile/energy/tesla_revolver/Destroy() +/obj/item/projectile/energy/tesla/Destroy() qdel(chain) return ..() +/obj/item/projectile/energy/tesla/revolver + name = "energy orb" -/obj/item/projectile/energy/tesla_cannon - name = "tesla bolt" - icon_state = "tesla_projectile" - impact_effect_type = /obj/effect/overlay/temp/impact_effect/blue_laser - var/chain +/obj/item/projectile/energy/tesla/revolver/on_hit(atom/target) + . = ..() + if(isliving(target)) + tesla_zap(target, 3, 10000) + qdel(src) -/obj/item/projectile/energy/tesla_cannon/fire(setAngle) - if(firer) - chain = firer.Beam(src, icon_state = "lightning[rand(1, 12)]", time = INFINITY, maxdistance = INFINITY) - ..() +/obj/item/projectile/energy/tesla/cannon + name = "tesla orb" -/obj/item/projectile/energy/tesla_cannon/on_hit(atom/target) +/obj/item/projectile/energy/tesla/cannon/on_hit(atom/target) . = ..() - tesla_zap(src, 3, 10000, explosive = FALSE, stun_mobs = FALSE) + tesla_zap(target, 3, 10000, explosive = FALSE, stun_mobs = FALSE) qdel(src) - -/obj/item/projectile/energy/tesla_cannon/Destroy() - qdel(chain) - return ..() diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index 2dbc0ff1c2..a8ab8fd426 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -38,7 +38,7 @@ /obj/item/weapon/reagent_containers/food/snacks/grown/wheat = list("flour" = -5), /obj/item/weapon/reagent_containers/food/snacks/grown/oat = list("flour" = -5), /obj/item/weapon/reagent_containers/food/snacks/grown/rice = list("rice" = -5), - /obj/item/weapon/reagent_containers/food/snacks/donut/New = list("sprinkles" = -2, "sugar" = 1), + /obj/item/weapon/reagent_containers/food/snacks/donut = list("sprinkles" = -2, "sugar" = 1), /obj/item/weapon/reagent_containers/food/snacks/grown/cherries = list("cherryjelly" = 0), /obj/item/weapon/reagent_containers/food/snacks/grown/bluecherries = list("bluecherryjelly" = 0), /obj/item/weapon/reagent_containers/food/snacks/egg = list("eggyolk" = -5), diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 442772fea8..56a89fe389 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -60,7 +60,10 @@ // data for nutriment is one or more (flavour -> ratio) // where all the ratio values adds up to 1 - var/list/taste_amounts = data.Copy() + var/list/taste_amounts = list() + if(data) + taste_amounts = data.Copy() + counterlist_scale(taste_amounts, volume) var/list/other_taste_amounts = newdata.Copy() diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index aa913ba8f0..6d38e85ca8 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -288,30 +288,43 @@ /datum/reagent/medicine/salglu_solution name = "Saline-Glucose Solution" id = "salglu_solution" - description = "Has a 33% chance per metabolism cycle to heal brute and burn damage. Can be used as a blood substitute on an IV drip." + description = "Has a 33% chance per metabolism cycle to heal brute and burn damage. Can be used as a temporary blood substitute." reagent_state = LIQUID color = "#DCDCDC" metabolization_rate = 0.5 * REAGENTS_METABOLISM + overdose_threshold = 60 taste_description = "sweetness and salt" + var/last_added = 0 + var/maximum_reachable = BLOOD_VOLUME_NORMAL - 10 //So that normal blood regeneration can continue with salglu active /datum/reagent/medicine/salglu_solution/on_mob_life(mob/living/M) + if(last_added) + M.blood_volume -= last_added + last_added = 0 + if(M.blood_volume < maximum_reachable) //Can only up to double your effective blood level. + var/amount_to_add = min(M.blood_volume, volume*5) + var/new_blood_level = min(M.blood_volume + amount_to_add, maximum_reachable) + last_added = new_blood_level - M.blood_volume + M.blood_volume = new_blood_level if(prob(33)) M.adjustBruteLoss(-0.5*REM, 0) M.adjustFireLoss(-0.5*REM, 0) - if(iscarbon(M)) - var/mob/living/carbon/C = M - C.blood_volume += 0.2 . = 1 ..() -/datum/reagent/medicine/salglu_solution/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1) - if(ishuman(M) && method == INJECT) - var/mob/living/carbon/human/H = M - if(H.dna && !(NOBLOOD in H.dna.species.species_traits)) - var/efficiency = (BLOOD_VOLUME_NORMAL-H.blood_volume)/700 + 0.2//The lower the blood of the patient, the better it is as a blood substitute. - efficiency = Clamp(efficiency, 0.1, 0.75) - //As it's designed for an IV drip, make large injections not as effective as repeated small injections. - H.blood_volume += round(efficiency * min(5,reac_volume), 0.1) +/datum/reagent/medicine/salglu_solution/overdose_process(mob/living/M) + if(prob(3)) + to_chat(M, "You feel salty.") + holder.add_reagent("sodiumchloride", 1) + holder.remove_reagent("salglu_solution", 0.5) + else if(prob(3)) + to_chat(M, "You feel sweet.") + holder.add_reagent("sugar", 1) + holder.remove_reagent("salglu_solution", 0.5) + if(prob(33)) + M.adjustBruteLoss(0.5*REM, 0) + M.adjustFireLoss(0.5*REM, 0) + . = 1 ..() /datum/reagent/medicine/mine_salve @@ -334,10 +347,9 @@ /datum/reagent/medicine/mine_salve/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1) if(iscarbon(M) && M.stat != DEAD) if(method in list(INGEST, VAPOR, INJECT)) - M.Stun(4) - M.Weaken(4) + M.nutrition -= 5 if(show_message) - to_chat(M, "Your stomach agonizingly cramps!") + to_chat(M, "Your stomach feels empty and cramps!") else var/mob/living/carbon/C = M for(var/s in C.surgeries) @@ -949,8 +961,7 @@ /datum/reagent/medicine/antitoxin/on_mob_life(mob/living/M) M.adjustToxLoss(-2*REM, 0) for(var/datum/reagent/toxin/R in M.reagents.reagent_list) - if(R != src) - M.reagents.remove_reagent(R.id,1) + M.reagents.remove_reagent(R.id,1) ..() . = 1 diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index c25a1d050d..dc8457905d 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -189,7 +189,7 @@ /datum/reagent/water/holywater/on_mob_life(mob/living/M) if(!data) data = 1 data++ - M.jitteriness = max(M.jitteriness-5,0) + M.jitteriness = min(M.jitteriness+4,10) if(data >= 30) // 12 units, 54 seconds @ metabolism 0.4 units & tick rate 1.8 sec if(!M.stuttering) M.stuttering = 1 @@ -212,9 +212,9 @@ SSticker.mode.remove_cultist(M.mind, 1, 1) else if(is_servant_of_ratvar(M)) remove_servant_of_ratvar(M) - holder.remove_reagent(id, volume) // maybe this is a little too perfect and a max() cap on the statuses would be better?? M.jitteriness = 0 M.stuttering = 0 + holder.remove_reagent(id, volume) // maybe this is a little too perfect and a max() cap on the statuses would be better?? return holder.remove_reagent(id, 0.4) //fixed consumption to prevent balancing going out of whack @@ -658,7 +658,7 @@ taste_mult = 0 // apparently tasteless. /datum/reagent/mercury/on_mob_life(mob/living/M) - if(M.canmove && isspaceturf(M.loc)) + if(M.canmove && !isspaceturf(M.loc)) step(M, pick(GLOB.cardinal)) if(prob(5)) M.emote(pick("twitch","drool","moan")) @@ -738,7 +738,7 @@ taste_description = "metal" /datum/reagent/lithium/on_mob_life(mob/living/M) - if(M.canmove && isspaceturf(M.loc)) + if(M.canmove && !isspaceturf(M.loc)) step(M, pick(GLOB.cardinal)) if(prob(5)) M.emote(pick("twitch","drool","moan")) diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 528124f84c..cedec9941b 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -648,6 +648,34 @@ M.losebreath += 5 return ..() +/datum/reagent/toxin/spewium + name = "Spewium" + id = "spewium" + description = "A powerful emetic, causes uncontrollable vomiting. May result in vomiting organs at high doses." + reagent_state = LIQUID + color = "#2f6617" //A sickly green color + metabolization_rate = REAGENTS_METABOLISM + overdose_threshold = 29 + toxpwr = 0 + taste_description = "vomit" + +/datum/reagent/toxin/spewium/on_mob_life(mob/living/M) + .=..() + if(current_cycle >=11 && prob(min(50,current_cycle)) && ishuman(M)) + var/mob/living/carbon/human/H = M + H.vomit(lost_nutrition = 10, blood = prob(10), stun = prob(50), distance = rand(0,4), message = TRUE, toxic = prob(30)) + for(var/datum/reagent/toxin/R in M.reagents.reagent_list) + if(R != src) + H.reagents.remove_reagent(R.id,1) + +/datum/reagent/toxin/spewium/overdose_process(mob/living/M) + . = ..() + if(current_cycle >=33 && prob(15) && ishuman(M)) + var/mob/living/carbon/human/H = M + H.spew_organ() + H.vomit(lost_nutrition = 0, blood = 1, stun = 1, distance = 4) + to_chat(H, "You feel something lumpy come up as you vomit.") + /datum/reagent/toxin/curare name = "Curare" id = "curare" diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm index a92c52abf4..37074b6d12 100644 --- a/code/modules/reagents/reagent_containers/bottle.dm +++ b/code/modules/reagents/reagent_containers/bottle.dm @@ -58,6 +58,12 @@ icon_state = "bottle12" list_reagents = list("cyanide" = 30) +/obj/item/weapon/reagent_containers/glass/bottle/spewium + name = "spewium bottle" + desc = "A small bottle of spewium." + icon_state = "bottle12" + list_reagents = list("spewium" = 30) + /obj/item/weapon/reagent_containers/glass/bottle/morphine name = "morphine bottle" desc = "A small bottle of morphine." diff --git a/code/modules/research/research.dm b/code/modules/research/research.dm index 25b3a98980..dfd64c3101 100644 --- a/code/modules/research/research.dm +++ b/code/modules/research/research.dm @@ -185,7 +185,7 @@ research holder datum. if((D.build_type & SMELTER) && ("initial" in D.category)) AddDesign2Known(D) -/datum/research/biogenerator/AddDesign2Known(datum/design/D) +/datum/research/smelter/AddDesign2Known(datum/design/D) if(!(D.build_type & SMELTER)) return ..() diff --git a/code/modules/shuttle/elevator.dm b/code/modules/shuttle/elevator.dm new file mode 100644 index 0000000000..12f9c24f9a --- /dev/null +++ b/code/modules/shuttle/elevator.dm @@ -0,0 +1,10 @@ +/obj/docking_port/mobile/elevator + name = "elevator" + id = "elevator" + dwidth = 3 + width = 7 + height = 7 + knockdown = FALSE + +/obj/docking_port/mobile/elevator/request(obj/docking_port/stationary/S) //No transit, no ignition, just a simple up/down platform + dock(S, TRUE) \ No newline at end of file diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 756fad25b3..b5571164ff 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -3,7 +3,7 @@ return // Called when shuttle attempts to move an atom. -/atom/movable/proc/onShuttleMove(turf/T1, rotation) +/atom/movable/proc/onShuttleMove(turf/T1, rotation, knockdown = TRUE) if(rotation) shuttleRotate(rotation) loc = T1 @@ -47,11 +47,11 @@ else shake_camera(src, 7, 1) -/mob/living/carbon/onShuttleMove() +/mob/living/carbon/onShuttleMove(turf/T1, rotation, knockdown = TRUE) . = ..() if(!.) return - if(!buckled) + if(!buckled && knockdown) Weaken(3) /obj/effect/abstract/proximity_checker/onShuttleMove() diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 00ddecb7f8..656ba24da6 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -217,6 +217,8 @@ var/launch_status = NOLAUNCH + var/knockdown = TRUE //Will it knock down mobs when it docks? + // A timid shuttle will not register itself with the shuttle subsystem // All shuttle templates are timid var/timid = FALSE @@ -517,7 +519,7 @@ //move mobile to new location for(var/atom/movable/AM in T0) - if(AM.onShuttleMove(T1, rotation)) + if(AM.onShuttleMove(T1, rotation, knockdown)) moved_atoms += AM if(rotation) @@ -578,10 +580,7 @@ if(M.pulledby) M.pulledby.stop_pulling() M.stop_pulling() - M.visible_message("[M] is hit by \ - a hyperspace ripple!", - "You feel an immense \ - crushing pressure as the space around you ripples.") + M.visible_message("[src] slams into [M]!") if(M.key || M.get_ghost(TRUE)) SSblackbox.add_details("shuttle_gib", "[type]") else diff --git a/code/modules/spells/spell_types/mind_transfer.dm b/code/modules/spells/spell_types/mind_transfer.dm index 7ebafe6e24..052c1f1162 100644 --- a/code/modules/spells/spell_types/mind_transfer.dm +++ b/code/modules/spells/spell_types/mind_transfer.dm @@ -62,29 +62,14 @@ Also, you never added distance checking after target is selected. I've went ahea var/mob/caster = user//The wizard/whomever doing the body transferring. //MIND TRANSFER BEGIN - if(caster.mind.special_verbs.len)//If the caster had any special verbs, remove them from the mob verb list. - for(var/V in caster.mind.special_verbs)//Since the caster is using an object spell system, this is mostly moot. - caster.verbs -= V//But a safety nontheless. - - if(victim.mind.special_verbs.len)//Now remove all of the victim's verbs. - for(var/V in victim.mind.special_verbs) - victim.verbs -= V - var/mob/dead/observer/ghost = victim.ghostize(0) caster.mind.transfer_to(victim) - if(victim.mind.special_verbs.len)//To add all the special verbs for the original caster. - for(var/V in caster.mind.special_verbs)//Not too important but could come into play. - caster.verbs += V - ghost.mind.transfer_to(caster) if(ghost.key) caster.key = ghost.key //have to transfer the key since the mind was not active qdel(ghost) - if(caster.mind.special_verbs.len)//If they had any special verbs, we add them here. - for(var/V in caster.mind.special_verbs) - caster.verbs += V //MIND TRANSFER END //Here we paralyze both mobs and knock them out for a time. diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index de8c2b79ac..60edac1977 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -218,6 +218,14 @@ for(var/X in list(owner.glasses, owner.ears, owner.wear_mask, owner.head)) var/obj/item/I = X owner.dropItemToGround(I, TRUE) + + //Handle dental implants + for(var/datum/action/item_action/hands_free/activate_pill/AP in owner.actions) + AP.Remove(owner) + var/obj/pill = AP.target + if(pill) + pill.forceMove(src) + name = "[owner.real_name]'s head" ..() @@ -300,6 +308,14 @@ C.real_name = real_name real_name = "" name = initial(name) + + //Handle dental implants + for(var/obj/item/weapon/reagent_containers/pill/P in src) + for(var/datum/action/item_action/hands_free/activate_pill/AP in P.actions) + P.forceMove(C) + AP.Grant(C) + break + ..() diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 909f83e4d7..dd63506086 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -48,7 +48,10 @@ brain = null update_icon_dropped() else - I.loc = T + if(istype(I, /obj/item/weapon/reagent_containers/pill)) + for(var/datum/action/item_action/hands_free/activate_pill/AP in I.actions) + qdel(AP) + I.forceMove(T) /obj/item/bodypart/head/update_limb(dropping_limb, mob/living/carbon/source) var/mob/living/carbon/C diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm index eef88e4a5f..c51a49081c 100644 --- a/code/modules/surgery/dental_implant.dm +++ b/code/modules/surgery/dental_implant.dm @@ -18,10 +18,10 @@ user.drop_item() tool.loc = target - var/datum/action/item_action/hands_free/activate_pill/P = new + var/datum/action/item_action/hands_free/activate_pill/P = new(tool) P.button.name = "Activate [tool.name]" P.target = tool - P.Grant(target) + P.Grant(target) //The pill never actually goes in an inventory slot, so the owner doesn't inherit actions from it user.visible_message("[user] wedges \the [tool] into [target]'s [parse_zone(target_zone)]!", "You wedge [tool] into [target]'s [parse_zone(target_zone)].") return 1 @@ -37,6 +37,5 @@ if(target.reagents.total_volume) target.reagents.reaction(owner, INGEST) target.reagents.trans_to(owner, target.reagents.total_volume) - Remove(owner) qdel(target) return 1 \ No newline at end of file diff --git a/code/modules/surgery/organs/ears.dm b/code/modules/surgery/organs/ears.dm index c91cb219af..e66346a2c8 100644 --- a/code/modules/surgery/organs/ears.dm +++ b/code/modules/surgery/organs/ears.dm @@ -4,6 +4,7 @@ desc = "There are three parts to the ear. Inner, middle and outer. Only one of these parts should be normally visible." zone = "head" slot = "ears" + gender = PLURAL // `deaf` measures "ticks" of deafness. While > 0, the person is unable // to hear anything. diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index 672ac924ad..2cb2dd5dc6 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -4,6 +4,7 @@ desc = "I see you!" zone = "eyes" slot = "eye_sight" + gender = PLURAL var/sight_flags = 0 var/see_in_dark = 2 diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index a2048c2b71..e4ab2199ad 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -8,6 +8,7 @@ icon_state = "appendix" zone = "mouth" slot = "vocal_cords" + gender = PLURAL var/list/spans = null /obj/item/organ/vocal_cords/proc/can_speak_with() //if there is any limitation to speaking with these cords diff --git a/code/world.dm b/code/world.dm index 9023ac47f3..29c40a5742 100644 --- a/code/world.dm +++ b/code/world.dm @@ -136,11 +136,7 @@ if(!key_valid) return "Bad Key" else -#define CHAT_PULLR 64 //defined in preferences.dm, but not available here at compilation time - for(var/client/C in GLOB.clients) - if(C.prefs && (C.prefs.chat_toggles & CHAT_PULLR)) - to_chat(C, "PR: [input["announce"]]") -#undef CHAT_PULLR + AnnouncePR(input["announce"], json_decode(input["payload"])) else if("crossmessage" in input) if(!key_valid) @@ -176,6 +172,25 @@ else if("server_hop" in input) show_server_hop_transfer_screen(input["server_hop"]) +#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round + //This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored + +/world/proc/AnnouncePR(announcement, list/payload) + var/static/list/PRcounts = list() //PR id -> number of times announced this round + var/id = "[payload["pull_request"]["id"]]" + if(!PRcounts[id]) + PRcounts[id] = 1 + else + ++PRcounts[id] + if(PRcounts[id] > PR_ANNOUNCEMENTS_PER_ROUND) + return + +#define CHAT_PULLR 64 //defined in preferences.dm, but not available here at compilation time + for(var/client/C in GLOB.clients) + if(C.prefs && (C.prefs.chat_toggles & CHAT_PULLR)) + C << "PR: [announcement]" +#undef CHAT_PULLR + #define WORLD_REBOOT(X) log_world("World rebooted at [time_stamp()]"); ..(X); return; /world/Reboot(var/reason, var/feedback_c, var/feedback_r, var/time) if (reason == 1) //special reboot, do none of the normal stuff @@ -226,7 +241,7 @@ /world/proc/RoundEndAnimation(round_end_sound_sent) set waitfor = FALSE var/round_end_sound - if(!SSticker && SSticker.round_end_sound) + if(SSticker.round_end_sound) round_end_sound = SSticker.round_end_sound if (!round_end_sound_sent) for(var/thing in GLOB.clients) diff --git a/html/changelogs/AutoChangeLog-pr-682.yml b/html/changelogs/AutoChangeLog-pr-682.yml new file mode 100644 index 0000000000..c55c645e6e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-682.yml @@ -0,0 +1,4 @@ +author: "Swindly" +delete-after: True +changes: + - tweak: "Mercury and Lithium make people move when not in space instead of when in space." diff --git a/html/changelogs/AutoChangeLog-pr-685.yml b/html/changelogs/AutoChangeLog-pr-685.yml new file mode 100644 index 0000000000..16311e93ff --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-685.yml @@ -0,0 +1,5 @@ +author: "Moonlighting Mac says" +delete-after: True +changes: + - bugfix: "Due to a clerical error in the chef's cookbooks now being resolved, you can now make the pristine cookery dish \"Stuffed Legion\" out of exotic ingredients from Lavaland." + - experiment: "After being found again you will now be able to enjoy its special blend of flavors with your tastebuds. Mmm." diff --git a/html/changelogs/AutoChangeLog-pr-698.yml b/html/changelogs/AutoChangeLog-pr-698.yml new file mode 100644 index 0000000000..40e55644b5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-698.yml @@ -0,0 +1,4 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - rscadd: "You can now make holocalls! Simply stand on a pad, bring up the menu, and select the holopad you wish to call. Remain still until someone answers. When they do, you'll be able to act just like an AI hologram until the call ends" diff --git a/html/changelogs/AutoChangeLog-pr-699.yml b/html/changelogs/AutoChangeLog-pr-699.yml new file mode 100644 index 0000000000..68fca1b6ac --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-699.yml @@ -0,0 +1,4 @@ +author: "QualityVan" +delete-after: True +changes: + - tweak: "Saline glucose now acts as temporary blood instead of increasing blood regeneration" diff --git a/html/changelogs/AutoChangeLog-pr-701.yml b/html/changelogs/AutoChangeLog-pr-701.yml new file mode 100644 index 0000000000..8848bcb450 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-701.yml @@ -0,0 +1,7 @@ +author: "ninjanomnom" +delete-after: True +changes: + - tweak: "TEG displays power in kw or MW now" + - tweak: "TEG power bar only maxes over 1MW now" + - experiment: "Moves TEG to SSair" + - experiment: "Moves SM to SSair" diff --git a/html/changelogs/AutoChangeLog-pr-705.yml b/html/changelogs/AutoChangeLog-pr-705.yml new file mode 100644 index 0000000000..a4861ed8f6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-705.yml @@ -0,0 +1,4 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - bugfix: "The biogenerator will now show its recipes again." diff --git a/html/changelogs/AutoChangeLog-pr-706.yml b/html/changelogs/AutoChangeLog-pr-706.yml new file mode 100644 index 0000000000..bef4ff2c24 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-706.yml @@ -0,0 +1,4 @@ +author: "Kor, Goof and Plizzard" +delete-after: True +changes: + - rscadd: "Adds persistent trophy cases. They are not on any map yet." diff --git a/html/changelogs/AutoChangeLog-pr-708.yml b/html/changelogs/AutoChangeLog-pr-708.yml new file mode 100644 index 0000000000..6cb7c07312 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-708.yml @@ -0,0 +1,4 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - bugfix: "Squishy plants will now affect walls and other turfs they get squished on" diff --git a/html/changelogs/AutoChangeLog-pr-714.yml b/html/changelogs/AutoChangeLog-pr-714.yml new file mode 100644 index 0000000000..d5e4582f40 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-714.yml @@ -0,0 +1,4 @@ +author: "XDTM" +delete-after: True +changes: + - tweak: "Blood Cult's talisman of Horrors now works at range. It will still give no warning to the victim." diff --git a/html/changelogs/AutoChangeLog-pr-717.yml b/html/changelogs/AutoChangeLog-pr-717.yml new file mode 100644 index 0000000000..fbb98e0039 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-717.yml @@ -0,0 +1,5 @@ +author: "coiax" +delete-after: True +changes: + - rscadd: "When talking on the alien hivemind, a person will be identified by +their real name, rather than who they are disguised as." diff --git a/html/changelogs/AutoChangeLog-pr-727.yml b/html/changelogs/AutoChangeLog-pr-727.yml new file mode 100644 index 0000000000..2eaec0638a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-727.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - tweak: "Fixed the slimecore HUD's neck slot sprite." diff --git a/html/changelogs/AutoChangeLog-pr-733.yml b/html/changelogs/AutoChangeLog-pr-733.yml new file mode 100644 index 0000000000..ef779f70a1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-733.yml @@ -0,0 +1,4 @@ +author: "BeeSting12" +delete-after: True +changes: + - bugfix: "Omega shuttle now has lighting." diff --git a/html/changelogs/AutoChangeLog-pr-745.yml b/html/changelogs/AutoChangeLog-pr-745.yml new file mode 100644 index 0000000000..b9aa3fddd2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-745.yml @@ -0,0 +1,4 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - bugfix: "revenants now properly resurrect from ectoplasm, as opposed to ectoplasm merely spawning a new grief ghost" diff --git a/html/changelogs/AutoChangeLog-pr-746.yml b/html/changelogs/AutoChangeLog-pr-746.yml new file mode 100644 index 0000000000..ddeea1d732 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-746.yml @@ -0,0 +1,4 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - bugfix: "Turrets can no longer see invisible things, such as unrevealed revenants" diff --git a/html/changelogs/AutoChangeLog-pr-747.yml b/html/changelogs/AutoChangeLog-pr-747.yml new file mode 100644 index 0000000000..583f6b5e56 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-747.yml @@ -0,0 +1,4 @@ +author: "QualityVan" +delete-after: True +changes: + - rscadd: "Point flashlights at mouths to see what's inside them" diff --git a/html/changelogs/AutoChangeLog-pr-748.yml b/html/changelogs/AutoChangeLog-pr-748.yml new file mode 100644 index 0000000000..7ad62adec8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-748.yml @@ -0,0 +1,5 @@ +author: "Moonlighting Mac says" +delete-after: True +changes: + - rscadd: "Courtesy of the art & crafts division, imitation basalt tiles themed on the rough volcanic terrain of lavaland are now available to be made out of sandstone." + - experiment: "The manufacturer even managed to replicate the way that it lights up with volcanic energy, it is the perfect accompaniment to other fake (or real) lava-land tiles or a independent piece." diff --git a/html/changelogs/AutoChangeLog-pr-756.yml b/html/changelogs/AutoChangeLog-pr-756.yml new file mode 100644 index 0000000000..7ef015b31c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-756.yml @@ -0,0 +1,6 @@ +author: "lordpidey" +delete-after: True +changes: + - rscadd: "There is a new traitor poison, spewium. It will cause uncontrollable vomiting, which gets worse the longer it's in your system. An overdose can cause vomiting of organs." + - tweak: "Committing suicide with a gas pump can now shoot out random organs." + - bugfix: "Toxic vomit now shows up as intended." diff --git a/html/changelogs/AutoChangeLog-pr-760.yml b/html/changelogs/AutoChangeLog-pr-760.yml new file mode 100644 index 0000000000..b0296b2330 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-760.yml @@ -0,0 +1,4 @@ +author: "bgobandit" +delete-after: True +changes: + - tweak: "The Syndicate has added basic functionality to their state-of-the-art equipment. Nuke ops can now donate all TCs at once." diff --git a/html/changelogs/AutoChangeLog-pr-764.yml b/html/changelogs/AutoChangeLog-pr-764.yml new file mode 100644 index 0000000000..87210fcb7a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-764.yml @@ -0,0 +1,4 @@ +author: "QualityVan" +delete-after: True +changes: + - bugfix: "Dental implants stay with the head they're in" diff --git a/html/changelogs/AutoChangeLog-pr-771.yml b/html/changelogs/AutoChangeLog-pr-771.yml new file mode 100644 index 0000000000..031ec64151 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-771.yml @@ -0,0 +1,4 @@ +author: "BeeSting12" +delete-after: True +changes: + - bugfix: "Pubbystation no longer has two airlocks stacked on top of each other leading into xenobiology's kill room." diff --git a/html/changelogs/AutoChangeLog-pr-781.yml b/html/changelogs/AutoChangeLog-pr-781.yml new file mode 100644 index 0000000000..08a5c148ff --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-781.yml @@ -0,0 +1,4 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - tweak: "Teslas now give off light" diff --git a/html/changelogs/AutoChangeLog-pr-792.yml b/html/changelogs/AutoChangeLog-pr-792.yml new file mode 100644 index 0000000000..9d2ccfebde --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-792.yml @@ -0,0 +1,6 @@ +author: "BeeSting12" +delete-after: True +changes: + - rscadd: "Deltastation's chemistry now has a screwdriver." + - bugfix: "Deltastation's morgue no longer has a blue tile." + - bugfix: "Deltastation's chemistry smart fridge is no longer blocked by a disposal unit." diff --git a/html/changelogs/AutoChangeLog-pr-800.yml b/html/changelogs/AutoChangeLog-pr-800.yml new file mode 100644 index 0000000000..798c98c64b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-800.yml @@ -0,0 +1,4 @@ +author: "coiax" +delete-after: True +changes: + - tweak: "The lavaland Seed Vault ruin can spawn only once." diff --git a/html/changelogs/AutoChangeLog-pr-801.yml b/html/changelogs/AutoChangeLog-pr-801.yml new file mode 100644 index 0000000000..756cf33927 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-801.yml @@ -0,0 +1,6 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - rscadd: "Internal Affairs Agents now obtain the kill objectives of their targets when they die." + - rscadd: "Internal Affairs Agents now have an integrated nanotrasen pinpointer that tracks their target at distances further than ten squares." + - rscadd: "Internal Affairs Agents will now lose any restrictions on collateral damage and gain a \"Die a glorious death\" objective upon becoming the last man standing, and revert if any of their targets are cloned." diff --git a/html/changelogs/AutoChangeLog-pr-805.yml b/html/changelogs/AutoChangeLog-pr-805.yml new file mode 100644 index 0000000000..be4a17ddf7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-805.yml @@ -0,0 +1,5 @@ +author: "CitadelStationBot" +delete-after: True +changes: + - rscadd: "Reduction to nutrition when consuming Miner's salve." + - rscdel: "Stun/weaken that bypasses bugged chemical protection when consuming Miner's salve." diff --git a/html/changelogs/AutoChangeLog-pr-809.yml b/html/changelogs/AutoChangeLog-pr-809.yml new file mode 100644 index 0000000000..06fb6139cc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-809.yml @@ -0,0 +1,5 @@ +author: "QualityVan" +delete-after: True +changes: + - rscadd: "Cargo can order restocking units for NanoMed vending machines" + - rscadd: "NanoMed vending machines can be build and unbuilt" diff --git a/html/changelogs/AutoChangeLog-pr-815.yml b/html/changelogs/AutoChangeLog-pr-815.yml new file mode 100644 index 0000000000..6472c7a13d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-815.yml @@ -0,0 +1,4 @@ +author: "Penguaro" +delete-after: True +changes: + - bugfix: "Adjusted the Examine description of the right-most tiles of the Space Station 13 sign to be consistent with the rest of the tiles." diff --git a/icons/effects/clockwork_effects.dmi b/icons/effects/clockwork_effects.dmi index 8bbf24a7ef..b2e15da1d0 100644 Binary files a/icons/effects/clockwork_effects.dmi and b/icons/effects/clockwork_effects.dmi differ diff --git a/icons/mob/screen_slimecore.dmi b/icons/mob/screen_slimecore.dmi index bc33ad6e37..63d67e6fba 100644 Binary files a/icons/mob/screen_slimecore.dmi and b/icons/mob/screen_slimecore.dmi differ diff --git a/icons/obj/flora/jungletrees.dmi b/icons/obj/flora/jungletrees.dmi index 461ac0b265..67c7e0f463 100644 Binary files a/icons/obj/flora/jungletrees.dmi and b/icons/obj/flora/jungletrees.dmi differ diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi index c0af32afea..c4713bd086 100644 Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ diff --git a/icons/obj/food/soupsalad.dmi b/icons/obj/food/soupsalad.dmi index fe4c07362a..c6df0a2603 100644 Binary files a/icons/obj/food/soupsalad.dmi and b/icons/obj/food/soupsalad.dmi differ diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi index d629cfe24d..5a8afeee51 100644 Binary files a/icons/obj/tiles.dmi and b/icons/obj/tiles.dmi differ diff --git a/icons/obj/vending_restock.dmi b/icons/obj/vending_restock.dmi index aa9f2873f0..eac7b8a266 100644 Binary files a/icons/obj/vending_restock.dmi and b/icons/obj/vending_restock.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index a1cd8fb2f9..28bc9e28d3 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/icons/turf/floors/junglechasm.dmi b/icons/turf/floors/junglechasm.dmi new file mode 100644 index 0000000000..699a3b667c Binary files /dev/null and b/icons/turf/floors/junglechasm.dmi differ diff --git a/config/admin_nicknames.txt b/strings/admin_nicknames.txt similarity index 100% rename from config/admin_nicknames.txt rename to strings/admin_nicknames.txt diff --git a/config/sillytips.txt b/strings/sillytips.txt similarity index 100% rename from config/sillytips.txt rename to strings/sillytips.txt diff --git a/config/tips.txt b/strings/tips.txt similarity index 100% rename from config/tips.txt rename to strings/tips.txt diff --git a/tgstation.dme b/tgstation.dme index 1f3ef27802..e10d48ca49 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -244,6 +244,7 @@ #include "code\datums\dog_fashion.dm" #include "code\datums\emotes.dm" #include "code\datums\forced_movement.dm" +#include "code\datums\holocall.dm" #include "code\datums\hud.dm" #include "code\datums\map_config.dm" #include "code\datums\martial.dm" @@ -2012,6 +2013,7 @@ #include "code\modules\shuttle\arrivals.dm" #include "code\modules\shuttle\assault_pod.dm" #include "code\modules\shuttle\computer.dm" +#include "code\modules\shuttle\elevator.dm" #include "code\modules\shuttle\emergency.dm" #include "code\modules\shuttle\ferry.dm" #include "code\modules\shuttle\manipulator.dm"