diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index 48ccd7f83e6..38453d4f526 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -2690,6 +2690,7 @@ "aZL" = (/obj/item/weapon/restraints/handcuffs/pinkcuffs,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/security/brig) "aZM" = (/obj/structure/stool/bed/chair,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/security/brig) "aZN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) +"aZO" = (/obj/machinery/firealarm{dir = 4; pixel_x = 24},/obj/item/weapon/twohanded/required/kirbyplants,/obj/structure/sign/bobross{pixel_y = 32},/turf/simulated/floor/wood,/area/crew_quarters/captain) "aZV" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor/wood,/area/crew_quarters/bar) "aZW" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4; level = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aZX" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1; initialize_directions = 11; level = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/junction{tag = "icon-pipe-j1 (EAST)"; icon_state = "pipe-j1"; dir = 4},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) @@ -3979,7 +3980,6 @@ "byW" = (/obj/machinery/ai_status_display{pixel_y = 32},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/carpet,/area/crew_quarters/captain) "byX" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/apc{cell_type = 5000; dir = 1; name = "north bump Important Area"; pixel_x = 0; pixel_y = 24},/turf/simulated/floor/wood,/area/crew_quarters/captain) "byY" = (/obj/machinery/status_display{pixel_x = 0; pixel_y = 32},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/turf/simulated/floor/carpet,/area/crew_quarters/captain) -"byZ" = (/obj/machinery/firealarm{dir = 4; pixel_x = 24},/obj/item/weapon/twohanded/required/kirbyplants,/turf/simulated/floor/wood,/area/crew_quarters/captain) "bza" = (/obj/structure/disposalpipe/segment,/obj/machinery/door/firedoor,/turf/simulated/floor/plasteel{dir = 8; icon_state = "bluecorner"},/area/hallway/primary/central/ne) "bzb" = (/obj/machinery/door/firedoor,/turf/simulated/floor/plasteel,/area/hallway/primary/central/ne) "bzc" = (/obj/structure/sign/directions/evac{dir = 4},/obj/structure/sign/directions/medical{dir = 4; pixel_y = 7},/obj/structure/sign/directions/science{dir = 4},/turf/simulated/wall,/area/crew_quarters/bar) @@ -9107,7 +9107,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrNbtvbtybtCbtDbtDbtzbtDbtDbtDbtzbrQaSdaSdaSdaToboRbqrbrUbtFbtGbrUbtBbtAbtHbtEbqrbtLbtMbtIblQblMbtObtPbtKbtJbtQbtNbtSbtRbtRbtRbtUbtTblMbnKbsdbtYbtZbtVbubblTblTblTblTblTbucbudbtWbufbugbnTbnObssbgSbgSbgSbtXbuebuabuibuhbujbqSbunbukbumbulbupbuoburbuqbutbusbuubuhbuwbuvbuybuxbuAbuzbuEbuEbuBbhqbuCaUSbmqbuDbuIbpKbmqbuFbuGbmqbuHbuMbpKbmqbogbofbofbofboibofbuJbofbsWbrobuKbebbuPbrrboBboAboAboBbrubuLbebbuNbuQbuObuSbuRbuUbuTbuWbuVbuVbuVbuVbuVbuVbuXbuZbuYboJboJboJboJboJboJbvdbvabvcbvbbjKbjKbjKbvebltbjKbvgbqnbwDbvhcUBbjRblDblAbeCblCbnbblAbeCblCbnbblAbeCblCblDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabvibvjbvjbvjbvjbvjbvjbvjbvjbvjbvjbvfbvlaOQbvlaSfboRbqrbvmbrUbvnbvnbvnbvkbrUbvobqrbvqbvrbtIbvsbvsbvsbvsbvpbvsbvtbnDbvvbvubvwbvwbvybvxblMbvzbvBbvAbvDbvCbvFbvGbvHbvIbvHbvJbvJbvJbvJbvJbvKbvEbnObvLbvNbvMbvPbvObvRbvQbvTbvSbuobvUbvVbvXbvXbvXbvXbvWbvXbvZbwabwbbvYbvUbwdbwcbmcbwebwgbwfbwibwhbwjbhqbhqbsNbmqbwkbmqbmqbmqaZVbmqbmqbwmbwmbmqbmqbwlbofbofbwnbwobofbofbofbwqbwpbwrbebbqabrrboBboBboBboBbrubwsbebbwtbwvbwvbwwbwvbwubljbljbljbljbwybljbljbljbwzbvaboJboJboJboJboJboJboJbvdbvabvcbvbbjKboMboMboNboMbjKbwxbjRbwBbwAbwCbjRbnbblAbeCblCbnbblAbeCblCbnbblAbeCblCbnbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwFbwEbwGbwHbwIbwIbwJbwIbwIbwIbwJbrQaSdaSdaSdbwKblFbwLbrUbwMbvnbvnbvnbvkbwMbrUbqrbwNbwObtIbvsbwPbwQbwRbwSbvsbwUbwTbwVblMbwWbwXbwZbwYblMbnKbxabxbbxbbxcbxbbxbbxbbxbbxebxdbxdbxdbxfbxdbxgbxhbxibxjbxkbxlbxlbxlbxlbxlbxmbxmbxnbxmbvXbvXbxobxpbxqbxrbxtbxsbxobxubvXbxvbxwbxvbxvbxvbxvbxvbxvbxvbwjbhqbhqaUSbxxbmqbxybxzbmqbxAbmqbxBbxDbxCbmqbxEbdTbxFbxGbdTbdTbxHbxJbxIbxJbdTbdTbebblbbxLbxMbxMbxMbxMbxLbxNbebbxObwvbwvbwwbxPbaubxQbxRbxSbxTbxUbxVbxWbxXbxYaYPbxZbcDbyaboJboJbyabcDbybaYPbycbvbbjKbqlbqlbqmbqlbjKbvgbqnbwDbvhcUBbjRbqoblAbeCblCbqoblAbeCblCbqoblAbeCblCbqoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwFbrObrObrQbrObrObrObrRbrObrObydaabaSdbyebndbyfbqrbtFbtFbtFbrUbyhbygbyjbyibqrbykbylbtIbvsbymbvsbynbyobvsbyqbypbyrblMbwWbwXbwZbskblMbnKbxabxbbytbysbyubyvbywbxbbyybyxbyAbyzbyBbyBbyBbyCbyEbyDbyFbxlbyGbyHbyIbyJbyLbyKbyMbyNbvXbyObxqbxqbyPbyQbyPbxqbxqbyRbvXbySbyUbyTbyWbyVbyYbyXbyZbxvbzabzbbzbbzcaUSaUSaUSaUSbzdbsNbzdbzeaUSbdRaUSaUSbdTbdTbdTbdTbzgbzfbzfbzfbzfbzhbzibebbjBbzjbjBbzkbzkbjBbzjbjBbebbxObwvbwvbzlbxPbaubaubaubaubaubtfbaubaubaubauaYPaYOaYQaYQaYQaYQaYQaYQaYPaYPbznbzmbzobxKbjKbjMbjKbjKbzpbjRbjRbjRbjRbqnbicbzqbeCbeCbeCbeCbeCbeCbeCbeCbeCbeCbicaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwFbrObrObrQbrObrObrObrRbrObrObydaabaSdbyebndbyfbqrbtFbtFbtFbrUbyhbygbyjbyibqrbykbylbtIbvsbymbvsbynbyobvsbyqbypbyrblMbwWbwXbwZbskblMbnKbxabxbbytbysbyubyvbywbxbbyybyxbyAbyzbyBbyBbyBbyCbyEbyDbyFbxlbyGbyHbyIbyJbyLbyKbyMbyNbvXbyObxqbxqbyPbyQbyPbxqbxqbyRbvXbySbyUbyTbyWbyVbyYbyXaZObxvbzabzbbzbbzcaUSaUSaUSaUSbzdbsNbzdbzeaUSbdRaUSaUSbdTbdTbdTbdTbzgbzfbzfbzfbzfbzhbzibebbjBbzjbjBbzkbzkbjBbzjbjBbebbxObwvbwvbzlbxPbaubaubaubaubaubtfbaubaubaubauaYPaYOaYQaYQaYQaYQaYQaYQaYPaYPbznbzmbzobxKbjKbjMbjKbjKbzpbjRbjRbjRbjRbqnbicbzqbeCbeCbeCbeCbeCbeCbeCbeCbeCbeCbicaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabjQaLdaSdaSdaSdaMsaMsaMsaMsaMsaMsbzrbzsbqrbqrbqrbqrbqrbqrbztbqrbqrbqrbnKbnKbzwbvsbzubzvbynbzxbvsbzzbzybzAblMbwWbwXbwZbnDblMbnKbxabxbbzDbzBbzCbyvbzCbxbbyybzGbzEbzFbzIbzHbzKbzJbzMbzLbyFbzRbzNbzObzPbzQbzQbzPbzUbzSbvXbzTbxqbxqbyPbzWbyPbxqbxqbzVbwbbzXbAbbzYbzZbAabAdbzYbAcbxvbAlbAebAfbAgbAhbAibAjbAkbAkbAkbAkbAkbAkbAmbAobAnbAkbAkbAqbAkbAkbAkbAkbAkbAkbAkbAkbApbAsbArbArbArbArbArbArbAtbAibAubAvbAvbAxbAwbAybAwbAzbAwbABbAAbACbAwbAFbADbAEbAHbAGbAGbAGbAGbAGbAGbAGbAIbALbAJbAJbAKbAJbBObjKbjKbrIbAMboIbANbrMboIbAObeCbeCbeCbeCbAPbeCbAPbeCbeCbeCbeCaYUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabAQbARbARbARbARbASbASbARbARbATaaaaabaSdaUkaSgbAVbAUbAXbAWbAWbAWbAWbAYbAZbBablQbnwbBcbBbbvsbvsbvsbBdbyobvsblMblMblMblMbwWbBebBgbBfblMbBhbBibxbbBjbBkbyvbzCbBlbxbbyybBmbzEbzFbBnbBobBpbzJbBqbzLbyFbzRbBrbBsbBtbBubBvbBwbzUbBxbvXbBybyPbxqbBAbBzbBAbxqbyPbBBbxubBCbzYbzYbzZbBDbAdbzYbBEbxvbBFbAfbAfbAgbAhbAibAkbAkbAkbAkbAkbAkbAkbBGbAkbAkbAkbAkbAkbAkbBHbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBIbBJbBKbBLbAGbAGbBMbwvbwvbwvbwvbwvbwwbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbBNbwvbDobBPbjKbjKbBQbjKbjKbjKbjKbBUbjRbqnbjRbjRbjRbqpbjCbBWbBVbjCbBXaYUbBXaYUbBYbBRbBSbicaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabCabCdbCcbBZbCebCbbCbbClbCibARbATaSdaSdaSdaTobCnbCfbCgbCfbCfbCfbCfbChbCtbCjblQblQbCkbCwbvsbwPbCmbCxbzxbvsbCobCpbCoblMblMblMblMbCqblMbCrbCsbxbbCybCubzCbCvbCzbxbbyybzJbCBbzFbBnbBnbCEbzJbCFbzLbyFbzRbCAbBsbBtbCGbCCbBwbzUbCDbvXbCHbCIbxqbCKbCJbCLbxqbCRbCNbCSbCMbCTbCObCPbCQbCUbzYbCVbxvbCYbCXbAfbAgbAhbAibAkbCZbAkbAkbAkbAkbCWbDbbDbbDbbDbbDcbAkbAkbAkbAkbDdbAkbCZbDabAkbAkbDebDgbDfbDhbDibDibDlbDjbDnbDmbwvbwvbwvbwvbwvbwvbwvbDkbDpbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbwvbDrbDqbDqbDsbDubDtbDxbDvbDvbDybDAbEHbmZbAMboIbrMbrMboIbDBdsldsldsldsnbicaaabicbDDbDwbDwbDFbicaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 499be494056..40f27d0d84f 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -63,13 +63,21 @@ #define THROWN_PROJECTILE_ATTACK 4 #define LEAP_ATTACK 5 +//Embedded objects +#define EMBEDDED_PAIN_CHANCE 15 //Chance for embedded objects to cause pain (damage user) +#define EMBEDDED_ITEM_FALLOUT 5 //Chance for embedded object to fall out (causing pain but removing the object) +#define EMBED_CHANCE 45 //Chance for an object to embed into somebody when thrown (if it's sharp) +#define EMBEDDED_PAIN_MULTIPLIER 2 //Coefficient of multiplication for the damage the item does while embedded (this*item.w_class) +#define EMBEDDED_FALL_PAIN_MULTIPLIER 5 //Coefficient of multiplication for the damage the item does when it falls out (this*item.w_class) +#define EMBEDDED_IMPACT_PAIN_MULTIPLIER 4 //Coefficient of multiplication for the damage the item does when it first embeds (this*item.w_class) +#define EMBED_THROWSPEED_THRESHOLD 4 //The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1) +#define EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER 8 //Coefficient of multiplication for the damage the item does when removed without a surgery (this*item.w_class) +#define EMBEDDED_UNSAFE_REMOVAL_TIME 30 //A Time in ticks, total removal time = (this*item.w_class) + //Gun Stuff #define SAWN_INTACT 0 #define SAWN_OFF 1 #define WEAPON_LIGHT 0 #define WEAPON_MEDIUM 1 - #define WEAPON_HEAVY 2 - -// Embedded objects -#define EMBED_THROWSPEED_THRESHOLD 15 \ No newline at end of file + #define WEAPON_HEAVY 2 \ No newline at end of file diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index a27e3f8e96a..d708813b139 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -2,9 +2,19 @@ #define isatom(A) istype(A, /atom) #define ismovableatom(A) istype(A, /atom/movable) -// Mobs +// Mobs #define ismegafauna(A) istype(A, /mob/living/simple_animal/hostile/megafauna) +//Objects + +var/list/static/global/pointed_types = typecacheof(list( + /obj/item/weapon/pen, + /obj/item/weapon/screwdriver, + /obj/item/weapon/reagent_containers/syringe, + /obj/item/weapon/kitchen/utensil/fork)) + +#define is_pointed(W) (is_type_in_typecache(W, pointed_types)) + //Turfs #define issimulatedturf(A) istype(A, /turf/simulated) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 89755d7acf0..f9bae78c35b 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -448,32 +448,32 @@ proc/checkhtml(var/t) // Pencode -/proc/pencode_to_html(text, mob/user, obj/item/weapon/pen/P = null, sign = 1, fields = 1, deffont = PEN_FONT, signfont = SIGNFONT, crayonfont = CRAYON_FONT) - text = replacetext(text, "\n", "
") - text = replacetext(text, "\[center\]", "
") - text = replacetext(text, "\[/center\]", "
") - text = replacetext(text, "\[br\]", "
") +/proc/pencode_to_html(text, mob/user, obj/item/weapon/pen/P = null, format = 1, sign = 1, fields = 1, deffont = PEN_FONT, signfont = SIGNFONT, crayonfont = CRAYON_FONT) text = replacetext(text, "\[b\]", "") text = replacetext(text, "\[/b\]", "") text = replacetext(text, "\[i\]", "") text = replacetext(text, "\[/i\]", "") text = replacetext(text, "\[u\]", "") text = replacetext(text, "\[/u\]", "") - text = replacetext(text, "\[large\]", "") - text = replacetext(text, "\[/large\]", "") if(sign) text = replacetext(text, "\[sign\]", "[user ? user.real_name : "Anonymous"]") if(fields) text = replacetext(text, "\[field\]", "") + if(format) + text = replacetext(text, "\[h1\]", "

") + text = replacetext(text, "\[/h1\]", "

") + text = replacetext(text, "\[h2\]", "

") + text = replacetext(text, "\[/h2\]", "

") + text = replacetext(text, "\[h3\]", "

") + text = replacetext(text, "\[/h3\]", "

") + text = replacetext(text, "\n", "
") + text = replacetext(text, "\[center\]", "
") + text = replacetext(text, "\[/center\]", "
") + text = replacetext(text, "\[br\]", "
") + text = replacetext(text, "\[large\]", "") + text = replacetext(text, "\[/large\]", "") - text = replacetext(text, "\[h1\]", "

") - text = replacetext(text, "\[/h1\]", "

") - text = replacetext(text, "\[h2\]", "

") - text = replacetext(text, "\[/h2\]", "

") - text = replacetext(text, "\[h3\]", "

") - text = replacetext(text, "\[/h3\]", "

") - - if(istype(P, /obj/item/toy/crayon)) // If it is a crayon, and he still tries to use these, make them empty! + if(istype(P, /obj/item/toy/crayon) || !format) // If it is a crayon, and he still tries to use these, make them empty! text = replacetext(text, "\[*\]", "") text = replacetext(text, "\[hr\]", "") text = replacetext(text, "\[small\]", "") @@ -485,7 +485,7 @@ proc/checkhtml(var/t) text = replacetext(text, "\[row\]", "") text = replacetext(text, "\[cell\]", "") text = replacetext(text, "\[logo\]", "") - + if(istype(P, /obj/item/toy/crayon)) text = "[text]" else // They are using "not a crayon" - formatting is OK and such text = replacetext(text, "\[*\]", "
  • ") @@ -501,9 +501,10 @@ proc/checkhtml(var/t) text = replacetext(text, "\[row\]", "") text = replacetext(text, "\[cell\]", "") text = replacetext(text, "\[logo\]", "") - + if(P) text = "[text]" - + else + text = "[text]" text = copytext(text, 1, MAX_PAPER_MESSAGE_LEN) return text diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 82b2ea8b419..c90db77effb 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1081,6 +1081,21 @@ proc/get_mob_with_client_list() return get_turf(location) +//For objects that should embed, but make no sense being is_sharp or is_pointed() +//e.g: rods +var/list/can_embed_types = typecacheof(list( + /obj/item/stack/rods, + /obj/item/pipe)) + +/proc/can_embed(obj/item/W) + if(is_sharp(W)) + return 1 + if(is_pointed(W)) + return 1 + + if(is_type_in_typecache(W, can_embed_types)) + return 1 + //Quick type checks for some tools var/global/list/common_tools = list( /obj/item/stack/cable_coil, @@ -1199,22 +1214,6 @@ var/global/list/common_tools = list( if(O.edge) return 1 return 0 -//Returns 1 if the given item is capable of popping things like balloons, inflatable barriers, or cutting police tape. -/proc/can_puncture(obj/item/W as obj) // For the record, WHAT THE HELL IS THIS METHOD OF DOING IT? - if(!istype(W)) return 0 - if(!W) return 0 - if(W.sharp) return 1 - return ( \ - W.sharp || \ - istype(W, /obj/item/weapon/screwdriver) || \ - istype(W, /obj/item/weapon/pen) || \ - istype(W, /obj/item/weapon/weldingtool) || \ - istype(W, /obj/item/weapon/lighter/zippo) || \ - istype(W, /obj/item/weapon/match) || \ - istype(W, /obj/item/clothing/mask/cigarette) || \ - istype(W, /obj/item/weapon/shovel) \ - ) - /proc/is_surgery_tool(obj/item/W as obj) return ( \ istype(W, /obj/item/weapon/scalpel) || \ @@ -1891,4 +1890,4 @@ var/global/list/g_fancy_list_of_types = null var/num = pick(num_sample) num_sample -= num result += (1 << num) - return result + return result diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index e453d748428..5e7fb5d0bd3 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -42,4 +42,4 @@ var/global/list/global_radios = list() //list of all radios, across all z-lev var/global/list/meteor_list = list() //list of all meteors var/global/list/poi_list = list() //list of points of interest for observe/follow - +var/global/list/active_jammers = list() // List of active radio jammers diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index e969751e1dd..51afe833ea3 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -199,6 +199,11 @@ Topic(src, list("src" = UID(), "command"="lights", "activate" = "0"), 1) return +/obj/machinery/ai_slipper/AICtrlClick() //Turns liquid dispenser on or off + ToggleOn() + +/obj/machinery/ai_slipper/AIAltClick() //Dispenses liquid if on + Activate() // // Override AdjacentQuick for AltClicking diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index a15176af87c..a8de6127c41 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -169,6 +169,12 @@ /obj/machinery/turretid/BorgAltClick() //turret lethal on/off. Forwards to AI code. AIAltClick() +/obj/machinery/ai_slipper/BorgCtrlClick() //Turns liquid dispenser on or off + ToggleOn() + +/obj/machinery/ai_slipper/BorgAltClick() //Dispenses liquid if on + Activate() + /* As with AI, these are not used in click code, because the code for robots is specific, not generic. diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 5ebe1f9ac6d..1d5d419ba82 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -235,6 +235,12 @@ or something covering your eyes." desc = "All that alcohol you've been drinking is impairing your speech, motor skills, and mental cognition. Make sure to act like it." icon_state = "drunk" +/obj/screen/alert/embeddedobject + name = "Embedded Object" + desc = "Something got lodged into your flesh and is causing major bleeding. It might fall out with time, but surgery is the safest way. \ + If you're feeling frisky, click yourself in help intent to pull the object out." + icon_state = "embeddedobject" + /obj/screen/alert/embeddedobject/Click() if(isliving(usr)) var/mob/living/carbon/human/M = usr diff --git a/code/datums/spells/summonitem.dm b/code/datums/spells/summonitem.dm index 32472fe1ec0..7524e7f31d6 100644 --- a/code/datums/spells/summonitem.dm +++ b/code/datums/spells/summonitem.dm @@ -79,6 +79,14 @@ add_logs(target, C, "magically debrained", addition="INTENT: [uppertext(target.a_intent)]")*/ if(C.stomach_contents && item_to_retrive in C.stomach_contents) C.stomach_contents -= item_to_retrive + for(var/X in C.bodyparts) + var/obj/item/organ/external/part = X + if(item_to_retrive in part.embedded_objects) + part.embedded_objects -= item_to_retrive + to_chat(C, "The [item_to_retrive] that was embedded in your [part] has mysteriously vanished. How fortunate!") + if(!C.has_embedded_objects()) + C.clear_alert("embeddedobject") + break else if(istype(item_to_retrive.loc,/obj/machinery/portable_atmospherics/)) //Edge cases for moved machinery diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index ef3b4a4e278..14732318aab 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -332,7 +332,7 @@ var/list/uplink_items = list() reference = "TPB" item = /obj/item/weapon/reagent_containers/glass/bottle/traitor cost = 2 - job = list("Research Director", "Chief Medical Officer", "Medical Doctor", "Psychiatrist", "Paramedic", "Virologist", "Bartender", "Chef") + job = list("Research Director", "Chief Medical Officer", "Medical Doctor", "Psychiatrist", "Chemist", "Paramedic", "Virologist", "Bartender", "Chef") // Paper contact poison pen @@ -737,6 +737,14 @@ var/list/uplink_items = list() cost = 17 excludefrom = list(/datum/game_mode/nuclear) +/datum/uplink_item/stealthy_weapons/throwingweapons + name = "Box of Throwing Weapons" + desc = "A box of shurikens and reinforced bolas from ancient Earth martial arts. They are highly effective \ + throwing weapons. The bolas can knock a target down and the shurikens will embed into limbs." + reference = "STK" + item = /obj/item/weapon/storage/box/syndie_kit/throwing_weapons + cost = 3 + /datum/uplink_item/stealthy_weapons/edagger name = "Energy Dagger" desc = "A dagger made of energy that looks and functions as a pen when off." @@ -1116,6 +1124,13 @@ var/list/uplink_items = list() cost = 1 surplus = 0 +/datum/uplink_item/device_tools/jammer + name = "Radio Jammer" + desc = "This device will disrupt any nearby outgoing radio communication when activated." + reference = "RJ" + item = /obj/item/device/jammer + cost = 5 + /datum/uplink_item/device_tools/teleporter name = "Teleporter Circuit Board" desc = "A printed circuit board that completes the teleporter onboard the mothership. Advise you test fire the teleporter before entering it, as malfunctions can occur." diff --git a/code/datums/wires/syndicatebomb.dm b/code/datums/wires/syndicatebomb.dm index d1fe6217058..616429b8cd8 100644 --- a/code/datums/wires/syndicatebomb.dm +++ b/code/datums/wires/syndicatebomb.dm @@ -1,5 +1,5 @@ /datum/wires/syndicatebomb - random = 1 + random = TRUE holder_type = /obj/machinery/syndicatebomb wire_count = 5 @@ -13,83 +13,90 @@ var/const/WIRE_ACTIVATE = 16 // Will start a bombs timer if pulsed, will hint if switch(index) if(WIRE_BOOM) return "Explode" - + if(WIRE_UNBOLT) return "Unbolt" - + if(WIRE_DELAY) return "Delay" - + if(WIRE_PROCEED) return "Proceed" - + if(WIRE_ACTIVATE) return "Activate" /datum/wires/syndicatebomb/CanUse(mob/living/L) var/obj/machinery/syndicatebomb/P = holder if(P.open_panel) - return 1 - return 0 + return TRUE + return FALSE /datum/wires/syndicatebomb/UpdatePulsed(index) - var/obj/machinery/syndicatebomb/P = holder + var/obj/machinery/syndicatebomb/B = holder switch(index) if(WIRE_BOOM) - if(P.active) - P.loc.visible_message("[bicon(holder)] An alarm sounds! It's go-") - P.timer = 0 + if(B.active) + holder.visible_message("[bicon(B)] An alarm sounds! It's go-") + B.explode_now = TRUE if(WIRE_UNBOLT) - P.loc.visible_message("[bicon(holder)] The bolts spin in place for a moment.") + holder.visible_message("[bicon(holder)] The bolts spin in place for a moment.") if(WIRE_DELAY) - playsound(P.loc, 'sound/machines/chime.ogg', 30, 1) - P.loc.visible_message("[bicon(holder)] The bomb chirps.") - P.timer += 10 - if(WIRE_PROCEED) - playsound(P.loc, 'sound/machines/buzz-sigh.ogg', 30, 1) - P.loc.visible_message("[bicon(holder)] The bomb buzzes ominously!") - if(P.timer >= 61) //Long fuse bombs can suddenly become more dangerous if you tinker with them - P.timer = 60 - if(P.timer >= 21) - P.timer -= 10 - else if(P.timer >= 11) //both to prevent negative timers and to have a little mercy - P.timer = 10 - if(WIRE_ACTIVATE) - if(!P.active && !P.defused) - playsound(P.loc, 'sound/machines/click.ogg', 30, 1) - P.loc.visible_message("[bicon(holder)] You hear the bomb start ticking!") - P.active = 1 - P.icon_state = "[initial(P.icon_state)]-active[P.open_panel ? "-wires" : ""]" + if(B.delayedbig) + holder.visible_message("[bicon(B)] The bomb has already been delayed.") else - P.loc.visible_message("[bicon(holder)] The bomb seems to hesitate for a moment.") - P.timer += 5 + holder.visible_message("[bicon(B)] The bomb chirps.") + playsound(B, 'sound/machines/chime.ogg', 30, 1) + B.detonation_timer += 300 + B.delayedbig = TRUE + if(WIRE_PROCEED) + holder.visible_message("[bicon(B)] The bomb buzzes ominously!") + playsound(B, 'sound/machines/buzz-sigh.ogg', 30, 1) + var/seconds = B.seconds_remaining() + if(seconds >= 61) // Long fuse bombs can suddenly become more dangerous if you tinker with them. + B.detonation_timer = world.time + 600 + else if(seconds >= 21) + B.detonation_timer -= 100 + else if(seconds >= 11) // Both to prevent negative timers and to have a little mercy. + B.detonation_timer = world.time + 100 + if(WIRE_ACTIVATE) + if(!B.active && !B.defused) + holder.visible_message("[bicon(B)] You hear the bomb start ticking!") + B.activate() + B.update_icon() + else if(B.delayedlittle) + holder.visible_message("[bicon(B)] Nothing happens.") + else + holder.visible_message("[bicon(B)] The bomb seems to hesitate for a moment.") + B.detonation_timer += 100 + B.delayedlittle = TRUE ..() /datum/wires/syndicatebomb/UpdateCut(index, mended) - var/obj/machinery/syndicatebomb/P = holder + var/obj/machinery/syndicatebomb/B = holder switch(index) if(WIRE_EXPLODE) - if(!mended) - if(P.active) - P.loc.visible_message("[bicon(holder)] An alarm sounds! It's go-") - P.timer = 0 - else - P.defused = 1 + if(mended) + B.defused = FALSE // Cutting and mending all the wires of an inactive bomb will thus cure any sabotage. else - P.defused = 0 //cutting and mending all the wires of an inactive bomb will thus cure any sabotage + if(B.active) + holder.visible_message("[bicon(B)] An alarm sounds! It's go-") + B.explode_now = TRUE + else + B.defused = TRUE if(WIRE_UNBOLT) - if(!mended && P.anchored) - playsound(P.loc, 'sound/effects/stealthoff.ogg', 30, 1) - P.loc.visible_message("[bicon(holder)] The bolts lift out of the ground!") - P.anchored = 0 + if(!mended && B.anchored) + holder.visible_message("[bicon(B)] The bolts lift out of the ground!") + playsound(B, 'sound/effects/stealthoff.ogg', 30, 1) + B.anchored = FALSE if(WIRE_PROCEED) - if(!mended && P.active) - P.loc.visible_message("[bicon(holder)] An alarm sounds! It's go-") - P.timer = 0 + if(!mended && B.active) + holder.visible_message("[bicon(B)] An alarm sounds! It's go-") + B.explode_now = TRUE if(WIRE_ACTIVATE) - if(!mended && P.active) - P.loc.visible_message("[bicon(holder)] The timer stops! The bomb has been defused!") - P.icon_state = "[initial(P.icon_state)]-inactive[P.open_panel ? "-wires" : ""]" - P.active = 0 - P.defused = 1 + if(!mended && B.active) + holder.visible_message("[bicon(B)] The timer stops! The bomb has been defused!") + B.active = FALSE + B.defused = TRUE + B.update_icon() ..() \ No newline at end of file diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 2a6aa2b3a39..5d6b9da47bc 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -190,7 +190,7 @@ /mob/living/carbon/human/proc/sec_hud_set_security_status() var/image/holder = hud_list[WANTED_HUD] - var/perpname = get_face_name(get_id_name("")) + var/perpname = get_visible_name(TRUE) //gets the name of the perp, works if they have an id or if their face is uncovered if(!ticker) return //wait till the game starts or the monkeys runtime.... if(perpname) var/datum/data/record/R = find_record("name", perpname, data_core.security) diff --git a/code/game/dna/genes/goon_powers.dm b/code/game/dna/genes/goon_powers.dm index 52b62f6cabf..194a82f0001 100644 --- a/code/game/dna/genes/goon_powers.dm +++ b/code/game/dna/genes/goon_powers.dm @@ -414,9 +414,6 @@ else M.stop_pulling() - if(user.pinned.len) - failure = 1 - user.visible_message("[user.name] takes a huge leap!") playsound(user.loc, 'sound/weapons/thudswoosh.ogg', 50, 1) if(failure) diff --git a/code/game/dna/genes/vg_powers.dm b/code/game/dna/genes/vg_powers.dm index e159aa44247..32a6a58cbb3 100644 --- a/code/game/dna/genes/vg_powers.dm +++ b/code/game/dna/genes/vg_powers.dm @@ -211,11 +211,11 @@ /obj/effect/proc_holder/spell/targeted/remotetalk/choose_targets(mob/user = usr) var/list/targets = new /list() var/list/validtargets = new /list() - for(var/mob/M in view(user.client.view, user)) + var/turf/T = get_turf(user) + for(var/mob/M in range(14, T)) if(M && M.mind) if(M == user) continue - validtargets += M if(!validtargets.len) @@ -237,14 +237,15 @@ if(!say) return say = strip_html(say) + say = pencode_to_html(say, usr, format = 0, fields = 0) for(var/mob/living/target in targets) log_say("Project Mind: [key_name(user)]->[key_name(target)]: [say]") if(REMOTE_TALK in target.mutations) - target.show_message("You hear [user.real_name]'s voice: [say]") + target.show_message("You hear [user.real_name]'s voice: [say]") else - target.show_message("You hear a voice that seems to echo around the room: [say]") - user.show_message("You project your mind into [target.real_name]: [say]") + target.show_message("You hear a voice that seems to echo around the room: [say]") + user.show_message("You project your mind into [target.name]: [say]") for(var/mob/dead/observer/G in player_list) G.show_message("Telepathic message from [user] ([ghost_follow_link(user, ghost=G)]) to [target] ([ghost_follow_link(target, ghost=G)]): [say]") diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm index 5fd98986332..9077f623a2c 100644 --- a/code/game/gamemodes/changeling/powers/revive.dm +++ b/code/game/gamemodes/changeling/powers/revive.dm @@ -39,10 +39,6 @@ var/obj/item/organ/external/O = H.bodyparts_by_name[organ_name] if(!O) continue - for(var/obj/item/weapon/shard/shrapnel/s in O.implants) - O.implants -= s - H.contents -= s - qdel(s) O.brute_dam = 0 O.burn_dam = 0 O.damage_state = "00" @@ -58,6 +54,7 @@ for(var/obj/item/organ/internal/IO in H.internal_organs) IO.damage = 0 IO.trace_chemicals.Cut() + H.remove_all_embedded_objects() H.updatehealth() to_chat(user, "We have regenerated.") diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 97511414e7a..bf2c692a0c0 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -41,6 +41,7 @@ w_class = WEIGHT_CLASS_SMALL force = 15 throwforce = 25 + embed_chance = 75 var/cooldown = 0 /obj/item/weapon/melee/cultblade/dagger/afterattack(mob/living/target as mob, mob/living/carbon/human/user as mob) diff --git a/code/game/gamemodes/miniantags/borer/borer.dm b/code/game/gamemodes/miniantags/borer/borer.dm index a9975618435..a98090d186a 100644 --- a/code/game/gamemodes/miniantags/borer/borer.dm +++ b/code/game/gamemodes/miniantags/borer/borer.dm @@ -361,11 +361,6 @@ host = M forceMove(M) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/head = H.get_organ("head") - head.implants += src - host.status_flags |= PASSEMOTES RemoveBorerActions() @@ -746,11 +741,6 @@ controlling = FALSE - if(ishuman(host)) - var/mob/living/carbon/human/H = host - var/obj/item/organ/external/head = H.get_organ("head") - head.implants -= src - reset_perspective(null) machine = null diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 4f9af54457c..faef00612ca 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -780,7 +780,7 @@ var/global/list/multiverse = list() to_chat(target, "You suddenly feel very hot") target.bodytemperature += 50 GiveHint(target) - else if(can_puncture(I)) + else if(is_pointed(I)) to_chat(target, "You feel a stabbing pain in [parse_zone(user.zone_sel.selecting)]!") target.Weaken(2) GiveHint(target) diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 41dc37ab43f..6d7264e9256 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -398,7 +398,7 @@ organData["broken"] = E.min_broken_damage var/shrapnelData[0] - for(var/obj/I in E.implants) + for(var/obj/I in E.embedded_objects) var/shrapnelSubData[0] shrapnelSubData["name"] = I.name @@ -605,7 +605,7 @@ infected = "Septic:" var/unknown_body = 0 - for(var/I in e.implants) + for(var/I in e.embedded_objects) unknown_body++ if(unknown_body || e.hidden) diff --git a/code/game/machinery/ai_slipper.dm b/code/game/machinery/ai_slipper.dm index 4d059043329..63aeee28b2f 100644 --- a/code/game/machinery/ai_slipper.dm +++ b/code/game/machinery/ai_slipper.dm @@ -5,12 +5,12 @@ layer = 3 anchored = 1.0 var/uses = 20 - var/disabled = 1 + var/disabled = TRUE var/lethal = 0 - var/locked = 1 + var/locked = TRUE var/cooldown_time = 0 var/cooldown_timeleft = 0 - var/cooldown_on = 0 + var/cooldown_on = FALSE req_access = list(access_ai_upload) /obj/machinery/ai_slipper/power_change() @@ -22,6 +22,7 @@ else icon_state = "motion0" stat |= NOPOWER + disabled = TRUE /obj/machinery/ai_slipper/proc/setState(var/enabled, var/uses) disabled = disabled @@ -49,6 +50,24 @@ return return +/obj/machinery/ai_slipper/proc/ToggleOn() + if(stat & (NOPOWER|BROKEN)) + return + disabled = !disabled + icon_state = disabled? "motion0":"motion3" + +/obj/machinery/ai_slipper/proc/Activate() + if(stat & (NOPOWER|BROKEN)) + return + if(cooldown_on || disabled) + return + else + new /obj/structure/foam(loc) + uses-- + cooldown_on = TRUE + cooldown_time = world.timeofday + 100 + slip_process() + /obj/machinery/ai_slipper/attack_ai(mob/user) return attack_hand(user) @@ -87,18 +106,10 @@ return 1 if(href_list["toggleOn"]) - disabled = !disabled - icon_state = disabled? "motion0":"motion3" + ToggleOn() + if(href_list["toggleUse"]) - if(cooldown_on || disabled) - return - else - new /obj/structure/foam(loc) - uses-- - cooldown_on = 1 - cooldown_time = world.timeofday + 100 - slip_process() - return + Activate() attack_hand(usr) @@ -115,5 +126,5 @@ if(uses <= 0) return if(uses >= 0) - cooldown_on = 0 + cooldown_on = FALSE power_change() \ No newline at end of file diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index 10f6fc1c8c5..153fc50bf91 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -1,3 +1,6 @@ +#define BUTTON_COOLDOWN 60 // cant delay the bomb forever +#define BUTTON_DELAY 50 //five seconds + /obj/machinery/syndicatebomb icon = 'icons/obj/assemblies.dmi' name = "syndicate bomb" @@ -6,71 +9,119 @@ anchored = 0 density = 0 - layer = MOB_LAYER - 0.1 //so people can't hide it and it's REALLY OBVIOUS + layer = BELOW_MOB_LAYER //so people can't hide it and it's REALLY OBVIOUS unacidable = 1 var/datum/wires/syndicatebomb/wires = null - var/timer = 120 - var/open_panel = 0 //are the wires exposed? - var/active = 0 //is the bomb counting down? - var/defused = 0 //is the bomb capable of exploding? - var/obj/item/weapon/bombcore/payload = /obj/item/weapon/bombcore/ + var/minimum_timer = 90 + var/timer_set = 90 + var/maximum_timer = 60000 + + var/can_unanchor = TRUE + + var/open_panel = FALSE //are the wires exposed? + var/active = FALSE //is the bomb counting down? + var/defused = FALSE //is the bomb capable of exploding? + var/obj/item/weapon/bombcore/payload = /obj/item/weapon/bombcore var/beepsound = 'sound/items/timer.ogg' + var/delayedbig = FALSE //delay wire pulsed? + var/delayedlittle = FALSE //activation wire pulsed? + var/obj/effect/countdown/syndicatebomb/countdown + + var/next_beep + var/detonation_timer + var/explode_now = FALSE + +/obj/machinery/syndicatebomb/proc/try_detonate(ignore_active = FALSE) + . = (payload in src) && (active || ignore_active) && !defused + if(.) + payload.detonate() /obj/machinery/syndicatebomb/process() - if(active && !defused && (timer > 0)) //Tick Tock - var/volume = (timer <= 20 ? 40 : 10) // Tick louder when the bomb is closer to being detonated. - playsound(loc, beepsound, volume, 0) - timer = max(timer - 2,0) // 2 seconds per process() - if(active && !defused && (timer <= 0)) //Boom - active = 0 - timer = 120 - update_icon() - if(payload in src) - payload.detonate() + if(!active) + fast_processing -= src + detonation_timer = null + next_beep = null + countdown.stop() return - if(!active || defused) //Counter terrorists win + + if(!isnull(next_beep) && (next_beep <= world.time)) + var/volume + switch(seconds_remaining()) + if(0 to 5) + volume = 50 + if(5 to 10) + volume = 40 + if(10 to 15) + volume = 30 + if(15 to 20) + volume = 20 + if(20 to 25) + volume = 10 + else + volume = 5 + playsound(loc, beepsound, volume, 0) + next_beep = world.time + 10 + + if(active && !defused && ((detonation_timer <= world.time) || explode_now)) + active = FALSE + timer_set = initial(timer_set) + update_icon() + try_detonate(TRUE) + //Counter terrorists win + else if(!active || defused) if(defused && payload in src) payload.defuse() - return + countdown.stop() + fast_processing -= src /obj/machinery/syndicatebomb/New() wires = new(src) - payload = new payload(src) + if(payload) + payload = new payload(src) update_icon() + countdown = new(src) ..() /obj/machinery/syndicatebomb/Destroy() QDEL_NULL(wires) + QDEL_NULL(countdown) + fast_processing -= src return ..() /obj/machinery/syndicatebomb/examine(mob/user) ..(user) - to_chat(user, "A digital display on it reads \"[timer]\".") + to_chat(user, "A digital display on it reads \"[seconds_remaining()]\".") /obj/machinery/syndicatebomb/update_icon() icon_state = "[initial(icon_state)][active ? "-active" : "-inactive"][open_panel ? "-wires" : ""]" -/obj/machinery/syndicatebomb/attackby(var/obj/item/I, var/mob/user, params) - if(istype(I, /obj/item/weapon/wrench)) +/obj/machinery/syndicatebomb/proc/seconds_remaining() + if(active) + . = max(0, round((detonation_timer - world.time) / 10)) + else + . = timer_set + +/obj/machinery/syndicatebomb/attackby(obj/item/I, mob/user, params) + if(iswrench(I) && can_unanchor) if(!anchored) - if(!isturf(src.loc) || istype(src.loc, /turf/space)) - to_chat(user, "The bomb must be placed on solid ground to attach it") + if(!isturf(loc) || isspaceturf(loc)) + to_chat(user, "The bomb must be placed on solid ground to attach it.") else - to_chat(user, "You firmly wrench the bomb to the floor") + to_chat(user, "You firmly wrench the bomb to the floor.") playsound(loc, I.usesound, 50, 1) anchored = 1 if(active) - to_chat(user, "The bolts lock in place") + to_chat(user, "The bolts lock in place.") else if(!active) - to_chat(user, "You wrench the bomb from the floor") + to_chat(user, "You wrench the bomb from the floor.") playsound(loc, I.usesound, 50, 1) anchored = 0 else to_chat(user, "The bolts are locked down!") - else if(istype(I, /obj/item/weapon/screwdriver)) + else if(isscrewdriver(I)) open_panel = !open_panel update_icon() to_chat(user, "You [open_panel ? "open" : "close"] the wire panel.") @@ -79,28 +130,47 @@ if(open_panel) wires.Interact(user) - else if(istype(I, /obj/item/weapon/crowbar)) - if(open_panel && isWireCut(WIRE_BOOM) && isWireCut(WIRE_UNBOLT) && isWireCut(WIRE_DELAY) && isWireCut(WIRE_PROCEED) && isWireCut(WIRE_ACTIVATE)) + else if(iscrowbar(I)) + if(open_panel && wires.IsAllCut()) if(payload) to_chat(user, "You carefully pry out [payload].") payload.loc = user.loc payload = null else - to_chat(user, "There isn't anything in here to remove!") + to_chat(user, "There isn't anything in here to remove!") else if(open_panel) - to_chat(user, "The wires connecting the shell to the explosives are holding it down!") + to_chat(user, "The wires connecting the shell to the explosives are holding it down!") else - to_chat(user, "The cover is screwed on, it won't pry off!") + to_chat(user, "The cover is screwed on, it won't pry off!") else if(istype(I, /obj/item/weapon/bombcore)) if(!payload) + if(!user.drop_item()) + return payload = I to_chat(user, "You place [payload] into [src].") - user.drop_item() - payload.loc = src + payload.forceMove(src) else to_chat(user, "[payload] is already loaded into [src], you'll have to remove it first.") + else if(iswelder(I)) + if(payload || !wires.IsAllCut() || !open_panel) + return + var/obj/item/weapon/weldingtool/WT = I + if(!WT.isOn()) + return + if(WT.get_fuel() < 5) //uses up 5 fuel. + to_chat(user, "You need more fuel to complete this task!") + return + + playsound(loc, WT.usesound, 50, 1) + to_chat(user, "You start to cut the [src] apart...") + if(do_after(user, 20*I.toolspeed, target = src)) + if(!WT.isOn() || !WT.remove_fuel(5, user)) + return + to_chat(user, "You cut the [src] apart.") + new /obj/item/stack/sheet/plasteel(loc, 5) + qdel(src) else - ..() + return ..() /obj/machinery/syndicatebomb/attack_ghost(mob/user) interact(user) @@ -133,21 +203,27 @@ return FALSE return TRUE +/obj/machinery/syndicatebomb/proc/activate() + active = TRUE + fast_processing += src + countdown.start() + next_beep = world.time + 10 + detonation_timer = world.time + (timer_set * 10) + playsound(loc, 'sound/machines/click.ogg', 30, 1) + /obj/machinery/syndicatebomb/proc/settings(mob/user) - var/newtime = input(user, "Please set the timer.", "Timer", "[timer]") as num - newtime = Clamp(newtime, 120, 60000) + var/new_timer = input(user, "Please set the timer.", "Timer", "[timer_set]") as num if(can_interact(user)) //No running off and setting bombs from across the station - timer = newtime - loc.visible_message("[bicon(src)] timer set for [timer] seconds.") + timer_set = Clamp(new_timer, minimum_timer, maximum_timer) + loc.visible_message("[bicon(src)] timer set for [timer_set] seconds.") if(alert(user,"Would you like to start the countdown now?",,"Yes","No") == "Yes" && can_interact(user)) if(defused || active) if(defused) loc.visible_message("[bicon(src)] Device error: User intervention required.") return else - loc.visible_message("[bicon(src)] [timer] seconds until detonation, please clear the area.") - playsound(loc, 'sound/machines/click.ogg', 30, 1) - active = 1 + loc.visible_message("[bicon(src)] [timer_set] seconds until detonation, please clear the area.") + activate() update_icon() add_fingerprint(user) @@ -167,12 +243,12 @@ name = "training bomb" icon_state = "training-bomb" desc = "A salvaged syndicate device gutted of its explosives to be used as a training aid for aspiring bomb defusers." - payload = /obj/item/weapon/bombcore/training/ + payload = /obj/item/weapon/bombcore/training /obj/machinery/syndicatebomb/badmin name = "generic summoning badmin bomb" desc = "Oh god what is in this thing?" - payload = /obj/item/weapon/bombcore/badmin/summon/ + payload = /obj/item/weapon/bombcore/badmin/summon /obj/machinery/syndicatebomb/badmin/clown name = "clown bomb" @@ -181,8 +257,23 @@ payload = /obj/item/weapon/bombcore/badmin/summon/clown beepsound = 'sound/items/bikehorn.ogg' -/obj/machinery/syndicatebomb/badmin/varplosion - payload = /obj/item/weapon/bombcore/badmin/explosion/ +/obj/machinery/syndicatebomb/empty + name = "bomb" + icon_state = "base-bomb" + desc = "An ominous looking device designed to detonate an explosive payload. Can be bolted down using a wrench." + payload = null + open_panel = TRUE + timer_set = 120 + +/obj/machinery/syndicatebomb/empty/New() + ..() + wires.CutAll() + +/obj/machinery/syndicatebomb/self_destruct + name = "self destruct device" + desc = "Do not taunt. Warranty invalid if exposed to high temperature. Not suitable for agents under 3 years of age." + payload = /obj/item/weapon/bombcore/large + can_unanchor = FALSE ///Bomb Cores/// @@ -196,17 +287,26 @@ origin_tech = "syndicate=5;combat=6" burn_state = FLAMMABLE //Burnable (but the casing isn't) var/adminlog = null + var/range_heavy = 3 + var/range_medium = 9 + var/range_light = 17 + var/range_flame = 17 /obj/item/weapon/bombcore/ex_act(severity) //Little boom can chain a big boom - src.detonate() + detonate() + + +/obj/item/weapon/bombcore/burn() + detonate() + ..() /obj/item/weapon/bombcore/proc/detonate() if(adminlog) message_admins(adminlog) log_game(adminlog) - explosion(get_turf(src),3,9,17, flame_range = 17) - if(src.loc && istype(src.loc,/obj/machinery/syndicatebomb/)) - qdel(src.loc) + explosion(get_turf(src), range_heavy, range_medium, range_light, flame_range = range_flame) + if(loc && istype(loc, /obj/machinery/syndicatebomb)) + qdel(loc) qdel(src) /obj/item/weapon/bombcore/proc/defuse() @@ -223,17 +323,20 @@ var/attempts = 0 /obj/item/weapon/bombcore/training/proc/reset() - var/obj/machinery/syndicatebomb/holder = src.loc + var/obj/machinery/syndicatebomb/holder = loc if(istype(holder)) if(holder.wires) holder.wires.Shuffle() holder.defused = 0 holder.open_panel = 0 + holder.delayedbig = FALSE + holder.delayedlittle = FALSE + holder.explode_now = FALSE holder.update_icon() holder.updateDialog() /obj/item/weapon/bombcore/training/detonate() - var/obj/machinery/syndicatebomb/holder = src.loc + var/obj/machinery/syndicatebomb/holder = loc if(istype(holder)) attempts++ holder.loc.visible_message("[bicon(holder)] Alert: Bomb has detonated. Your score is now [defusals] for [attempts]. Resetting wires...") @@ -242,7 +345,7 @@ qdel(src) /obj/item/weapon/bombcore/training/defuse() - var/obj/machinery/syndicatebomb/holder = src.loc + var/obj/machinery/syndicatebomb/holder = loc if(istype(holder)) attempts++ defusals++ @@ -257,11 +360,11 @@ origin_tech = null /obj/item/weapon/bombcore/badmin/defuse() //because we wouldn't want them being harvested by players - var/obj/machinery/syndicatebomb/B = src.loc + var/obj/machinery/syndicatebomb/B = loc qdel(B) qdel(src) -/obj/item/weapon/bombcore/badmin/summon/ +/obj/item/weapon/bombcore/badmin/summon var/summon_path = /obj/item/weapon/reagent_containers/food/snacks/cookie var/amt_summon = 1 @@ -285,42 +388,165 @@ playsound(src.loc, 'sound/misc/sadtrombone.ogg', 50) ..() -/obj/item/weapon/bombcore/badmin/explosion/ - var/HeavyExplosion = 2 - var/MediumExplosion = 5 - var/LightExplosion = 11 - var/Flames = 11 +/obj/item/weapon/bombcore/large + name = "large bomb payload" + range_heavy = 5 + range_medium = 10 + range_light = 20 + range_flame = 20 -/obj/item/weapon/bombcore/badmin/explosion/detonate() - explosion(get_turf(src),HeavyExplosion,MediumExplosion,LightExplosion, flame_range = Flames) +/obj/item/weapon/bombcore/large/underwall + layer = ABOVE_OPEN_TURF_LAYER /obj/item/weapon/bombcore/miniature name = "small bomb core" w_class = WEIGHT_CLASS_SMALL + range_heavy = 1 + range_medium = 2 + range_light = 4 + range_flame = 2 -/obj/item/weapon/bombcore/miniature/detonate() - explosion(src.loc,1,2,4,flame_range = 2) //Identical to a minibomb +/obj/item/weapon/bombcore/chemical + name = "chemical payload" + desc = "An explosive payload designed to spread chemicals, dangerous or otherwise, across a large area. It is able to hold up to four chemical containers, and must be loaded before use." + origin_tech = "combat=4;materials=3" + icon_state = "chemcore" + var/list/beakers = list() + var/max_beakers = 1 + var/spread_range = 5 + var/temp_boost = 50 + var/time_release = 0 + +/obj/item/weapon/bombcore/chemical/detonate() + + if(time_release > 0) + var/total_volume = 0 + for(var/obj/item/weapon/reagent_containers/RC in beakers) + total_volume += RC.reagents.total_volume + + if(total_volume < time_release) // If it's empty, the detonation is complete. + if(loc && istype(loc, /obj/machinery/syndicatebomb)) + qdel(loc) + qdel(src) + return + + var/fraction = time_release/total_volume + var/datum/reagents/reactants = new(time_release) + reactants.my_atom = src + for(var/obj/item/weapon/reagent_containers/RC in beakers) + RC.reagents.trans_to(reactants, RC.reagents.total_volume*fraction, 1, 1, 1) + chem_splash(get_turf(src), spread_range, list(reactants), temp_boost) + + // Detonate it again in one second, until it's out of juice. + addtimer(src, "detonate", 10) + + // If it's not a time release bomb, do normal explosion + + var/list/reactants = list() + + for(var/obj/item/weapon/reagent_containers/glass/G in beakers) + reactants += G.reagents + + for(var/obj/item/slime_extract/S in beakers) + if(S.Uses) + for(var/obj/item/weapon/reagent_containers/glass/G in beakers) + G.reagents.trans_to(S, G.reagents.total_volume) + + if(S && S.reagents && S.reagents.total_volume) + reactants += S.reagents + + if(!chem_splash(get_turf(src), spread_range, reactants, temp_boost)) + playsound(loc, 'sound/items/Screwdriver2.ogg', 50, 1) + return // The Explosion didn't do anything. No need to log, or disappear. + + if(adminlog) + message_admins(adminlog) + log_game(adminlog) + + playsound(loc, 'sound/effects/bamf.ogg', 75, 1, 5) + + if(loc && istype(loc, /obj/machinery/syndicatebomb)) + qdel(loc) qdel(src) +/obj/item/weapon/bombcore/chemical/attackby(obj/item/I, mob/user, params) + if(iscrowbar(I) && beakers.len > 0) + playsound(loc, I.usesound, 50, 1) + for (var/obj/item/B in beakers) + B.loc = get_turf(src) + beakers -= B + return + else if(istype(I, /obj/item/weapon/reagent_containers/glass/beaker) || istype(I, /obj/item/weapon/reagent_containers/glass/bottle)) + if(beakers.len < max_beakers) + if(!user.drop_item()) + return + beakers += I + to_chat(user, "You load [src] with [I].") + I.loc = src + else + to_chat(user, "The [I] wont fit! The [src] can only hold up to [max_beakers] containers.") + return + ..() + +/obj/item/weapon/bombcore/chemical/CheckParts(list/parts_list) + ..() + // Using different grenade casings, causes the payload to have different properties. + var/obj/item/weapon/stock_parts/matter_bin/MB = locate(/obj/item/weapon/stock_parts/matter_bin) in src + if(MB) + max_beakers += MB.rating // max beakers = 2-5. + qdel(MB) + for(var/obj/item/weapon/grenade/chem_grenade/G in src) + + if(istype(G, /obj/item/weapon/grenade/chem_grenade/large)) + var/obj/item/weapon/grenade/chem_grenade/large/LG = G + max_beakers += 1 // Adding two large grenades only allows for a maximum of 7 beakers. + spread_range += 2 // Extra range, reduced density. + temp_boost += 50 // maximum of +150K blast using only large beakers. Not enough to self ignite. + for(var/obj/item/slime_extract/S in LG.beakers) // And slime cores. + if(beakers.len < max_beakers) + beakers += S + S.loc = src + else + S.loc = get_turf(src) + + if(istype(G, /obj/item/weapon/grenade/chem_grenade/cryo)) + spread_range -= 1 // Reduced range, but increased density. + temp_boost -= 100 // minimum of -150K blast. + + if(istype(G, /obj/item/weapon/grenade/chem_grenade/pyro)) + temp_boost += 150 // maximum of +350K blast, which is enough to self ignite. Which means a self igniting bomb can't take advantage of other grenade casing properties. Sorry? + + if(istype(G, /obj/item/weapon/grenade/chem_grenade/adv_release)) + time_release += 50 // A typical bomb, using basic beakers, will explode over 2-4 seconds. Using two will make the reaction last for less time, but it will be more dangerous overall. + + for(var/obj/item/weapon/reagent_containers/glass/B in G) + if(beakers.len < max_beakers) + beakers += B + B.loc = src + else + B.loc = get_turf(src) + + qdel(G) + ///Syndicate Detonator (aka the big red button)/// /obj/item/device/syndicatedetonator name = "big red button" - desc = "Nothing good can come of pressing a button this garish..." + desc = "Your standard issue bomb synchronizing button. Five second safety delay to prevent 'accidents'." icon = 'icons/obj/assemblies.dmi' icon_state = "bigred" item_state = "electronic" w_class = WEIGHT_CLASS_TINY origin_tech = "syndicate=3" - var/cooldown = 0 + var/timer = 0 var/detonated = 0 var/existant = 0 -/obj/item/device/syndicatedetonator/attack_self(mob/user as mob) - if(!cooldown) +/obj/item/device/syndicatedetonator/attack_self(mob/user) + if(timer < world.time) for(var/obj/machinery/syndicatebomb/B in machines) if(B.active) - B.timer = 0 + B.detonation_timer = world.time + BUTTON_DELAY detonated++ existant++ playsound(user, 'sound/machines/click.ogg', 20, 1) @@ -334,5 +560,7 @@ log_game("[key_name(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] ([T.x],[T.y],[T.z])") detonated = 0 existant = 0 - cooldown = 1 - spawn(30) cooldown = 0 + timer = world.time + BUTTON_COOLDOWN + +#undef BUTTON_COOLDOWN +#undef BUTTON_DELAY \ No newline at end of file diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index ae198664806..294dda0d674 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -4,7 +4,6 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d name = "item" icon = 'icons/obj/items.dmi' var/discrete = 0 // used in item_attack.dm to make an item not show an attack message to viewers - var/no_embed = 0 // For use in item_attack.dm var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite var/blood_overlay_color = null var/item_state = null @@ -63,6 +62,17 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d var/mob/thrownby = null + //So items can have custom embedd values + //Because customisation is king + var/embed_chance = EMBED_CHANCE + var/embedded_fall_chance = EMBEDDED_ITEM_FALLOUT + var/embedded_pain_chance = EMBEDDED_PAIN_CHANCE + var/embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER //The coefficient of multiplication for the damage this item does while embedded (this*w_class) + var/embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER //The coefficient of multiplication for the damage this item does when falling out of a limb (this*w_class) + var/embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER //The coefficient of multiplication for the damage this item does when first embedded (this*w_class) + var/embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER //The coefficient of multiplication for the damage removing this without surgery causes (this*w_class) + var/embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME //A time in ticks, multiplied by the w_class. + var/toolspeed = 1 // If this item is a tool, the speed multiplier /* Species-specific sprites, concept stolen from Paradise//vg/. diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 3c9c0211663..3d1f1001b06 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -247,6 +247,13 @@ var/global/list/default_medbay_channels = list( A.name = from A.role = role A.message = message + var/jammed = FALSE + for(var/obj/item/device/jammer/jammer in active_jammers) + if(get_dist(get_turf(src), get_turf(jammer)) < jammer.range) + jammed = TRUE + break + if(jammed) + message = Gibberish(message, 100) Broadcast_Message(connection, A, 0, "*garbled automated announcement*", src, message, from, "Automated Announcement", from, "synthesized voice", @@ -332,6 +339,12 @@ var/global/list/default_medbay_channels = list( var/datum/radio_frequency/connection = message_mode var/turf/position = get_turf(src) + var/jammed = FALSE + for(var/obj/item/device/jammer/jammer in active_jammers) + if(get_dist(position, get_turf(jammer)) < jammer.range) + jammed = TRUE + break + //#### Tagging the signal with all appropriate identity values ####// // ||-- The mob's name identity --|| @@ -345,6 +358,9 @@ var/global/list/default_medbay_channels = list( var/jobname // the mob's "job" + if(jammed) + message = Gibberish(message, 100) + // --- Human: use their actual job --- if(ishuman(M)) var/mob/living/carbon/human/H = M diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 5f140f05d03..6b48dea1910 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -146,3 +146,22 @@ effective or pretty fucking useless. attack_self(usr) add_fingerprint(usr) return + +/obj/item/device/jammer + name = "radio jammer" + desc = "Device used to disrupt nearby radio communication." + icon_state = "jammer" + var/active = FALSE + var/range = 12 + +/obj/item/device/jammer/Destroy() + active_jammers -= src + return ..() + +/obj/item/device/jammer/attack_self(mob/user) + to_chat(user,"You [active ? "deactivate" : "activate"] the [src].") + active = !active + if(active) + active_jammers |= src + else + active_jammers -= src \ No newline at end of file diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm index 5f55a5acdcc..dccc8f041f6 100644 --- a/code/game/objects/items/latexballoon.dm +++ b/code/game/objects/items/latexballoon.dm @@ -59,5 +59,5 @@ var/obj/item/weapon/tank/T = W blow(T, user) return - if(is_sharp(W) || is_hot(W) || can_puncture(W)) + if(is_sharp(W) || is_hot(W) || is_pointed(W)) burst() diff --git a/code/game/objects/items/policetape.dm b/code/game/objects/items/policetape.dm index 56fd5eadbad..bea99b5d98b 100644 --- a/code/game/objects/items/policetape.dm +++ b/code/game/objects/items/policetape.dm @@ -174,7 +174,7 @@ var/list/tape_roll_applications = list() breaktape(/obj/item/weapon/wirecutters,user) /obj/item/tape/proc/breaktape(obj/item/weapon/W as obj, mob/user as mob) - if(user.a_intent == INTENT_HELP && ((!can_puncture(W) && src.allowed(user)))) + if(user.a_intent == INTENT_HELP && ((!is_pointed(W) && src.allowed(user)))) to_chat(user, "You can't break the [src] with that!") return user.visible_message("[user] breaks the [src]!", "You break the [src]!") diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 67755655fe3..029cb8cd4a5 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -123,6 +123,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list( */ var/global/list/datum/stack_recipe/plasteel_recipes = list( new /datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1), + new /datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 50), new /datum/stack_recipe("Surgery Table", /obj/machinery/optable, 5, time = 50, one_per_turf = 1, on_floor = 1), new /datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1), new /datum/stack_recipe("Mass Driver frame", /obj/machinery/mass_driver_frame, 3, time = 50, one_per_turf = 1) diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index f21914a7c32..707eac2fbce 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -19,6 +19,9 @@ var/obj/item/device/assembly_holder/nadeassembly = null var/label = null var/assemblyattacher + var/ignition_temp = 10 // The amount of heat added to the reagents when this grenade goes off. + var/threatscale = 1 // Used by advanced grenades to make them slightly more worthy. + var/no_splash = FALSE //If the grenade deletes even if it has no reagents to splash with. Used for slime core reactions. /obj/item/weapon/grenade/chem_grenade/New() create_reagents(1000) @@ -99,6 +102,7 @@ log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])") bombers += "[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])" to_chat(user, "You prime the [name]! [det_time / 10] second\s!") + playsound(user.loc, 'sound/weapons/armbomb.ogg', 60, 1) active = 1 update_icon() if(iscarbon(user)) @@ -264,13 +268,18 @@ if(stage != READY) return - var/has_reagents = 0 + var/list/datum/reagents/reactants = list() for(var/obj/item/weapon/reagent_containers/glass/G in beakers) - if(G.reagents.total_volume) - has_reagents = 1 + reactants += G.reagents - if(!has_reagents) - playsound(loc, usesound, 50, 1) + if(!chem_splash(get_turf(src), affected_area, reactants, ignition_temp, threatscale) && !no_splash) + playsound(loc, 'sound/items/Screwdriver2.ogg', 50, 1) + if(beakers.len) + for(var/obj/O in beakers) + O.forceMove(get_turf(src)) + beakers = list() + stage = EMPTY + update_icon() return if(nadeassembly) @@ -281,31 +290,9 @@ message_admins("grenade primed by an assembly, attached by [key_name_admin(M)](?) ([admin_jump_link(M)]) and last touched by [key_name_admin(last)](?) ([admin_jump_link(last)]) ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [A.name] (JMP).") log_game("grenade primed by an assembly, attached by [key_name(M)] and last touched by [key_name(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [A.name] ([T.x], [T.y], [T.z])") - playsound(loc, 'sound/effects/bamf.ogg', 50, 1) - update_mob() - invisibility = INVISIBILITY_MAXIMUM //kaboom - qdel(nadeassembly) // do this now to stop infrared beams - var/end_temp = 0 - for(var/obj/item/weapon/reagent_containers/glass/G in beakers) - G.reagents.trans_to(src, G.reagents.total_volume) - end_temp += G.reagents.chem_temp - reagents.chem_temp = end_temp - if(reagents.total_volume) //The possible reactions didnt use up all reagents. - var/datum/effect/system/steam_spread/steam = new /datum/effect/system/steam_spread() - steam.set_up(10, 0, get_turf(src)) - steam.attach(src) - steam.start() - - for(var/atom/A in view(affected_area, loc)) - if(A == src) - continue - reagents.reaction(A, 1, 10) - - - spawn(15) //Making sure all reagents can work - qdel(src) //correctly before deleting the grenade. + qdel(src) /obj/item/weapon/grenade/chem_grenade/proc/CreateDefaultTrigger(var/typekey) if(ispath(typekey,/obj/item/device/assembly)) @@ -327,64 +314,37 @@ //Large chem grenades accept slime cores and use the appropriately. /obj/item/weapon/grenade/chem_grenade/large name = "large grenade casing" - desc = "For oversized grenades; fits additional contents and affects a greater area." + desc = "A custom made large grenade. It affects a larger area." icon_state = "large_grenade" bomb_state = "largebomb" allowed_containers = list(/obj/item/weapon/reagent_containers/glass,/obj/item/weapon/reagent_containers/food/condiment, /obj/item/weapon/reagent_containers/food/drinks) origin_tech = "combat=3;engineering=3" - affected_area = 4 - + affected_area = 5 + ignition_temp = 25 // Large grenades are slightly more effective at setting off heat-sensitive mixtures than smaller grenades. + threatscale = 1.1 // 10% more effective. /obj/item/weapon/grenade/chem_grenade/large/prime() if(stage != READY) return - var/has_reagents = 0 - var/obj/item/slime_extract/valid_core = null + for(var/obj/item/slime_extract/S in beakers) + if(S.Uses) + for(var/obj/item/weapon/reagent_containers/glass/G in beakers) + G.reagents.trans_to(S, G.reagents.total_volume) - for(var/obj/item/weapon/reagent_containers/glass/G in beakers) - if(!istype(G)) continue - if(G.reagents.total_volume) has_reagents = 1 - for(var/obj/item/slime_extract/E in beakers) - if(!istype(E)) continue - if(E.Uses) valid_core = E - if(E.reagents.total_volume) has_reagents = 1 + //If there is still a core (sometimes it's used up) + //and there are reagents left, behave normally, + //otherwise drop it on the ground for timed reactions like gold. - if(!has_reagents) - playsound(loc, prime_sound, 50, 1) - return - - playsound(loc, 'sound/effects/bamf.ogg', 50, 1) - - update_mob() - - if(valid_core) - for(var/obj/item/weapon/reagent_containers/glass/G in beakers) - G.reagents.trans_to(valid_core, G.reagents.total_volume) - - //If there is still a core (sometimes it's used up) - //and there are reagents left, behave normally - - if(valid_core && valid_core.reagents && valid_core.reagents.total_volume) - valid_core.reagents.trans_to(src,valid_core.reagents.total_volume) - else - for(var/obj/item/weapon/reagent_containers/glass/G in beakers) - G.reagents.trans_to(src, G.reagents.total_volume) - - if(reagents.total_volume) //The possible reactions didnt use up all reagents. - var/datum/effect/system/steam_spread/steam = new /datum/effect/system/steam_spread() - steam.set_up(10, 0, get_turf(src)) - steam.attach(src) - steam.start() - - for(var/atom/A in view(affected_area, loc)) - if( A == src ) continue - reagents.reaction(A, 1, 10) - - invisibility = INVISIBILITY_MAXIMUM //Why am i doing this? - spawn(50) //To make sure all reagents can work - qdel(src) //correctly before deleting the grenade. + if(S) + if(S.reagents && S.reagents.total_volume) + for(var/obj/item/weapon/reagent_containers/glass/G in beakers) + S.reagents.trans_to(G, S.reagents.total_volume) + else + S.forceMove(get_turf(src)) + no_splash = TRUE + ..() //I tried to just put it in the allowed_containers list but @@ -399,6 +359,71 @@ else return ..() +/obj/item/weapon/grenade/chem_grenade/cryo // Intended for rare cryogenic mixes. Cools the area moderately upon detonation. + name = "cryo grenade" + desc = "A custom made cryogenic grenade. It rapidly cools its contents upon detonation." + icon_state = "cryog" + affected_area = 2 + ignition_temp = -100 + +/obj/item/weapon/grenade/chem_grenade/pyro // Intended for pyrotechnical mixes. Produces a small fire upon detonation, igniting potentially flammable mixtures. + name = "pyro grenade" + desc = "A custom made pyrotechnical grenade. It heats up and ignites its contents upon detonation." + icon_state = "pyrog" + origin_tech = "combat=4;engineering=4" + affected_area = 3 + ignition_temp = 500 // This is enough to expose a hotspot. + +/obj/item/weapon/grenade/chem_grenade/adv_release // Intended for weaker, but longer lasting effects. Could have some interesting uses. + name = "advanced release grenade" + desc = "A custom made advanced release grenade. It is able to be detonated more than once. Can be configured using a multitool." + icon_state = "timeg" + origin_tech = "combat=3;engineering=4" + var/unit_spread = 10 // Amount of units per repeat. Can be altered with a multitool. + +/obj/item/weapon/grenade/chem_grenade/adv_release/attackby(obj/item/I, mob/user, params) + if(ismultitool(I)) + switch(unit_spread) + if(0 to 24) + unit_spread += 5 + if(25 to 99) + unit_spread += 25 + else + unit_spread = 5 + to_chat(user, " You set the time release to [unit_spread] units per detonation.") + return + ..() + +/obj/item/weapon/grenade/chem_grenade/adv_release/prime() + if(stage != READY) + return + + var/total_volume = 0 + for(var/obj/item/weapon/reagent_containers/RC in beakers) + total_volume += RC.reagents.total_volume + if(!total_volume) + qdel(src) + qdel(nadeassembly) + return + var/fraction = unit_spread/total_volume + var/datum/reagents/reactants = new(unit_spread) + reactants.my_atom = src + for(var/obj/item/weapon/reagent_containers/RC in beakers) + RC.reagents.trans_to(reactants, RC.reagents.total_volume*fraction, threatscale, 1, 1) + chem_splash(get_turf(src), affected_area, list(reactants), ignition_temp, threatscale) + + if(nadeassembly) + var/mob/M = get_mob_by_ckey(assemblyattacher) + var/mob/last = get_mob_by_ckey(nadeassembly.fingerprintslast) + var/turf/T = get_turf(src) + var/area/A = get_area(T) + message_admins("grenade primed by an assembly, attached by [key_name_admin(M)](?) (FLW) and last touched by [key_name_admin(last)](?) (FLW) ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [A.name] (JMP).") + log_game("grenade primed by an assembly, attached by [key_name(M)] and last touched by [key_name(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [A.name] ([T.x], [T.y], [T.z])") + else + addtimer(src, "prime", det_time) + var/turf/DT = get_turf(src) + var/area/DA = get_area(DT) + log_game("A grenade detonated at [DA.name] ([DT.x], [DT.y], [DT.z])") /obj/item/weapon/grenade/chem_grenade/metalfoam payload_name = "metal foam" diff --git a/code/game/objects/items/weapons/implants/implant_death_alarm.dm b/code/game/objects/items/weapons/implants/implant_death_alarm.dm index da9560122ad..d4807a18701 100644 --- a/code/game/objects/items/weapons/implants/implant_death_alarm.dm +++ b/code/game/objects/items/weapons/implants/implant_death_alarm.dm @@ -35,7 +35,7 @@ var/mob/M = imp_in var/area/t = get_area(M) - var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset(null) + var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset(src) a.follow_target = M switch(cause) @@ -52,7 +52,7 @@ else a.autosay("[mobname] has died-zzzzt in-in-in...", "[mobname]'s Death Alarm") qdel(src) - + qdel(a) /obj/item/weapon/implant/death_alarm/emp_act(severity) //for some reason alarms stop going off in case they are emp'd, even without this diff --git a/code/game/objects/items/weapons/kitchen.dm b/code/game/objects/items/weapons/kitchen.dm index c642226a8d6..82c6b14f880 100644 --- a/code/game/objects/items/weapons/kitchen.dm +++ b/code/game/objects/items/weapons/kitchen.dm @@ -98,7 +98,6 @@ throw_range = 6 materials = list(MAT_METAL=12000) attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - no_embed = 1 sharp = 1 edge = 1 diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 2bb2924837d..810be365fa8 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -6,7 +6,6 @@ var/w_class_on = WEIGHT_CLASS_BULKY var/icon_state_on = "axe1" var/list/attack_verb_on = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - no_embed = 1 // Physically impossible for energy weapons to embed themselves into people, this should fix that. -- Dave hitsound = 'sound/weapons/blade1.ogg' // Probably more appropriate than the previous hitsound. -- Dave usesound = 'sound/weapons/blade1.ogg' toolspeed = 1 @@ -25,6 +24,7 @@ force = force_on throwforce = throwforce_on hitsound = 'sound/weapons/blade1.ogg' + throw_speed = 4 if(attack_verb_on.len) attack_verb = attack_verb_on if(!item_color) @@ -38,6 +38,7 @@ force = initial(force) throwforce = initial(throwforce) hitsound = initial(hitsound) + throw_speed = initial(throw_speed) if(attack_verb_on.len) attack_verb = list() icon_state = initial(icon_state) @@ -85,6 +86,8 @@ throw_speed = 3 throw_range = 5 hitsound = "swing_hit" + embed_chance = 75 + embedded_impact_pain_multiplier = 10 armour_penetration = 35 origin_tech = "combat=3;magnets=4;syndicate=4" block_chance = 50 diff --git a/code/game/objects/items/weapons/shards.dm b/code/game/objects/items/weapons/shards.dm index 554347224eb..272e66ee11a 100644 --- a/code/game/objects/items/weapons/shards.dm +++ b/code/game/objects/items/weapons/shards.dm @@ -88,28 +88,4 @@ if(affecting.take_damage(5, 0)) H.UpdateDamageIcon() H.updatehealth() - ..() - -// Shrapnel - -/obj/item/weapon/shard/shrapnel - name = "shrapnel" - icon = 'icons/obj/shards.dmi' - icon_state = "shrapnellarge" - desc = "A bunch of tiny bits of shattered metal." - -/obj/item/weapon/shard/shrapnel/New() - - src.icon_state = pick("shrapnellarge", "shrapnelmedium", "shrapnelsmall") - switch(src.icon_state) - if("shrapnelsmall") - src.pixel_x = rand(-12, 12) - src.pixel_y = rand(-12, 12) - if("shrapnelmedium") - src.pixel_x = rand(-8, 8) - src.pixel_y = rand(-8, 8) - if("shrapnellarge") - src.pixel_x = rand(-5, 5) - src.pixel_y = rand(-5, 5) - else - return + ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index 9efc5f625a6..c5f32121d4f 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -157,6 +157,22 @@ new /obj/item/weapon/grenade/empgrenade(src) new /obj/item/weapon/implanter/emp/(src) +/obj/item/weapon/storage/box/syndie_kit/throwing_weapons + name = "boxed throwing kit" + can_hold = list(/obj/item/weapon/throwing_star, /obj/item/weapon/restraints/legcuffs/bola/tactical) + max_combined_w_class = 16 + max_w_class = WEIGHT_CLASS_NORMAL + +/obj/item/weapon/storage/box/syndie_kit/throwing_weapons/New() + ..() + new /obj/item/weapon/throwing_star(src) + new /obj/item/weapon/throwing_star(src) + new /obj/item/weapon/throwing_star(src) + new /obj/item/weapon/throwing_star(src) + new /obj/item/weapon/throwing_star(src) + new /obj/item/weapon/restraints/legcuffs/bola/tactical(src) + new /obj/item/weapon/restraints/legcuffs/bola/tactical(src) + /obj/item/weapon/storage/box/syndie_kit/sarin name = "Sarin Gas Grenades" diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm index c07c658a7bf..11da88ae680 100644 --- a/code/game/objects/items/weapons/teleportation.dm +++ b/code/game/objects/items/weapons/teleportation.dm @@ -128,7 +128,7 @@ Frequency: if(turfs.len) L["None (Dangerous)"] = pick(turfs) var/t1 = input(user, "Please select a teleporter to lock in on.", "Hand Teleporter") as null|anything in L - if(!t1 || (user.is_in_active_hand(src) || user.stat || user.restrained())) + if(!t1 || (!user.is_in_active_hand(src) || user.stat || user.restrained())) return if(active_portals >= 3) user.show_message("\The [src] is recharging!") diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index cdd8b8a5de1..9f4ebf36611 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -210,7 +210,6 @@ block_chance = 75 sharp = 1 edge = 1 - no_embed = 1 // Like with the single-handed esword, this shouldn't be embedding in people. /obj/item/weapon/twohanded/dualsaber/New() blade_color = pick("red", "blue", "green", "purple") @@ -500,7 +499,6 @@ attack_verb = list("sawed", "cut", "hacked", "carved", "cleaved", "butchered", "felled", "timbered") sharp = 1 edge = 1 - no_embed = 1 /obj/item/weapon/twohanded/chainsaw/update_icon() if(wielded) @@ -539,7 +537,6 @@ icon_state = "mjollnir0" flags = CONDUCT slot_flags = SLOT_BACK - no_embed = 1 force = 5 force_unwielded = 5 force_wielded = 20 @@ -604,7 +601,6 @@ icon_state = "mjollnir0" flags = CONDUCT slot_flags = SLOT_BACK - no_embed = 1 force = 5 force_unwielded = 5 force_wielded = 25 @@ -652,7 +648,6 @@ icon_state = "knighthammer0" flags = CONDUCT slot_flags = SLOT_BACK - no_embed = 1 force = 5 force_unwielded = 5 force_wielded = 30 diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index 95317b7f0a6..586b24bc719 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -130,6 +130,21 @@ obj/item/weapon/wirerod/attackby(obj/item/I, mob/user, params) qdel(I) qdel(src) +/obj/item/weapon/throwing_star + name = "throwing star" + desc = "An ancient weapon still used to this day due to it's ease of lodging itself into victim's body parts" + icon_state = "throwingstar" + item_state = "eshield0" + force = 2 + throwforce = 20 //This is never used on mobs since this has a 100% embed chance. + throw_speed = 4 + embedded_pain_multiplier = 4 + w_class = WEIGHT_CLASS_SMALL + embed_chance = 100 + embedded_fall_chance = 0 //Hahaha! + sharp = 1 + edge = 1 + materials = list(MAT_METAL=500, MAT_GLASS=500) /obj/item/weapon/spear/kidan icon_state = "kidanspear" diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm index d651ad55adb..e9d9781bf0e 100644 --- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm +++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm @@ -251,6 +251,10 @@ new /obj/item/clothing/under/rank/medical/skirt(src) new /obj/item/clothing/under/rank/medical/skirt(src) new /obj/item/clothing/head/surgery/purple(src) + new /obj/item/clothing/under/medigown(src) + new /obj/item/clothing/under/medigown(src) + new /obj/item/clothing/under/medigown(src) + new /obj/item/clothing/under/medigown(src) new /obj/item/clothing/shoes/black(src) new /obj/item/clothing/shoes/black(src) new /obj/item/clothing/shoes/black(src) @@ -406,6 +410,10 @@ new /obj/item/clothing/suit/storage/labcoat(src) new /obj/item/clothing/mask/surgical(src) new /obj/item/clothing/mask/surgical(src) + new /obj/item/clothing/under/medigown(src) + new /obj/item/clothing/under/medigown(src) + new /obj/item/clothing/under/medigown(src) + new /obj/item/clothing/under/medigown(src) /obj/structure/closet/wardrobe/grey diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm index 14f1357af87..2cdcfc18376 100644 --- a/code/game/objects/structures/inflatable.dm +++ b/code/game/objects/structures/inflatable.dm @@ -96,7 +96,7 @@ /obj/structure/inflatable/attackby(obj/item/weapon/W as obj, mob/user as mob, params) if(!istype(W)) return - if(can_puncture(W)) + if(is_pointed(W)) visible_message("[user] pierces [src] with [W]!") deflate(1) if(W.damtype == BRUTE || W.damtype == BURN) diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm index 3f4eea3dbf4..b1cf367ba1f 100644 --- a/code/game/objects/structures/signs.dm +++ b/code/game/objects/structures/signs.dm @@ -182,10 +182,15 @@ icon_state = "nuke" /obj/structure/sign/clown - name = "\improper mech painting" + name = "\improper clown painting" desc = "A painting of the clown and mime. Awwww." icon_state = "clown" +/obj/structure/sign/bobross + name = "\improper calming painting" + desc = "We don't make mistakes, just happy little accidents." + icon_state = "bob" + /obj/structure/sign/singulo name = "\improper singulo painting" desc = "A mesmerizing painting of a singularity. It seems to suck you in..." diff --git a/code/game/response_team.dm b/code/game/response_team.dm index 344a9b72054..ebfe10f71e0 100644 --- a/code/game/response_team.dm +++ b/code/game/response_team.dm @@ -387,12 +387,13 @@ var/ert_request_answered = 0 /obj/item/clothing/head/helmet/space/hardsuit/ert/commander = 1, /obj/item/clothing/mask/gas/sechailer/swat = 1, /obj/item/weapon/restraints/handcuffs = 1, + /obj/item/clothing/shoes/magboots = 1, /obj/item/weapon/storage/lockbox/mindshield = 1 ) /datum/outfit/job/centcom/response_team/commander/gamma name = "RT Commander (Gamma)" - shoes = /obj/item/clothing/shoes/combat/swat + shoes = /obj/item/clothing/shoes/magboots/advance gloves = /obj/item/clothing/gloves/combat suit = /obj/item/clothing/suit/space/hardsuit/ert/commander glasses = /obj/item/clothing/glasses/hud/security/night @@ -457,6 +458,7 @@ var/ert_request_answered = 0 backpack_contents = list( /obj/item/clothing/head/helmet/space/hardsuit/ert/security = 1, /obj/item/clothing/mask/gas/sechailer = 1, + /obj/item/clothing/shoes/magboots = 1, /obj/item/weapon/storage/box/handcuffs = 1, /obj/item/weapon/gun/energy/ionrifle/carbine = 1 ) @@ -464,7 +466,7 @@ var/ert_request_answered = 0 /datum/outfit/job/centcom/response_team/security/gamma name = "RT Security (Gamma)" has_grenades = TRUE - shoes = /obj/item/clothing/shoes/combat/swat + shoes = /obj/item/clothing/shoes/magboots/advance gloves = /obj/item/clothing/gloves/combat suit = /obj/item/clothing/suit/space/hardsuit/ert/security suit_store = /obj/item/weapon/gun/energy/gun/nuclear @@ -509,7 +511,7 @@ var/ert_request_answered = 0 /datum/outfit/job/centcom/response_team/engineer/red name = "RT Engineer (Red)" - shoes = /obj/item/clothing/shoes/magboots + shoes = /obj/item/clothing/shoes/magboots/advance gloves = /obj/item/clothing/gloves/color/yellow suit = /obj/item/clothing/suit/space/hardsuit/ert/engineer suit_store = /obj/item/weapon/tank/emergency_oxygen/engi @@ -594,12 +596,13 @@ var/ert_request_answered = 0 /obj/item/weapon/storage/firstaid/toxin = 1, /obj/item/weapon/storage/firstaid/adv = 1, /obj/item/weapon/storage/firstaid/surgery = 1, - /obj/item/weapon/gun/energy/gun = 1 + /obj/item/weapon/gun/energy/gun = 1, + /obj/item/clothing/shoes/magboots = 1 ) /datum/outfit/job/centcom/response_team/medic/gamma name = "RT Medic (Gamma)" - shoes = /obj/item/clothing/shoes/combat/swat + shoes = /obj/item/clothing/shoes/magboots/advance gloves = /obj/item/clothing/gloves/combat suit = /obj/item/clothing/suit/space/hardsuit/ert/medical glasses = /obj/item/clothing/glasses/hud/health/night diff --git a/code/modules/admin/verbs/gimmick_team.dm b/code/modules/admin/verbs/gimmick_team.dm index 9aecae47d17..2ca1d3c27df 100644 --- a/code/modules/admin/verbs/gimmick_team.dm +++ b/code/modules/admin/verbs/gimmick_team.dm @@ -12,6 +12,7 @@ return if(alert("Do you want to spawn a Gimmick Team at YOUR CURRENT LOCATION?",,"Yes","No")=="No") return + var/turf/T = get_turf(mob) var/pick_manually = 0 if(alert("Pick the team members manually? If you select yes, you pick from ghosts. If you select no, ghosts get offered the chance to join.",,"Yes","No")=="Yes") pick_manually = 1 @@ -34,6 +35,9 @@ var/dresscode = input("Select Outfit", "Dress-a-mob") as null|anything in outfit_list if(isnull(dresscode)) return + var/is_syndicate = 0 + if(alert("Do you want these characters automatically classified as antagonists?",,"Yes","No")=="Yes") + is_syndicate = 1 var/list/players_to_spawn = list() if(pick_manually) @@ -55,7 +59,8 @@ return 0 var/datum/outfit/O = outfit_list[dresscode] - var/turf/T = get_turf(mob) + + var/players_spawned = 0 for(var/mob/thisplayer in players_to_spawn) var/mob/living/carbon/human/H = new /mob/living/carbon/human(T) H.name = random_name(pick(MALE,FEMALE)) @@ -67,13 +72,20 @@ H.mind_initialize() H.mind.assigned_role = "MODE" H.mind.special_role = "Event Character" - ticker.mode.traitors |= H.mind //Adds them to extra antag list H.key = thisplayer.key H.equipOutfit(O, FALSE) to_chat(H, "
    [themission]") + H.mind.store_memory("[themission]

    ") + + if(is_syndicate) + ticker.mode.traitors |= H.mind //Adds them to extra antag list + + players_spawned++ + if(players_spawned >= teamsize) + break message_admins("[key_name_admin(src)] has spawned a Gimmick Team.", 1) diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 9e40914da9b..5f3cc4dec2b 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -2154,7 +2154,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts else if(status == "cyborg") if(rlimb_data[name]) - O.robotize(rlimb_data[name]) + O.robotize(rlimb_data[name], convert_all = 0) else O.robotize() else diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index c7c7c3afcb0..d120ef04528 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -90,7 +90,8 @@ scan_reagents = 1 //You can see reagents while wearing science goggles species_fit = list("Vox") sprite_sheets = list( - "Vox" = 'icons/mob/species/vox/eyes.dmi' + "Vox" = 'icons/mob/species/vox/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) actions_types = list(/datum/action/item_action/toggle_research_scanner) @@ -138,7 +139,8 @@ item_state = "eyepatch" species_fit = list("Vox") sprite_sheets = list( - "Vox" = 'icons/mob/species/vox/eyes.dmi' + "Vox" = 'icons/mob/species/vox/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) /obj/item/clothing/glasses/monocle @@ -150,7 +152,8 @@ species_fit = list("Vox") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/eyes.dmi', - "Drask" = 'icons/mob/species/drask/eyes.dmi' + "Drask" = 'icons/mob/species/drask/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) /obj/item/clothing/glasses/material @@ -163,7 +166,8 @@ species_fit = list("Vox") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/eyes.dmi', - "Drask" = 'icons/mob/species/drask/eyes.dmi' + "Drask" = 'icons/mob/species/drask/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) /obj/item/clothing/glasses/material/cyber @@ -182,7 +186,8 @@ prescription = 1 species_fit = list("Vox") sprite_sheets = list( - "Vox" = 'icons/mob/species/vox/eyes.dmi' + "Vox" = 'icons/mob/species/vox/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) /obj/item/clothing/glasses/regular/hipster @@ -198,7 +203,8 @@ item_state = "3d" species_fit = list("Vox") sprite_sheets = list( - "Vox" = 'icons/mob/species/vox/eyes.dmi' + "Vox" = 'icons/mob/species/vox/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) /obj/item/clothing/glasses/gglasses @@ -208,7 +214,8 @@ item_state = "gglasses" species_fit = list("Vox") sprite_sheets = list( - "Vox" = 'icons/mob/species/vox/eyes.dmi' + "Vox" = 'icons/mob/species/vox/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) prescription_upgradable = 1 @@ -379,7 +386,8 @@ flash_protect = -1 species_fit = list("Vox") sprite_sheets = list( - "Vox" = 'icons/mob/species/vox/eyes.dmi' + "Vox" = 'icons/mob/species/vox/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) emp_act(severity) diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index 818ed3f2f10..ff8de1a6a82 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -62,7 +62,8 @@ HUDType = DATA_HUD_DIAGNOSTIC species_fit = list("Vox") sprite_sheets = list( - "Vox" = 'icons/mob/species/vox/eyes.dmi' + "Vox" = 'icons/mob/species/vox/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) /obj/item/clothing/glasses/hud/diagnostic/night @@ -85,7 +86,8 @@ species_fit = list("Vox") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/eyes.dmi', - "Drask" = 'icons/mob/species/drask/eyes.dmi' + "Drask" = 'icons/mob/species/drask/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) /obj/item/clothing/glasses/hud/security/chameleon @@ -138,7 +140,8 @@ HUDType = DATA_HUD_HYDROPONIC species_fit = list("Vox") sprite_sheets = list( - "Vox" = 'icons/mob/species/vox/eyes.dmi' + "Vox" = 'icons/mob/species/vox/eyes.dmi', + "Grey" = 'icons/mob/species/grey/eyes.dmi' ) /obj/item/clothing/glasses/hud/hydroponic/night diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index c73a6f21306..ae694f8edf2 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -70,4 +70,8 @@ heat_protection = HEAD max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT cold_protection = HEAD - min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT \ No newline at end of file + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT + species_fit = list("Grey") + sprite_sheets = list( + "Grey" = 'icons/mob/species/grey/helmet.dmi' + ) \ No newline at end of file diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 1bb6c1ec382..c3595288213 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -13,10 +13,11 @@ max_heat_protection_temperature = HELMET_MAX_TEMP_PROTECT strip_delay = 60 burn_state = FIRE_PROOF - species_fit = list("Vox", "Drask") + species_fit = list("Vox", "Drask", "Grey") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/helmet.dmi', - "Drask" = 'icons/mob/species/drask/helmet.dmi' + "Drask" = 'icons/mob/species/drask/helmet.dmi', + "Grey" = 'icons/mob/species/grey/helmet.dmi' ) /obj/item/clothing/head/helmet/attack_self(mob/user) diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index aa5a81c2063..ee0610471c8 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -24,12 +24,13 @@ flags_inv = (HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE) actions_types = list(/datum/action/item_action/toggle) burn_state = FIRE_PROOF - species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin") + species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin", "Grey") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/head.dmi', "Unathi" = 'icons/mob/species/unathi/helmet.dmi', "Tajaran" = 'icons/mob/species/tajaran/helmet.dmi', - "Vulpkanin" = 'icons/mob/species/vulpkanin/helmet.dmi' + "Vulpkanin" = 'icons/mob/species/vulpkanin/helmet.dmi', + "Grey" = 'icons/mob/species/grey/helmet.dmi' ) /obj/item/clothing/head/welding/flamedecal diff --git a/code/modules/clothing/masks/boxing.dm b/code/modules/clothing/masks/boxing.dm index 59081cf3d00..d66daf59760 100644 --- a/code/modules/clothing/masks/boxing.dm +++ b/code/modules/clothing/masks/boxing.dm @@ -8,12 +8,13 @@ w_class = WEIGHT_CLASS_SMALL actions_types = list(/datum/action/item_action/adjust) adjusted_flags = SLOT_HEAD - species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin") + species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin", "Grey") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi', "Unathi" = 'icons/mob/species/unathi/mask.dmi', "Tajaran" = 'icons/mob/species/tajaran/mask.dmi', "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi', + "Grey" = 'icons/mob/species/grey/mask.dmi', "Drask" = 'icons/mob/species/drask/mask.dmi' ) @@ -28,12 +29,13 @@ flags = BLOCKHAIR flags_inv = HIDEFACE w_class = WEIGHT_CLASS_SMALL - species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin") + species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin", "Grey") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi', "Unathi" = 'icons/mob/species/unathi/mask.dmi', "Tajaran" = 'icons/mob/species/tajaran/mask.dmi', "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi', + "Grey" = 'icons/mob/species/grey/mask.dmi', "Drask" = 'icons/mob/species/drask/mask.dmi' ) diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm index 851c10db354..afefbbc93cc 100644 --- a/code/modules/clothing/masks/breath.dm +++ b/code/modules/clothing/masks/breath.dm @@ -10,13 +10,14 @@ permeability_coefficient = 0.50 actions_types = list(/datum/action/item_action/adjust) burn_state = FIRE_PROOF - species_fit = list("Vox", "Vox Armalis", "Unathi", "Tajaran", "Vulpkanin") + species_fit = list("Vox", "Vox Armalis", "Unathi", "Tajaran", "Vulpkanin", "Grey" ) sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi', "Vox Armalis" = 'icons/mob/species/armalis/mask.dmi', "Unathi" = 'icons/mob/species/unathi/mask.dmi', "Tajaran" = 'icons/mob/species/tajaran/mask.dmi', "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi', + "Grey" = 'icons/mob/species/grey/mask.dmi', "Drask" = 'icons/mob/species/drask/mask.dmi' ) @@ -30,7 +31,7 @@ item_state = "medical" permeability_coefficient = 0.01 put_on_delay = 10 - species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin") + species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin", "Grey") /obj/item/clothing/mask/breath/vox desc = "A weirdly-shaped breath mask." diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index d524d87e3d8..5ac05685079 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -34,12 +34,13 @@ w_class = WEIGHT_CLASS_TINY resist_time = 150 mute = 0 - species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin") + species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin", "Grey") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi', "Unathi" = 'icons/mob/species/unathi/mask.dmi', "Tajaran" = 'icons/mob/species/tajaran/mask.dmi', - "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi' + "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi', + "Grey" = 'icons/mob/species/grey/mask.dmi' ) /obj/item/clothing/mask/muzzle/tapegag/dropped(mob/living/carbon/human/user) @@ -65,12 +66,13 @@ permeability_coefficient = 0.01 armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 25, rad = 0) actions_types = list(/datum/action/item_action/adjust) - species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin") + species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin", "Grey") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi', "Unathi" = 'icons/mob/species/unathi/mask.dmi', "Tajaran" = 'icons/mob/species/tajaran/mask.dmi', - "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi' + "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi', + "Grey" = 'icons/mob/species/grey/mask.dmi' ) @@ -83,12 +85,13 @@ icon_state = "fake-moustache" flags_inv = HIDEFACE actions_types = list(/datum/action/item_action/pontificate) - species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin") + species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin", "Grey") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi', "Unathi" = 'icons/mob/species/unathi/mask.dmi', "Tajaran" = 'icons/mob/species/tajaran/mask.dmi', - "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi' + "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi', + "Grey" = 'icons/mob/species/grey/mask.dmi' ) /obj/item/clothing/mask/fakemoustache/attack_self(mob/user) @@ -267,12 +270,13 @@ slot_flags = SLOT_MASK adjusted_flags = SLOT_HEAD icon_state = "bandbotany" - species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin") + species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin", "Grey") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi', "Unathi" = 'icons/mob/species/unathi/mask.dmi', "Tajaran" = 'icons/mob/species/tajaran/mask.dmi', - "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi' + "Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi', + "Grey" = 'icons/mob/species/grey/mask.dmi' ) actions_types = list(/datum/action/item_action/adjust) diff --git a/code/modules/clothing/spacesuits/ert.dm b/code/modules/clothing/spacesuits/ert.dm index 80257cda101..90d61fa0313 100644 --- a/code/modules/clothing/spacesuits/ert.dm +++ b/code/modules/clothing/spacesuits/ert.dm @@ -9,6 +9,10 @@ var/obj/machinery/camera/camera var/has_camera = TRUE strip_delay = 130 + species_fit = list("Grey") + sprite_sheets = list( + "Grey" = 'icons/mob/species/grey/helmet.dmi' + ) /obj/item/clothing/head/helmet/space/hardsuit/ert/attack_self(mob/user) if(camera || !has_camera) diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 802f39ad361..5483ca65072 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -20,14 +20,15 @@ "Skrell" = 'icons/mob/species/skrell/helmet.dmi', "Vox" = 'icons/mob/species/vox/helmet.dmi', "Vulpkanin" = 'icons/mob/species/vulpkanin/helmet.dmi', - "Drask" = 'icons/mob/species/drask/helmet.dmi' + "Drask" = 'icons/mob/species/drask/helmet.dmi', + "Grey" = 'icons/mob/species/grey/helmet.dmi' ) sprite_sheets_obj = list( "Unathi" = 'icons/obj/clothing/species/unathi/hats.dmi', "Tajaran" = 'icons/obj/clothing/species/tajaran/hats.dmi', "Skrell" = 'icons/obj/clothing/species/skrell/hats.dmi', "Vox" = 'icons/obj/clothing/species/vox/hats.dmi', - "Vulpkanin" = 'icons/obj/clothing/species/vulpkanin/hats.dmi', + "Vulpkanin" = 'icons/obj/clothing/species/vulpkanin/hats.dmi' ) /obj/item/clothing/head/helmet/space/hardsuit/equip_to_best_slot(mob/M) @@ -83,7 +84,7 @@ "Tajaran" = 'icons/obj/clothing/species/tajaran/suits.dmi', "Skrell" = 'icons/obj/clothing/species/skrell/suits.dmi', "Vox" = 'icons/obj/clothing/species/vox/suits.dmi', - "Vulpkanin" = 'icons/obj/clothing/species/vulpkanin/suits.dmi', + "Vulpkanin" = 'icons/obj/clothing/species/vulpkanin/suits.dmi' ) //Breach thresholds, should ideally be inherited by most (if not all) hardsuits. @@ -440,7 +441,10 @@ heat_protection = HEAD //Uncomment to enable firesuit protection max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT unacidable = 1 - sprite_sheets = null + species_fit = list("Grey") + sprite_sheets = list( + "Grey" = 'icons/mob/species/grey/helmet.dmi' + ) /obj/item/clothing/suit/space/hardsuit/wizard icon_state = "hardsuit-wiz" @@ -538,7 +542,6 @@ icon_state = "hardsuit0-hos" item_color = "hos" armor = list(melee = 45, bullet = 25, laser = 30,energy = 10, bomb = 25, bio = 100, rad = 50) - sprite_sheets = null /obj/item/clothing/suit/space/hardsuit/security/hos diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm index 20d9809f2b2..60e76418a53 100644 --- a/code/modules/clothing/spacesuits/miscellaneous.dm +++ b/code/modules/clothing/spacesuits/miscellaneous.dm @@ -8,9 +8,10 @@ permeability_coefficient = 0.01 armor = list(melee = 40, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50) species_restricted = list("exclude", "Diona", "Wryn") - species_fit = list("Vox") + species_fit = list("Vox", "Grey") sprite_sheets = list( - "Vox" = 'icons/mob/species/vox/helmet.dmi' + "Vox" = 'icons/mob/species/vox/helmet.dmi', + "Grey" = 'icons/mob/species/grey/helmet.dmi' ) /obj/item/clothing/head/helmet/space/capspace/equipped(mob/living/carbon/human/user, slot) @@ -136,9 +137,10 @@ desc = "A paramedic EVA helmet. Used in the recovery of bodies from space." icon_state = "paramedic-eva-helmet" item_state = "paramedic-eva-helmet" - species_fit = list("Vox") + species_fit = list("Vox", "Grey") sprite_sheets = list( - "Vox" = 'icons/mob/species/vox/helmet.dmi' + "Vox" = 'icons/mob/species/vox/helmet.dmi', + "Grey" = 'icons/mob/species/grey/helmet.dmi' ) sprite_sheets_obj = list( "Vox" = 'icons/obj/clothing/species/vox/hats.dmi' @@ -187,12 +189,13 @@ armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 100, rad = 20) flash_protect = 0 species_restricted = list("exclude", "Diona", "Wryn") - species_fit = list("Tajaran", "Unathi", "Vox", "Vulpkanin") + species_fit = list("Tajaran", "Unathi", "Vox", "Vulpkanin", "Grey") sprite_sheets = list( "Tajaran" = 'icons/mob/species/tajaran/helmet.dmi', "Unathi" = 'icons/mob/species/unathi/helmet.dmi', "Vox" = 'icons/mob/species/vox/helmet.dmi', - "Vulpkanin" = 'icons/mob/species/vulpkanin/helmet.dmi' + "Vulpkanin" = 'icons/mob/species/vulpkanin/helmet.dmi', + "Grey" = 'icons/mob/species/grey/helmet.dmi' ) sprite_sheets_obj = list( "Vox" = 'icons/obj/clothing/species/vox/hats.dmi', diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm index 273dab0c787..eda243a859a 100644 --- a/code/modules/clothing/spacesuits/plasmamen.dm +++ b/code/modules/clothing/spacesuits/plasmamen.dm @@ -116,7 +116,7 @@ armor = list(melee = 10, bullet = 5, laser = 10, energy = 5, bomb = 10, bio = 100, rad = 0) max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT flash_protect = 2 - + /obj/item/clothing/suit/space/eva/plasmaman/engineer name = "plasmaman engineer suit" icon_state = "plasmamanEngineer_suit" @@ -128,7 +128,7 @@ base_state = "plasmamanEngineer_helmet" armor = list(melee = 10, bullet = 5, laser = 10, energy = 5, bomb = 10, bio = 100, rad = 75) flash_protect = 2 - + /obj/item/clothing/suit/space/eva/plasmaman/engineer/ce name = "plasmaman chief engineer suit" icon_state = "plasmaman_CE" @@ -269,6 +269,24 @@ icon_state = "plasmaman_CMO_helmet0" base_state = "plasmaman_CMO_helmet" +/obj/item/clothing/suit/space/eva/plasmaman/medical/coroner + name = "plasmaman coroner suit" + icon_state = "plasmaman_Coroner" + +/obj/item/clothing/head/helmet/space/eva/plasmaman/medical/coroner + name = "plasmaman coroner helmet" + icon_state = "plasmaman_Coroner_helmet0" + base_state = "plasmaman_Coroner_helmet" + +/obj/item/clothing/suit/space/eva/plasmaman/medical/virologist + name = "plasmaman virologist suit" + icon_state = "plasmaman_Virologist" + +/obj/item/clothing/head/helmet/space/eva/plasmaman/medical/virologist + name = "plasmaman virologist helmet" + icon_state = "plasmaman_Virologist_helmet0" + base_state = "plasmaman_Virologist_helmet" + /obj/item/clothing/suit/space/eva/plasmaman/science name = "plasmaman scientist suit" icon_state = "plasmamanScience_suit" @@ -278,6 +296,15 @@ icon_state = "plasmamanScience_helmet0" base_state = "plasmamanScience_helmet" +/obj/item/clothing/suit/space/eva/plasmaman/science/geneticist + name = "plasmaman geneticist suit" + icon_state = "plasmaman_Geneticist" + +/obj/item/clothing/head/helmet/space/eva/plasmaman/science/geneticist + name = "plasmaman geneticist helmet" + icon_state = "plasmaman_Geneticist_helmet0" + base_state = "plasmaman_Geneticist_helmet" + /obj/item/clothing/suit/space/eva/plasmaman/science/rd name = "plasmaman research director suit" icon_state = "plasmaman_RD" diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm index da181368cc5..f1fb29ed645 100644 --- a/code/modules/clothing/spacesuits/rig/rig.dm +++ b/code/modules/clothing/spacesuits/rig/rig.dm @@ -978,10 +978,6 @@ else M.stop_pulling() - if(wearer.pinned.len) - to_chat(src, "Your host is pinned to a wall by [wearer.pinned[1]]!") - return 0 - // AIs are a bit slower than regular and ignore move intent. wearer_move_delay = world.time + ai_controlled_move_delay diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 43b89d315d9..a5340ed91bc 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -952,17 +952,17 @@ /obj/item/clothing/suit/tailcoat name = "victorian tailcoat" - desc = "a fancy victorian tailcoat." + desc = "A fancy victorian tailcoat." icon_state = "tailcoat" item_state = "tailcoat" /obj/item/clothing/suit/victcoat name = "ladies victorian coat" - desc = "a fancy victorian coat." + desc = "A fancy victorian coat." icon_state = "ladiesvictoriancoat" item_state = "ladiesvictoriancoat" /obj/item/clothing/suit/victcoat/red name = "ladies red victorian coat" icon_state = "ladiesredvictoriancoat" - item_state = "ladiesredvictoriancoat" \ No newline at end of file + item_state = "ladiesredvictoriancoat" diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm index 5f358ac58f4..8f4b65e6030 100644 --- a/code/modules/clothing/under/accessories/accessory.dm +++ b/code/modules/clothing/under/accessories/accessory.dm @@ -620,7 +620,7 @@ return var/area/t = get_area(M) - var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset(null) + var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset(src) if(istype(t, /area/syndicate_station) || istype(t, /area/syndicate_mothership) || istype(t, /area/shuttle/syndicate_elite) ) //give the syndicats a bit of stealth a.autosay("[M] has been vandalized in Space!", "[M]'s Death Alarm") diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 4fa40404c46..6dc1e1f2991 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -791,10 +791,10 @@ /obj/item/clothing/under/victdress name = "black victorian dress" - desc = "a victorian style dress, fancy!." + desc = "A victorian style dress, fancy!" icon_state = "victorianblackdress" - item_state = "Victorianblackdress" - item_color = "Victorianblackdress" + item_state = "victorianblackdress" + item_color = "victorianblackdress" body_parts_covered = UPPER_TORSO|LOWER_TORSO /obj/item/clothing/under/victdress/red @@ -805,7 +805,7 @@ /obj/item/clothing/under/victsuit name = "victorian suit" - desc = "a victorian style suit, fancy!." + desc = "A victorian style suit, fancy!" icon_state = "victorianvest" item_state = "victorianvest" item_color = "victorianvest" @@ -822,3 +822,11 @@ icon_state = "victorianredvest" item_state = "victorianredvest" item_color = "victorianredvest" + +/obj/item/clothing/under/medigown + name = "medical gown" + desc = "a flimsy examination gown, the back ties never close." + icon_state = "medicalgown" + item_state = "medicalgown" + item_color = "medicalgown" + body_parts_covered = UPPER_TORSO|LOWER_TORSO diff --git a/code/modules/countdown/countdown.dm b/code/modules/countdown/countdown.dm index 2ef85d6a9d7..7e651fb910f 100644 --- a/code/modules/countdown/countdown.dm +++ b/code/modules/countdown/countdown.dm @@ -9,15 +9,19 @@ var/atom/attached_to color = "#ff0000" var/text_size = 4 - var/started = 0 + var/started = FALSE invisibility = INVISIBILITY_OBSERVER - anchored = 1 - layer = 5 + anchored = TRUE + layer = GHOST_LAYER /obj/effect/countdown/New(atom/A) . = ..() attach(A) +/obj/effect/countdown/examine(mob/user) + . = ..() + to_chat(user, "This countdown is displaying: [displayed_text]") + /obj/effect/countdown/proc/attach(atom/A) attached_to = A loc = get_turf(A) @@ -25,13 +29,13 @@ /obj/effect/countdown/proc/start() if(!started) fast_processing += src - started = 1 + started = TRUE /obj/effect/countdown/proc/stop() if(started) maptext = null fast_processing -= src - started = 0 + started = FALSE /obj/effect/countdown/proc/get_value() // Get the value from our atom @@ -56,6 +60,19 @@ fast_processing -= src return ..() +/obj/effect/countdown/ex_act(severity) //immune to explosions + return + +/obj/effect/countdown/syndicatebomb + name = "syndicate bomb countdown" + +/obj/effect/countdown/syndicatebomb/get_value() + var/obj/machinery/syndicatebomb/S = attached_to + if(!istype(S)) + return + else if(S.active) + return S.seconds_remaining() + /obj/effect/countdown/clonepod name = "cloning pod countdown" text_size = 1 diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index 6f266c121e1..3fbcf39ed08 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -324,6 +324,30 @@ /obj/item/stack/rods = 1) category = CAT_MISC +/datum/crafting_recipe/chemical_payload + name = "Chemical Payload (C4)" + result = /obj/item/weapon/bombcore/chemical + reqs = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/grenade/plastic/c4 = 1, + /obj/item/weapon/grenade/chem_grenade = 2 + ) + parts = list(/obj/item/weapon/stock_parts/matter_bin = 1, /obj/item/weapon/grenade/chem_grenade = 2) + time = 30 + category = CAT_WEAPON + +/datum/crafting_recipe/chemical_payload2 + name = "Chemical Payload (gibtonite)" + result = /obj/item/weapon/bombcore/chemical + reqs = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/twohanded/required/gibtonite = 1, + /obj/item/weapon/grenade/chem_grenade = 2 + ) + parts = list(/obj/item/weapon/stock_parts/matter_bin = 1, /obj/item/weapon/grenade/chem_grenade = 2) + time = 50 + category = CAT_WEAPON + /datum/crafting_recipe/bonfire name = "Bonfire" time = 60 diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index 98fe9fad27f..8b98dac200d 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -137,6 +137,7 @@ var/list/event_last_fired = list() new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Trivial News", /datum/event/trivial_news, 400), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mundane News", /datum/event/mundane_news, 300), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Vermin Infestation",/datum/event/infestation, 100, list(ASSIGNMENT_JANITOR = 100)), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Sentience", /datum/event/sentience, 50), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Wallrot", /datum/event/wallrot, 0, list(ASSIGNMENT_ENGINEER = 30, ASSIGNMENT_GARDENER = 50)) ) diff --git a/code/modules/events/sentience.dm b/code/modules/events/sentience.dm new file mode 100644 index 00000000000..cfa0d24d98e --- /dev/null +++ b/code/modules/events/sentience.dm @@ -0,0 +1,47 @@ +/datum/event/sentience + +/datum/event/sentience/start() + var/ghostmsg = "Do you want to awaken as a sentient being?" + var/list/candidates = pollCandidates(ghostmsg, ROLE_SENTIENT, 1) + var/list/potential = list() + var/sentience_type = SENTIENCE_ORGANIC + + for(var/mob/living/simple_animal/L in living_mob_list) + var/turf/T = get_turf(L) + if (T.z != 1) + continue + if(!(L in player_list) && !L.mind && (L.sentience_type == sentience_type)) + potential += L + + var/mob/living/simple_animal/SA = pick(potential) + var/mob/SG = pick(candidates) + + if(!SA || !SG) //if you can't find either a simple animal or a player, end + return FALSE + + var/sentience_report = "[command_name()] Medium-Priority Update" + + var/data = pick("scans from our long-range sensors", "our sophisticated probabilistic models", "our omnipotence", "the communications traffic on your station", "energy emissions we detected", "\[REDACTED\]", "Steve") + var/pets = pick("animals", "pets", "simple animals", "lesser lifeforms", "\[REDACTED\]") + var/strength = pick("human", "skrell", "vox", "grey", "diona", "IPC", "tajaran", "vulpakanin", "kidan", "plasmaman", "drask", + "slime", "monkey", "moderate", "lizard", "security", "command", "clown", "mime", "low", "very low", "greytide", "catgirl", "\[REDACTED\]") + + sentience_report += "

    Based on [data], we believe that one of the station's [pets] has developed [strength] level intelligence, and the ability to communicate." + + + + SA.key = SG.key + SA.universal_speak = 1 + SA.sentience_act() + SA.maxHealth = max(SA.maxHealth, 200) + SA.health = SA.maxHealth + SA.del_on_death = FALSE + greet_sentient(SA) + print_command_report(sentience_report, "[command_name()] Update") + +/datum/event/sentience/proc/greet_sentient(var/mob/living/carbon/human/M) + to_chat(M, "Hello world!") + to_chat(M, "Due to freak radiation, you have gained \ + human level intelligence and the ability to speak and understand \ + human language!") + diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm index 36d84b0f72d..cc9ed1a27d6 100644 --- a/code/modules/mob/language.dm +++ b/code/modules/mob/language.dm @@ -96,6 +96,9 @@ return (copytext(message, length(message)) == "!") ? 2 : 1 /datum/language/proc/broadcast(mob/living/speaker, message, speaker_mask) + if(!check_can_speak(speaker)) + return FALSE + log_say("[key_name(speaker)]: ([name]) [message]") if(!speaker_mask) @@ -114,6 +117,9 @@ /datum/language/proc/check_special_condition(mob/other, mob/living/speaker) return TRUE +/datum/language/proc/check_can_speak(mob/living/speaker) + return TRUE + /datum/language/proc/get_spoken_verb(msg_end) switch(msg_end) if("!") @@ -292,8 +298,29 @@ /datum/language/grey/broadcast(mob/living/speaker, message, speaker_mask) ..(speaker,message,speaker.real_name) +/datum/language/grey/check_can_speak(mob/living/speaker) + if(ishuman(speaker)) + var/mob/living/carbon/human/S = speaker + var/obj/item/organ/external/rhand = S.get_organ("r_hand") + var/obj/item/organ/external/lhand = S.get_organ("l_hand") + if((!rhand || !rhand.is_usable()) && (!lhand || !lhand.is_usable())) + to_chat(speaker,"You can't communicate without the ability to use your hands!") + return FALSE + if(speaker.incapacitated(ignore_lying = 1)) + to_chat(speaker,"You can't communicate while unable to move your hands to your head!") + return FALSE + + var/their = "their" + if(speaker.gender == "female") + their = "her" + if(speaker.gender == "male") + their = "his" + speaker.visible_message("[speaker] touches [their] fingers to [their] temple.") //If placed in grey/broadcast, it will happen regardless of the success of the action. + + return TRUE + /datum/language/grey/check_special_condition(mob/living/carbon/human/other, mob/living/carbon/human/speaker) - if(other in range(7, speaker)) + if(atoms_share_level(other, speaker)) return TRUE return FALSE diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm index 7a12b570201..daeebf8442f 100644 --- a/code/modules/mob/living/carbon/brain/brain_item.dm +++ b/code/modules/mob/living/carbon/brain/brain_item.dm @@ -71,9 +71,9 @@ var/obj/item/organ/internal/brain/B = src if(!special) var/mob/living/simple_animal/borer/borer = owner.has_brain_worms() - if(borer) - borer.detach() //Should remove borer if the brain is removed - RR + borer.leave_host() //Should remove borer if the brain is removed - RR + if(owner.mind && !non_primary)//don't transfer if the owner does not have a mind. B.transfer_identity(user) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 8caecdb42d7..dd18495cc70 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -244,6 +244,10 @@ if(status == "") status = "OK" src.show_message(text("\t []My [] is [].",status=="OK"?"":"",org.name,status),1) + + for(var/obj/item/I in org.embedded_objects) + to_chat(src, "\t There is \a [I] embedded in your [org.name]!") + if(staminaloss) if(staminaloss > 30) to_chat(src, "You're completely exhausted.") diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 206571bec93..bfc2737d4d7 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -90,8 +90,10 @@ if(src) qdel(src) /mob/living/carbon/human/death(gibbed) - if(stat == DEAD) return - if(healths) healths.icon_state = "health5" + if(stat == DEAD) + return + if(healths) + healths.icon_state = "health5" if(!gibbed) emote("deathgasp") //let the world KNOW WE ARE DEAD @@ -102,21 +104,8 @@ set_heartattack(FALSE) //Handle species-specific deaths. - if(species) species.handle_death(src) - - //Handle brain slugs. - var/obj/item/organ/external/head = get_organ("head") - var/mob/living/simple_animal/borer/B - - if(istype(head)) - for(var/I in head.implants) - if(istype(I,/mob/living/simple_animal/borer)) - B = I - if(B) - if(B.controlling && B.host == src) - B.detach() - - verbs -= /mob/living/carbon/proc/release_control + if(species) + species.handle_death(src) callHook("death", list(src, gibbed)) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 693973ab42d..961ee9ffd0b 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -382,6 +382,9 @@ else wound_flavor_text["[temp.limb_name]"] = "" + for(var/obj/item/I in temp.embedded_objects) + msg += "[t_He] [t_has] \a [bicon(I)] [I] embedded in [t_his] [temp.name]!\n" + //Handles the text strings being added to the actual description. //If they have something that covers the limb, and it is not missing, put flavortext. If it is covered but bleeding, add other flavortext. var/display_chest = 0 @@ -438,9 +441,6 @@ if(display_gloves) msg += "[src] has blood running from under [t_his] gloves!\n" - - for(var/implant in get_visible_implants(0)) - msg += "[src] has \a [implant] sticking out of [t_his] flesh!\n" if(digitalcamo) msg += "[t_He] [t_is] repulsively uncanny!\n" if(!(skipface || ( wear_mask && ( wear_mask.flags_inv & HIDEFACE || wear_mask.flags_cover & MASKCOVERSMOUTH) ) ) && is_thrall(src) && in_range(user,src)) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 2fec182504a..8a39920cae1 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -8,7 +8,6 @@ //why are these here and not in human_defines.dm //var/list/hud_list[10] var/datum/species/species //Contains icon generation and language information, set during New(). - var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us. var/obj/item/weapon/rig/wearing_rig // This is very not good, but it's much much better than calling get_rig() every update_canmove() call. /mob/living/carbon/human/New(var/new_loc, var/new_species = null, var/delay_ready_dna = 0) @@ -597,7 +596,7 @@ return //repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere -/mob/living/carbon/human/get_visible_name() +/mob/living/carbon/human/get_visible_name(var/id_override = FALSE) if(name_override) return name_override if(wear_mask && (wear_mask.flags_inv & HIDEFACE)) //Wearing a mask which hides our face, use id-name if possible @@ -606,7 +605,7 @@ return get_id_name("Unknown") //Likewise for hats var/face_name = get_face_name() var/id_name = get_id_name("") - if(id_name && (id_name != face_name)) + if(id_name && (id_name != face_name) && !id_override) return "[face_name] (as [id_name])" return face_name @@ -700,6 +699,28 @@ if(G && G.pickpocket) thief_mode = 1 + if(href_list["embedded_object"]) + var/obj/item/organ/external/L = locate(href_list["embedded_limb"]) in bodyparts + if(!L) + return + var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects + if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore + return + var/time_taken = I.embedded_unsafe_removal_time*I.w_class + usr.visible_message("[usr] attempts to remove [I] from their [L.name].","You attempt to remove [I] from your [L.name]... (It will take [time_taken/10] seconds.)") + if(do_after(usr, time_taken, needhand = 1, target = src)) + if(!I || !L || I.loc != src || !(I in L.embedded_objects)) + return + L.embedded_objects -= I + L.take_damage(I.embedded_unsafe_removal_pain_multiplier*I.w_class)//It hurts to rip it out, get surgery you dingus. + I.forceMove(get_turf(src)) + usr.put_in_hands(I) + usr.emote("scream") + usr.visible_message("[usr] successfully rips [I] out of their [L.name]!","You successfully remove [I] from your [L.name].") + if(!has_embedded_objects()) + clear_alert("embeddedobject") + return + if(href_list["item"]) var/slot = text2num(href_list["item"]) if(slot in check_obscured_slots()) @@ -1348,16 +1369,6 @@ else ..() -/mob/living/carbon/human/get_visible_implants(var/class = 0) - - var/list/visible_implants = list() - for(var/obj/item/organ/external/organ in bodyparts) - for(var/obj/item/weapon/O in organ.implants) - if(!istype(O,/obj/item/weapon/implant) && (O.w_class > class) && !istype(O,/obj/item/weapon/shard/shrapnel)) - visible_implants += O - - return(visible_implants) - /mob/living/carbon/human/generate_name() name = species.makeName(gender,src) real_name = name @@ -1365,29 +1376,6 @@ dna.real_name = name return name -/mob/living/carbon/human/proc/handle_embedded_objects() - - for(var/obj/item/organ/external/organ in bodyparts) - if(organ.status & ORGAN_SPLINTED) //Splints prevent movement. - continue - for(var/obj/item/weapon/O in organ.implants) - if(!istype(O,/obj/item/weapon/implant) && prob(5)) //Moving with things stuck in you could be bad. - // All kinds of embedded objects cause bleeding. - var/msg = null - switch(rand(1,3)) - if(1) - msg ="A spike of pain jolts your [organ.name] as you bump [O] inside." - if(2) - msg ="Your movement jostles [O] in your [organ.name] painfully." - if(3) - msg ="[O] in your [organ.name] twists painfully as you move." - to_chat(src, msg) - - organ.take_damage(rand(1,3), 0, 0) - if(!(organ.status & ORGAN_ROBOT)) //There is no blood in protheses. - organ.status |= ORGAN_BLEEDING - src.adjustToxLoss(rand(1,3)) - /mob/living/carbon/human/verb/check_pulse() set category = null set name = "Check pulse" diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index bbe57fa66f9..917d9d9b0f7 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -8,7 +8,7 @@ emp_act */ -/mob/living/carbon/human/bullet_act(var/obj/item/projectile/P, var/def_zone) +/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone) if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) if(check_reflect(def_zone)) // Checks if you've passed a reflection% check @@ -41,19 +41,6 @@ emp_act . = bullet_act(P, "chest") //act on chest instead return - //Shrapnel - if(P.damage_type == BRUTE) - var/armor = getarmor_organ(organ, "bullet") - if((P.embed && prob(20 + max(P.damage - armor, -10)))) - var/obj/item/weapon/shard/shrapnel/SP = new() - (SP.name) = "[P.name] shrapnel" - if(P.ammo_casing && P.ammo_casing.caliber) - (SP.desc) = "[SP.desc] It looks like it is a [P.ammo_casing.caliber] caliber round." - else - (SP.desc) = "[SP.desc] The round's caliber is unidentifiable." - (SP.loc) = organ - organ.embed(SP) - organ.add_autopsy_data(P.name, P.damage) // Add the bullet's name to the autopsy data return (..(P , def_zone)) @@ -297,21 +284,6 @@ emp_act if(Iforce > 10 || Iforce >= 5 && prob(33)) forcesay(hit_appends) //forcesay checks stat already -/* //Melee weapon embedded object code. Commented out, as most people on the forums seem to find this annoying and think it does not contribute to general gameplay. - Dave - if(I.damtype == BRUTE && !I.is_robot_module()) - var/damage = I.force - if(armor) - damage /= armor+1 - - //blunt objects should really not be embedding in things unless a huge amount of force is involved - var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3) - var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class - - //Sharp objects will always embed if they do enough damage. - if(((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance))) && (I.no_embed == 0) ) - affecting.embed(I) - return 1*/ - //this proc handles being hit by a thrown atom /mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0) var/obj/item/I @@ -325,24 +297,19 @@ emp_act hitpush = 0 skipcatch = 1 blocked = 1 - /*else if(I) + else if(I) if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD) - if(!I.is_robot_module()) - var/armor = run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].", I.armour_penetration) //I guess "melee" is the best fit here - var/sharp = is_sharp(I) - var/damage = throwpower * (I.throw_speed / 5) - if(armor) - damage /= armor + 1 - - //blunt objects should really not be embedding in things unless a huge amount of force is involved - var/embed_chance = sharp? damage / I.w_class : damage/(I.w_class * 3) - var/embed_threshold = sharp? 5 * I.w_class : 15 * I.w_class - - //Sharp objects will always embed if they do enough damage. - //Thrown sharp objects have some momentum already and have a small chance to embed even if the damage is below the threshold - - if(((sharp && prob(damage / (10 * I.w_class) * 100)) || (damage > embed_threshold && prob(embed_chance))) && (I.no_embed == 0)) - affecting.embed(I)*/ + if(can_embed(I)) + if(prob(I.embed_chance)) + throw_alert("embeddedobject", /obj/screen/alert/embeddedobject) + var/obj/item/organ/external/L = pick(bodyparts) + L.embedded_objects |= I +// I.add_mob_blood(src)//it embedded itself in you, of course it's bloody! + I.forceMove(src) + L.take_damage(I.w_class*I.embedded_impact_pain_multiplier) + visible_message("[I] embeds itself in [src]'s [L.name]!","[I] embeds itself in your [L.name]!") + hitpush = 0 + skipcatch = 1 //can't catch the now embedded item return ..() /mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2) @@ -421,5 +388,5 @@ emp_act /mob/living/carbon/human/water_act(volume, temperature, source) ..() - if(temperature >= 330) bodytemperature = bodytemperature + (temperature - bodytemperature) - if(temperature <= 280) bodytemperature = bodytemperature - (bodytemperature - temperature) + species.water_act(src,volume,temperature,source) + diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 5a67b1c09a2..cba5e4eb458 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -40,6 +40,10 @@ if(!client) species.handle_npc(src) + if(stat != DEAD) + //Stuff jammed in your limbs hurts + handle_embedded_objects() + if(stat == DEAD) handle_decay() @@ -814,13 +818,6 @@ blinded = 1 stat = UNCONSCIOUS - if(embedded_flag && !(mob_master.current_cycle % 10)) - var/list/E - E = get_visible_implants(0) - if(!E.len) - embedded_flag = 0 - - //Vision //god knows why this is here var/obj/item/organ/vision if(species.vision_organ) @@ -933,6 +930,22 @@ adjustToxLoss(-3) lastpuke = 0 +/mob/living/carbon/human/proc/handle_embedded_objects() + for(var/X in bodyparts) + var/obj/item/organ/external/BP = X + for(var/obj/item/I in BP.embedded_objects) + if(prob(I.embedded_pain_chance)) + BP.take_damage(I.w_class*I.embedded_pain_multiplier) + to_chat(src, "[I] embedded in your [BP.name] hurts!") + + if(prob(I.embedded_fall_chance)) + BP.take_damage(I.w_class*I.embedded_fall_pain_multiplier) + BP.embedded_objects -= I + I.forceMove(get_turf(src)) + visible_message("[I] falls out of [name]'s [BP.name]!","[I] falls out of your [BP.name]!") + if(!has_embedded_objects()) + clear_alert("embeddedobject") + /mob/living/carbon/human/handle_changeling() if(mind) if(mind.changeling) diff --git a/code/modules/mob/living/carbon/human/species/plasmaman.dm b/code/modules/mob/living/carbon/human/species/plasmaman.dm index 9f5d32e838a..4563fb2029f 100644 --- a/code/modules/mob/living/carbon/human/species/plasmaman.dm +++ b/code/modules/mob/living/carbon/human/species/plasmaman.dm @@ -49,9 +49,12 @@ var/tank_slot_name = "suit storage" switch(assigned_role) - if("Scientist","Geneticist","Roboticist") + if("Scientist","Roboticist") suit=/obj/item/clothing/suit/space/eva/plasmaman/science helm=/obj/item/clothing/head/helmet/space/eva/plasmaman/science + if("Geneticist") + suit=/obj/item/clothing/suit/space/eva/plasmaman/science/geneticist + helm=/obj/item/clothing/head/helmet/space/eva/plasmaman/science/geneticist if("Research Director") suit=/obj/item/clothing/suit/space/eva/plasmaman/science/rd helm=/obj/item/clothing/head/helmet/space/eva/plasmaman/science/rd @@ -103,6 +106,12 @@ if("Chief Medical Officer") suit=/obj/item/clothing/suit/space/eva/plasmaman/medical/cmo helm=/obj/item/clothing/head/helmet/space/eva/plasmaman/medical/cmo + if("Coroner") + suit=/obj/item/clothing/suit/space/eva/plasmaman/medical/coroner + helm=/obj/item/clothing/head/helmet/space/eva/plasmaman/medical/coroner + if("Virologist") + suit=/obj/item/clothing/suit/space/eva/plasmaman/medical/virologist + helm=/obj/item/clothing/head/helmet/space/eva/plasmaman/medical/virologist if("Bartender", "Chef") suit=/obj/item/clothing/suit/space/eva/plasmaman/service helm=/obj/item/clothing/head/helmet/space/eva/plasmaman/service diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index c1d1a169c1d..52e5de89876 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -399,9 +399,6 @@ if(has_gravity(H)) gravity = 1 - if(H.embedded_flag) - H.handle_embedded_objects() //Moving with objects stuck in you can cause bad times. - if(!ignoreslow && gravity) if(slowdown) . = slowdown @@ -743,3 +740,9 @@ It'll return null if the organ doesn't correspond, so include null checks when u if(H.see_override) //Override all H.see_invisible = H.see_override + +/datum/species/proc/water_act(mob/living/carbon/human/M, volume, temperature, source) + if(temperature >= 330) + M.bodytemperature = M.bodytemperature + (temperature - M.bodytemperature) + if(temperature <= 280) + M.bodytemperature = M.bodytemperature - (M.bodytemperature - temperature) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index 52c66369fe9..60e71f7e8ab 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -753,6 +753,11 @@ genemutcheck(C,REMOTETALKBLOCK,null,MUTCHK_FORCED) ..() +/datum/species/grey/water_act(var/mob/living/carbon/C, volume, temperature, source) + ..() + C.take_organ_damage(5,min(volume,20)) + C.emote("scream") + /datum/species/grey/after_equip_job(datum/job/J, mob/living/carbon/human/H) var/speech_pref = H.client.prefs.speciesprefs if(speech_pref) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 90003c12e65..7215c05a8e2 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -512,6 +512,7 @@ human_mob.restore_blood() human_mob.shock_stage = 0 human_mob.decaylevel = 0 + human_mob.remove_all_embedded_objects() restore_all_organs() surgeries.Cut() //End all surgeries. diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 16c8f1a3ef0..3454a6597ab 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -260,10 +260,6 @@ stored_comms["glass"]++ else if(istype(W,/obj/item/ammo_casing)) stored_comms["metal"]++ - else if(istype(W,/obj/item/weapon/shard/shrapnel)) - stored_comms["metal"]++ - stored_comms["metal"]++ - stored_comms["metal"]++ else if(istype(W,/obj/item/weapon/shard)) stored_comms["glass"]++ stored_comms["glass"]++ diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 226e568f09e..aadd5a74c1b 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1052,104 +1052,6 @@ var/list/slot_equipment_priority = list( \ /mob/proc/get_species() return "" -/mob/proc/get_visible_implants(var/class = 0) - var/list/visible_implants = list() - for(var/obj/item/O in embedded) - if(O.w_class > class) - visible_implants += O - return visible_implants - -/mob/proc/yank_out_object() - set category = "Object" - set name = "Yank out object" - set desc = "Remove an embedded item at the cost of bleeding and pain." - set src in view(1) - - if(!isliving(usr) || usr.next_move > world.time) - return - usr.changeNext_move(CLICK_CD_RESIST) - - if(usr.stat == 1) - to_chat(usr, "You are unconcious and cannot do that!") - return - - if(usr.restrained()) - to_chat(usr, "You are restrained and cannot do that!") - return - - var/mob/S = src - var/mob/U = usr - var/list/valid_objects = list() - var/self = null - - if(S == U) - self = 1 // Removing object from yourself. - - valid_objects = get_visible_implants(0) - if(!valid_objects.len) - if(self) - to_chat(src, "You have nothing stuck in your body that is large enough to remove.") - else - to_chat(U, "[src] has nothing stuck in their wounds that is large enough to remove.") - return - - var/obj/item/weapon/selection = input("What do you want to yank out?", "Embedded objects") in valid_objects - - if(self) - visible_message("[usr] appears to be trying to extract an object from their body.") - to_chat(src, "You attempt to get a good grip on [selection] in your body.") - else - visible_message("[usr] attempts to get a good grip on [selection] in [S]'s body.") - to_chat(U, "You attempt to get a good grip on [selection] in [S]'s body.") - - if(!do_after(U, 80, target = S)) - return - if(!selection || !S || !U) - return - - if(self) - visible_message("[src] rips [selection] out of their body.","You rip [selection] out of your body.") - else - visible_message("[usr] rips [selection] out of [src]'s body.","[usr] rips [selection] out of your body.") - valid_objects = get_visible_implants(0) - if(valid_objects.len == 1) //Yanking out last object - removing verb. - src.verbs -= /mob/proc/yank_out_object - - if(ishuman(src)) - - var/mob/living/carbon/human/H = src - var/obj/item/organ/external/affected - - for(var/obj/item/organ/external/organ in H.bodyparts) //Grab the organ holding the implant. - for(var/obj/item/weapon/O in organ.implants) - if(O == selection) - affected = organ - - affected.implants -= selection - H.shock_stage+=10 - - if(prob(10)) //I'M SO ANEMIC I COULD JUST -DIE-. - var/datum/wound/internal_bleeding/I = new () - affected.wounds += I - H.custom_pain("Something tears wetly in your [affected] as [selection] is pulled free!", 1) - - if(ishuman(U)) - var/mob/living/carbon/human/human_user = U - human_user.bloody_hands(H) - - selection.forceMove(get_turf(src)) - if(!(U.l_hand && U.r_hand)) - U.put_in_hands(selection) - - for(var/obj/item/weapon/O in pinned) - if(O == selection) - pinned -= O - if(!pinned.len) - anchored = 0 - return 1 - - - /mob/dead/observer/verb/respawn() set name = "Respawn as NPC" set category = "Ghost" diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 700e5d912e7..25131513c4d 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -53,8 +53,6 @@ var/lastpuke = 0 var/unacidable = 0 var/can_strip = 1 - var/list/pinned = list() //List of things pinning this creature to walls (see living_defense.dm) - var/list/embedded = list() //Embedded items, since simple mobs don't have organs. var/list/languages = list() // For speaking/listening. var/list/abilities = list() // For species-derived or admin-given powers. var/list/speak_emote = list("says") // Verbs used when speaking. Defaults to 'say' if speak_emote is null. @@ -122,6 +120,7 @@ var/has_enabled_antagHUD = 0 var/antagHUD = 0 + var/can_change_intents = 1 //all mobs can change intents by default. //Generic list for proc holders. Only way I can see to enable certain verbs/procs. Should be modified if needed. var/proc_holder_list[] = list() diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index f8b8f7c84d7..43b12417215 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -242,7 +242,7 @@ proc/slur(phrase, var/list/slurletters = ("'"))//use a different list as an inpu return sanitize(copytext(t,1,MAX_MESSAGE_LEN)) -proc/Gibberish(t, p)//t is the inputted message, and any value higher than 70 for p will cause letters to be replaced instead of added +/proc/Gibberish(t, p)//t is the inputted message, and any value higher than 70 for p will cause letters to be replaced instead of added /* Turn text into complete gibberish! */ var/returntext = "" for(var/i = 1, i <= length(t), i++) @@ -337,30 +337,31 @@ var/list/intents = list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM) set name = "a-intent" set hidden = 1 - if(ishuman(src) || isalienadult(src) || isbrain(src)) - switch(input) - if(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM) - a_intent = input - if("right") - a_intent = intent_numeric((intent_numeric(a_intent)+1) % 4) - if("left") - a_intent = intent_numeric((intent_numeric(a_intent)+3) % 4) - if(hud_used && hud_used.action_intent) - hud_used.action_intent.icon_state = "[a_intent]" + if(can_change_intents) + if(ishuman(src) || isalienadult(src) || isbrain(src)) + switch(input) + if(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM) + a_intent = input + if("right") + a_intent = intent_numeric((intent_numeric(a_intent)+1) % 4) + if("left") + a_intent = intent_numeric((intent_numeric(a_intent)+3) % 4) + if(hud_used && hud_used.action_intent) + hud_used.action_intent.icon_state = "[a_intent]" - else if(isrobot(src) || islarva(src)) - switch(input) - if(INTENT_HELP) - a_intent = INTENT_HELP - if(INTENT_HARM) - a_intent = INTENT_HARM - if("right","left") - a_intent = intent_numeric(intent_numeric(a_intent) - 3) - if(hud_used && hud_used.action_intent) - if(a_intent == INTENT_HARM) - hud_used.action_intent.icon_state = "harm" - else - hud_used.action_intent.icon_state = "help" + else if(isrobot(src) || islarva(src)) + switch(input) + if(INTENT_HELP) + a_intent = INTENT_HELP + if(INTENT_HARM) + a_intent = INTENT_HARM + if("right","left") + a_intent = intent_numeric(intent_numeric(a_intent) - 3) + if(hud_used && hud_used.action_intent) + if(a_intent == INTENT_HARM) + hud_used.action_intent.icon_state = "harm" + else + hud_used.action_intent.icon_state = "help" /mob/living/verb/mob_sleep() diff --git a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm index 20c4e92fd98..a868c0958ea 100644 --- a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm +++ b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm @@ -43,7 +43,7 @@ if(!istype(file)) data["error"] = "I/O ERROR: Unable to open file." else - data["filedata"] = pencode_to_html(file.stored_data, sign = 0, fields = 0) + data["filedata"] = pencode_to_html(file.stored_data, format = 1, sign = 0, fields = 0) data["filename"] = "[file.filename].[file.filetype]" else if(!computer || !HDD) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 250abe3d682..cd5b065b3ca 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -203,7 +203,7 @@ /obj/item/weapon/paper/proc/parsepencode(var/t, var/obj/item/weapon/pen/P, mob/user as mob) - t = pencode_to_html(t, usr, P, TRUE, TRUE, deffont, signfont, crayonfont) + t = pencode_to_html(t, usr, P, TRUE, TRUE, TRUE, deffont, signfont, crayonfont) //Count the fields var/laststart = 1 diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 9f5d3534215..7780f057b19 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -159,6 +159,7 @@ w_class = initial(w_class) name = initial(name) hitsound = initial(hitsound) + embed_chance = initial(embed_chance) throwforce = initial(throwforce) playsound(user, 'sound/weapons/saberoff.ogg', 5, 1) to_chat(user, "[src] can now be concealed.") @@ -170,6 +171,7 @@ w_class = WEIGHT_CLASS_NORMAL name = "energy dagger" hitsound = 'sound/weapons/blade1.ogg' + embed_chance = 100 //rule of cool throwforce = 35 playsound(user, 'sound/weapons/saberon.ogg', 5, 1) to_chat(user, "[src] is now active.") diff --git a/code/modules/projectiles/guns/alien.dm b/code/modules/projectiles/guns/alien.dm index f541ca2a94a..5900e9a249e 100644 --- a/code/modules/projectiles/guns/alien.dm +++ b/code/modules/projectiles/guns/alien.dm @@ -101,6 +101,5 @@ flag = "bullet" pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE - embed = 0 weaken = 5 stun = 5 diff --git a/code/modules/projectiles/guns/throw/crossbow.dm b/code/modules/projectiles/guns/throw/crossbow.dm index 77d3e89eade..a06aac35be5 100644 --- a/code/modules/projectiles/guns/throw/crossbow.dm +++ b/code/modules/projectiles/guns/throw/crossbow.dm @@ -170,8 +170,6 @@ /obj/item/weapon/arrow/rod/removed() if(superheated) // The rod has been superheated - we don't want it to be useable when removed from the bow. visible_message("[src] shatters into a scattering of overstressed metal shards as it leaves the crossbow.") - var/obj/item/weapon/shard/shrapnel/S = new /obj/item/weapon/shard/shrapnel - S.loc = get_turf(src) qdel(src) #undef XBOW_TENSION_20 diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 4a3afd18684..20957e18786 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -48,7 +48,6 @@ var/drowsy = 0 var/stamina = 0 var/jitter = 0 - var/embed = 0 // whether or not the projectile can embed itself in the mob var/forcedodge = 0 //to pass through everything var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all. diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 7434038eb91..2c55431fba0 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -4,7 +4,6 @@ damage = 60 damage_type = BRUTE flag = "bullet" - embed = 1 sharp = 1 hitsound_wall = "ricochet" @@ -14,11 +13,9 @@ stamina = 80 /obj/item/projectile/bullet/weakbullet/rubber //beanbag that shells that don't embed - embed = 0 sharp = 0 /obj/item/projectile/bullet/weakbullet/booze - embed = 0 /obj/item/projectile/bullet/weakbullet/booze/on_hit(atom/target, blocked = 0) if(..(target, blocked)) @@ -45,7 +42,6 @@ icon_state = "bullet-r" /obj/item/projectile/bullet/weakbullet2/rubber //detective's bullets that don't embed - embed = 0 sharp = 0 /obj/item/projectile/bullet/weakbullet3 @@ -56,7 +52,6 @@ damage = 5 stamina = 30 icon_state = "bullet-r" - embed = 0 sharp = 0 /obj/item/projectile/bullet/toxinbullet @@ -145,7 +140,6 @@ name = "rubber pellet" damage = 3 stamina = 25 - embed = 0 sharp = 0 icon_state = "bullet-r" @@ -157,7 +151,6 @@ stutter = 5 jitter = 20 range = 7 - embed = 0 sharp = 0 icon_state = "spark" color = "#FFFF00" @@ -209,7 +202,6 @@ stun = 5 forcedodge = 1 nodamage = 1 - embed = 0 sharp = 0 pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE hitsound = 'sound/items/bikehorn.ogg' @@ -244,7 +236,6 @@ name = "dart" icon_state = "cbbolt" damage = 6 - embed = 0 sharp = 0 var/piercing = 0 @@ -307,7 +298,6 @@ name = "cap" damage = 0 nodamage = 1 - embed = 0 sharp = 0 /obj/item/projectile/bullet/cap/fire() diff --git a/code/modules/projectiles/projectile/force.dm b/code/modules/projectiles/projectile/force.dm index 4e5c6d27700..4d62550a852 100644 --- a/code/modules/projectiles/projectile/force.dm +++ b/code/modules/projectiles/projectile/force.dm @@ -4,7 +4,6 @@ icon_state = "ice_1" damage = 20 flag = "energy" - embed = 1 /obj/item/projectile/forcebolt/strong name = "force bolt" diff --git a/code/modules/projectiles/projectile/reusable.dm b/code/modules/projectiles/projectile/reusable.dm index a223f415165..8592a7a46ee 100644 --- a/code/modules/projectiles/projectile/reusable.dm +++ b/code/modules/projectiles/projectile/reusable.dm @@ -36,7 +36,6 @@ range = 10 var/obj/item/weapon/pen/pen = null edge = 0 - embed = 0 log_override = TRUE//it won't log even when there's a pen inside, but since the damage will be so low, I don't think there's any point in making it any more complex /obj/item/projectile/bullet/reusable/foam_dart/handle_drop() diff --git a/code/modules/reagents/chem_splash.dm b/code/modules/reagents/chem_splash.dm new file mode 100644 index 00000000000..7c16bf1ab9a --- /dev/null +++ b/code/modules/reagents/chem_splash.dm @@ -0,0 +1,78 @@ +// Replaces chemgrenade stuff, allowing reagent explosions to be called from anywhere. +// It should be called using a location, the range, and a list of reagents involved. + +// Threatscale is a multiplier for the 'threat' of the grenade. If you're increasing the affected range drastically, you might want to improve this. +// Extra heat affects the temperature of the mixture, and may cause it to react in different ways. + + +/proc/chem_splash(turf/epicenter, affected_range = 3, list/datum/reagents/reactants = list(), extra_heat = 0, threatscale = 1, adminlog = 1) + if(!isturf(epicenter) || !reactants.len || threatscale <= 0) + return + var/has_reagents + var/total_reagents + for(var/datum/reagents/R in reactants) + if(R.total_volume) + has_reagents = 1 + total_reagents += R.total_volume + + if(!has_reagents) + return + + var/datum/reagents/splash_holder = new/datum/reagents(total_reagents*threatscale) + splash_holder.my_atom = epicenter // For some reason this is setting my_atom to null, and causing runtime errors. + var/total_temp = 0 + + for(var/datum/reagents/R in reactants) + R.trans_to(splash_holder, R.total_volume, threatscale, 1, 1) + total_temp += R.chem_temp + splash_holder.chem_temp = (total_temp/reactants.len) + extra_heat // Average temperature of reagents + extra heat. + splash_holder.handle_reactions() // React them now. + + if(splash_holder.total_volume && affected_range >= 0) //The possible reactions didnt use up all reagents, so we spread it around. + var/datum/effect/system/steam_spread/steam = new /datum/effect/system/steam_spread() + steam.set_up(10, 0, epicenter) + steam.attach(epicenter) + steam.start() + + var/list/viewable = view(affected_range, epicenter) + + var/list/accessible = list(epicenter) + for(var/i=1; i<=affected_range; i++) + var/list/turflist = list() + for(var/turf/T in (orange(i, epicenter) - orange(i-1, epicenter))) + turflist |= T + for(var/turf/T in turflist) + if( !(get_dir(T,epicenter) in cardinal) && (abs(T.x - epicenter.x) == abs(T.y - epicenter.y) )) + turflist.Remove(T) + turflist.Add(T) // we move the purely diagonal turfs to the end of the list. + for(var/turf/T in turflist) + if(accessible[T]) + continue + for(var/thing in T.GetAtmosAdjacentTurfs(alldir = TRUE)) + var/turf/NT = thing + if(!(NT in accessible)) + continue + if(!(get_dir(T,NT) in cardinal)) + continue + accessible[T] = 1 + break + var/list/reactable = accessible + for(var/turf/T in accessible) + for(var/atom/A in T.GetAllContents()) + if(!(A in viewable)) + continue + reactable |= A + if(extra_heat >= 300) + T.hotspot_expose(extra_heat*2, 5) + if(!reactable.len) //Nothing to react with. Probably means we're in nullspace. + return + for(var/thing in reactable) + var/atom/A = thing + var/distance = max(1,get_dist(A, epicenter)) + var/fraction = 0.5/(2 ** distance) //50/25/12/6... for a 200u splash, 25/12/6/3... for a 100u, 12/6/3/1 for a 50u + splash_holder.reaction(A, TOUCH, fraction) + + qdel(splash_holder) + return 1 + + diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index c65c628353b..662843e337a 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -108,7 +108,7 @@ var/const/INGEST = 2 return the_id -/datum/reagents/proc/trans_to(target, amount=1, multiplier=1, preserve_data=1)//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred. +/datum/reagents/proc/trans_to(target, amount=1, multiplier=1, preserve_data=1, no_react = 0)//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred. if(!target) return if(total_volume <= 0) @@ -143,13 +143,14 @@ var/const/INGEST = 2 if(preserve_data) trans_data = copy_data(current_reagent) - R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data, chem_temp) + R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data, chem_temp, no_react = 1) remove_reagent(current_reagent.id, current_reagent_transfer) update_total() R.update_total() - R.handle_reactions() - handle_reactions() + if(!no_react) + R.handle_reactions() + handle_reactions() return amount /datum/reagents/proc/copy_to(obj/target, amount=1, multiplier=1, preserve_data=1, safety = 0) @@ -537,7 +538,7 @@ var/const/INGEST = 2 var/amt = list_reagents[r_id] add_reagent(r_id, amt, data) -/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300) +/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, no_react = 0) if(!isnum(amount)) return 1 update_total() @@ -554,7 +555,8 @@ var/const/INGEST = 2 update_total() my_atom.on_reagent_change() R.on_merge(data) - handle_reactions() + if(!no_react) + handle_reactions() return 0 var/datum/reagent/D = chemical_reagents_list[reagent] @@ -570,7 +572,8 @@ var/const/INGEST = 2 update_total() my_atom.on_reagent_change() - handle_reactions() + if(!no_react) + handle_reactions() return 0 else warning("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])") diff --git a/code/modules/reagents/chemistry/reagents/misc.dm b/code/modules/reagents/chemistry/reagents/misc.dm index 241370668e0..9670c80afef 100644 --- a/code/modules/reagents/chemistry/reagents/misc.dm +++ b/code/modules/reagents/chemistry/reagents/misc.dm @@ -371,10 +371,12 @@ description = "What is this emotion you humans call \"love?\" Oh, it's this? This is it? Huh, well okay then, thanks." reagent_state = LIQUID color = "#FF83A5" + process_flags = ORGANIC | SYNTHETIC // That's the power of love~ /datum/reagent/love/on_mob_life(mob/living/M) - if(M.a_intent == INTENT_HARM) - M.a_intent = INTENT_HELP + if(M.a_intent != INTENT_HELP) + M.a_intent_change(INTENT_HELP) + M.can_change_intents = 0 //Now you have no choice but to be helpful. if(prob(8)) var/lovely_phrase = pick("appreciated", "loved", "pretty good", "really nice", "pretty happy with yourself, even though things haven't always gone as well as they could") @@ -391,9 +393,14 @@ break ..() +/datum/reagent/love/on_mob_delete(mob/living/M) + M.can_change_intents = 1 + ..() + /datum/reagent/love/reaction_mob(mob/living/M, method=TOUCH, volume) to_chat(M, "You feel loved!") + /datum/reagent/royal_bee_jelly name = "royal bee jelly" id = "royal_bee_jelly" diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm index 40d9cb1c481..8aa18899ac1 100644 --- a/code/modules/reagents/chemistry/reagents/toxins.dm +++ b/code/modules/reagents/chemistry/reagents/toxins.dm @@ -221,6 +221,8 @@ if(method == TOUCH) if(ishuman(M)) var/mob/living/carbon/human/H = M + if(H.get_species() == "Grey") + return if(volume > 25) @@ -247,6 +249,8 @@ if(method == INGEST) if(ishuman(M)) var/mob/living/carbon/human/H = M + if(H.get_species() == "Grey") + return if(volume < 10) to_chat(M, "The greenish acidic substance stings you, but isn't concentrated enough to harm you!") diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm index 70d2a9f76c0..773d03c6006 100644 --- a/code/modules/reagents/chemistry/reagents/water.dm +++ b/code/modules/reagents/chemistry/reagents/water.dm @@ -20,10 +20,65 @@ drink_desc = "The father of all refreshments." /datum/reagent/water/reaction_mob(mob/living/M, method=TOUCH, volume) -// Put out fire if(method == TOUCH) + // Put out fire M.adjust_fire_stacks(-(volume / 10)) M.ExtinguishMob() + if(ishuman(M)) + + var/mob/living/carbon/human/H = M + + if(H.get_species() != "Grey") //God this is so gross I hate it. + return + + if(volume > 25) + + if(H.wear_mask) + to_chat(H, "Your mask protects you from the water!") + return + + if(H.head) + to_chat(H, "Your helmet protects you from the water!") + return + + if(!M.unacidable) + if(prob(75)) + var/obj/item/organ/external/affecting = H.get_organ("head") + if(affecting) + affecting.take_damage(5, 10) + H.UpdateDamageIcon() + H.emote("scream") + else + M.take_organ_damage(5,10) + else + M.take_organ_damage(5,10) + + if(method == INGEST) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + + if(H.get_species() != "Grey") + return + + if(volume < 10) + to_chat(M, "The watery solvent substance stings you, but isn't concentrated enough to harm you!") + + if(volume >=10 && volume <=25) + if(!H.unacidable) + M.take_organ_damage(0,min(max(volume-10,2)*2,20)) + M.emote("scream") + + + if(volume > 25) + if(!M.unacidable) + if(prob(75)) + var/obj/item/organ/external/affecting = H.get_organ("head") + if(affecting) + affecting.take_damage(0, 20) + H.UpdateDamageIcon() + H.emote("scream") + else + M.take_organ_damage(0,20) /datum/reagent/water/reaction_turf(turf/simulated/T, volume) if(!istype(T)) diff --git a/code/modules/reagents/reagent_containers/glass_containers.dm b/code/modules/reagents/reagent_containers/glass_containers.dm index f60efa3b784..63db086cef8 100644 --- a/code/modules/reagents/reagent_containers/glass_containers.dm +++ b/code/modules/reagents/reagent_containers/glass_containers.dm @@ -40,7 +40,8 @@ /obj/machinery/biogenerator, /obj/machinery/hydroponics, /obj/machinery/constructable_frame, - /obj/machinery/icemachine) + /obj/machinery/icemachine, + /obj/item/weapon/bombcore/chemical) /obj/item/weapon/reagent_containers/glass/New() ..() diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index d406dcaf0ef..eb43698d451 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -29,6 +29,7 @@ /obj/structure/reagent_dispensers/proc/boom() visible_message("[src] ruptures!") + chem_splash(loc, 5, list(reagents)) qdel(src) /obj/structure/reagent_dispensers/ex_act(severity) @@ -53,15 +54,6 @@ desc = "A water tank." icon_state = "water" -/obj/structure/reagent_dispensers/watertank/boom() - playsound(loc, 'sound/effects/spray2.ogg', 50, 1, -6) - new /obj/effect/effect/water(loc) - for(var/turf/simulated/T in view(5, loc)) - T.MakeSlippery() - for(var/mob/living/L in T) - L.adjust_fire_stacks(-20) - ..() - /obj/structure/reagent_dispensers/watertank/high name = "high-capacity water tank" desc = "A highly-pressurized water tank made to hold gargantuan amounts of water.." diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 9391af77424..09b17748dfd 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -80,6 +80,36 @@ build_path = /obj/item/weapon/grenade/chem_grenade/large category = list("Weapons") +/datum/design/pyro_grenade + name = "Pyro Grenade" + desc = "An advanced grenade that is able to self ignite its mixture." + id = "pyro_Grenade" + req_tech = list("combat" = 4, "engineering" = 4) + build_type = PROTOLATHE + materials = list(MAT_METAL = 2000, MAT_PLASMA = 500) + build_path = /obj/item/weapon/grenade/chem_grenade/pyro + category = list("Weapons") + +/datum/design/cryo_grenade + name = "Cryo Grenade" + desc = "An advanced grenade that rapidly cools its contents upon detonation." + id = "cryo_Grenade" + req_tech = list("combat" = 3, "materials" = 3) + build_type = PROTOLATHE + materials = list(MAT_METAL = 2000, MAT_SILVER = 500) + build_path = /obj/item/weapon/grenade/chem_grenade/cryo + category = list("Weapons") + +/datum/design/adv_grenade + name = "Advanced Release Grenade" + desc = "An advanced grenade that can be detonated several times, best used with a repeating igniter." + id = "adv_Grenade" + req_tech = list("combat" = 3, "engineering" = 4) + build_type = PROTOLATHE + materials = list(MAT_METAL = 3000, MAT_GLASS = 500) + build_path = /obj/item/weapon/grenade/chem_grenade/adv_release + category = list("Weapons") + /datum/design/tele_shield name = "Telescopic Riot Shield" desc = "An advanced riot shield made of lightweight materials that collapses for easy storage." diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/cavity_implant.dm similarity index 53% rename from code/modules/surgery/implant.dm rename to code/modules/surgery/cavity_implant.dm index 498976c4635..bd82e7192ae 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/cavity_implant.dm @@ -1,10 +1,3 @@ -//Procedures in this file: Putting items in body cavity. Implant removal. Items removal. - - -////////////////////////////////////////////////////////////////// -// ITEM PLACEMENT SURGERY // -////////////////////////////////////////////////////////////////// - /datum/surgery/cavity_implant name = "Cavity Implant/Removal" steps = list(/datum/surgery_step/generic/cut_open,/datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/open_encased/saw, @@ -199,198 +192,15 @@ affected.wounds += I affected.owner.custom_pain("You feel something rip in your [affected.name]!", 1) user.drop_item() - target.internal_organs += tool + affected.hidden = tool tool.forceMove(affected) return 1 else if(IC) user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "You pull [IC] out of [target]'s [target_zone].") user.put_in_hands(IC) - target.internal_organs -= IC + affected.hidden = null return 1 else to_chat(user, "You don't find anything in [target]'s [target_zone].") - return 0 - - -////////////////////////////////////////////////////////////////// -// IMPLANT/ITEM REMOVAL SURGERY // -////////////////////////////////////////////////////////////////// - -/datum/surgery/cavity_implant_rem - name = "Implant Removal" - steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin,/datum/surgery_step/cavity/implant_removal,/datum/surgery_step/cavity/close_space,/datum/surgery_step/generic/cauterize/) - possible_locs = list("chest")//head is for borers..i can put it elsewhere - -/datum/surgery/cavity_implant_rem/synth - name = "Implant Removal" - steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/cavity/implant_removal,/datum/surgery_step/robotics/external/close_hatch) - possible_locs = list("chest")//head is for borers..i can put it elsewhere - -/datum/surgery/cavity_implant_rem/can_start(mob/user, mob/living/carbon/human/target) - if(!istype(target)) - return 0 - var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting) - if(!affected) - return 0 - if(affected.status & ORGAN_ROBOT) - return 0 - return 1 - -/datum/surgery/cavity_implant_rem/synth/can_start(mob/user, mob/living/carbon/human/target) - if(!istype(target)) - return 0 - var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting) - if(!affected) - return 0 - if(!(affected.status & ORGAN_ROBOT)) - return 0 - - return 1 - -/datum/surgery_step/cavity/implant_removal - name = "extract implant" - allowed_tools = list( - /obj/item/weapon/hemostat = 100, \ - /obj/item/weapon/wirecutters = 75, \ - /obj/item/weapon/kitchen/utensil/fork = 20 - ) - var/obj/item/weapon/implant/I = null - time = 64 - -/datum/surgery_step/cavity/implant_removal/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - I = locate(/obj/item/weapon/implant) in target - user.visible_message("[user] starts poking around inside [target]'s [affected.name] with \the [tool].", \ - "You start poking around inside [target]'s [affected.name] with \the [tool]." ) - target.custom_pain("The pain in your [affected.name] is living hell!",1) - ..() - -/datum/surgery_step/cavity/implant_removal/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery) - var/obj/item/organ/external/affected = target.get_organ(target_zone) - I = locate(/obj/item/weapon/implant) in target - if(I && (target_zone == "chest")) //implant removal only works on the chest. - user.visible_message("[user] takes something out of [target]'s [affected.name] with \the [tool].", \ - "You take [I] out of [target]'s [affected.name]s with \the [tool]." ) - - I.removed(target) - - var/obj/item/weapon/implantcase/case - - if(istype(user.get_item_by_slot(slot_l_hand), /obj/item/weapon/implantcase)) - case = user.get_item_by_slot(slot_l_hand) - else if(istype(user.get_item_by_slot(slot_r_hand), /obj/item/weapon/implantcase)) - case = user.get_item_by_slot(slot_r_hand) - else - case = locate(/obj/item/weapon/implantcase) in get_turf(target) - - if(case && !case.imp) - case.imp = I - I.loc = case - case.update_icon() - user.visible_message("[user] places [I] into [case]!", "You place [I] into [case].") - else - qdel(I) - return 1 - else - user.visible_message(" [user] could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.", \ - "You could not find anything inside [target]'s [affected.name].") - return 1 - -/datum/surgery_step/cavity/implant_removal/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery) - ..() - var/obj/item/organ/external/chest/affected = target.get_organ(target_zone) - if(affected.implants.len) - var/fail_prob = 10 - fail_prob += 100 - tool_quality(tool) - if(prob(fail_prob)) - var/obj/item/weapon/implant/imp = affected.implants[1] - user.visible_message(" Something beeps inside [target]'s [affected.name]!") - playsound(imp.loc, 'sound/items/countdown.ogg', 75, 1, -3) - spawn(25) - imp.activate() - return 0 - - -////////////////////////////////////////////////////////////////// -// EMBEDDED ITEM REOMOVAL // -////////////////////////////////////////////////////////////////// - -/datum/surgery/embedded_removal - name = "Removal of Embedded Objects" - steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/remove_object, /datum/surgery_step/generic/cauterize) - possible_locs = list("r_arm","l_arm","r_leg","l_leg","r_hand","r_foot","l_hand","l_foot","groin","chest","head") - -/datum/surgery/embedded_removal/synth - steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch, /datum/surgery_step/remove_object, /datum/surgery_step/robotics/external/close_hatch) - possible_locs = list("r_arm","l_arm","r_leg","l_leg","r_hand","r_foot","l_hand","l_foot","groin","chest","head") - - -/datum/surgery/embedded_removal/can_start(mob/user, mob/living/carbon/human/target) - if(!istype(target)) - return 0 - var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting) - if(!affected) - return 0 - if(affected.status & ORGAN_ROBOT) - return 0 - return 1 - -/datum/surgery/embedded_removal/synth/can_start(mob/user, mob/living/carbon/human/target) - if(!istype(target)) - return 0 - var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting) - if(!affected) - return 0 - if(!(affected.status & ORGAN_ROBOT)) - return 0 - return 1 - -/datum/surgery_step/remove_object - name = "remove embedded objects" - time = 32 - allowed_tools = list( - /obj/item/weapon/scalpel/laser/manager = 100, \ - /obj/item/weapon/hemostat = 100, \ - /obj/item/stack/cable_coil = 75, \ - /obj/item/device/assembly/mousetrap = 20 - ) - var/obj/item/organ/external/L = null - - -/datum/surgery_step/remove_object/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) - L = target.get_organ(target_zone) - if(L) - user.visible_message("[user] looks for objects embedded in [target]'s [target_zone].", "You look for objects embedded in [target]'s [target_zone]...") - else - user.visible_message("[user] looks for [target]'s [target_zone].", "You look for [target]'s [target_zone]...") - - -/datum/surgery_step/remove_object/end_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) - if(L) - if(ishuman(target)) - var/mob/living/carbon/human/H = target - var/objects = 0 - for(var/obj/item/I in L.implants) - if(!istype(I,/obj/item/weapon/implant)) - objects++ - I.forceMove(get_turf(H)) - L.implants -= I - - //Handle possessive brain borers. - if(H.has_brain_worms() && target_zone == "head")//remove worms outside the loop - var/mob/living/simple_animal/borer/worm = H.has_brain_worms() - if(worm.controlling) - target.release_control() - worm.detach() - worm.leave_host() - user.visible_message("a slug like creature wiggles out of [H]'s [target_zone]!") - - if(objects > 0) - user.visible_message("[user] sucessfully removes [objects] objects from [H]'s [L.limb_name]!", "You sucessfully remove [objects] objects from [H]'s [L.limb_name].") - else - to_chat(user, "You find no objects embedded in [H]'s [L.limb_name]!") - else - to_chat(user, "You can't find [target]'s [target_zone], let alone any objects embedded in it!") - - return 1 + return 0 \ No newline at end of file diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm new file mode 100644 index 00000000000..7b04be81e1d --- /dev/null +++ b/code/modules/surgery/implant_removal.dm @@ -0,0 +1,78 @@ +////////////////////////////////////////////////////////////////// +// IMPLANT REMOVAL SURGERY // +////////////////////////////////////////////////////////////////// + +/datum/surgery/implant_removal + name = "Implant Removal" + steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin,/datum/surgery_step/extract_implant,/datum/surgery_step/generic/cauterize) + possible_locs = list("chest") + +/datum/surgery/implant_removal/synth + name = "Implant Removal" + steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/extract_implant,/datum/surgery_step/robotics/external/close_hatch) + possible_locs = list("chest") + +/datum/surgery/implant_removal/can_start(mob/user, mob/living/carbon/human/target) + if(!istype(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting) + if(!affected) + return 0 + if(affected.status & ORGAN_ROBOT) + return 0 + return 1 + +/datum/surgery/implant_removal/synth/can_start(mob/user, mob/living/carbon/human/target) + if(!istype(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting) + if(!affected) + return 0 + if(!(affected.status & ORGAN_ROBOT)) + return 0 + + return 1 + +/datum/surgery_step/extract_implant + name = "extract implant" + allowed_tools = list(/obj/item/weapon/hemostat = 100, /obj/item/weapon/crowbar = 65) + time = 64 + var/obj/item/weapon/implant/I = null + +/datum/surgery_step/extract_implant/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + I = locate(/obj/item/weapon/implant) in target + user.visible_message("[user] starts poking around inside [target]'s [affected.name] with \the [tool].", \ + "You start poking around inside [target]'s [affected.name] with \the [tool]." ) + target.custom_pain("The pain in your [affected.name] is living hell!",1) + ..() + +/datum/surgery_step/extract_implant/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + I = locate(/obj/item/weapon/implant) in target + if(I && (target_zone == "chest")) //implant removal only works on the chest. + user.visible_message("[user] takes something out of [target]'s [affected.name] with \the [tool].", \ + "You take [I] out of [target]'s [affected.name]s with \the [tool]." ) + + I.removed(target) + + var/obj/item/weapon/implantcase/case + + if(istype(user.get_item_by_slot(slot_l_hand), /obj/item/weapon/implantcase)) + case = user.get_item_by_slot(slot_l_hand) + else if(istype(user.get_item_by_slot(slot_r_hand), /obj/item/weapon/implantcase)) + case = user.get_item_by_slot(slot_r_hand) + else + case = locate(/obj/item/weapon/implantcase) in get_turf(target) + + if(case && !case.imp) + case.imp = I + I.forceMove(case) + case.update_icon() + user.visible_message("[user] places [I] into [case]!", "You place [I] into [case].") + else + qdel(I) + else + user.visible_message(" [user] could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.", \ + "You could not find anything inside [target]'s [affected.name].") + return 1 \ No newline at end of file diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index 174076c5fab..773508c88ea 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -52,4 +52,7 @@ qdel(tool) + affected.open = 0 + affected.germ_level = 0 + affected.status &= ~ORGAN_BLEEDING return 1 \ No newline at end of file diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm index 7d544a61cda..00addd62b9a 100644 --- a/code/modules/surgery/organs/organ_external.dm +++ b/code/modules/surgery/organs/organ_external.dm @@ -59,7 +59,7 @@ var/encased // Needs to be opened with a saw to access the organs. var/obj/item/hidden = null - var/list/implants = list() + var/list/embedded_objects = list() // how often wounds should be updated, a higher number means less often var/wound_update_accuracy = 1 @@ -105,7 +105,7 @@ QDEL_LIST(wounds) - QDEL_LIST(implants) + QDEL_LIST(embedded_objects) QDEL_NULL(hidden) @@ -363,12 +363,6 @@ This function completely restores a damaged organ to perfect condition. for(var/obj/item/organ/external/EO in contents) EO.rejuvenate() - // remove embedded objects and drop them on the floor - for(var/obj/implanted_object in implants) - if(!istype(implanted_object,/obj/item/weapon/implant)) // We don't want to remove REAL implants. Just shrapnel etc. - implanted_object.loc = owner.loc - implants -= implanted_object - owner.updatehealth() update_icon() if(!owner) @@ -911,20 +905,6 @@ Note that amputating the affected organ does in fact remove the infection from t /obj/item/organ/external/proc/is_malfunctioning() return ((status & ORGAN_ROBOT) && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam) && !tough) -/obj/item/organ/external/proc/embed(var/obj/item/weapon/W, var/silent = 0) - if(!owner || loc != owner) - return - if(!silent) - owner.visible_message("\The [W] sticks in the wound!") - implants += W - owner.embedded_flag = 1 - owner.verbs += /mob/proc/yank_out_object - W.add_blood(owner) - if(ismob(W.loc)) - var/mob/living/H = W.loc - H.drop_item() - W.loc = owner - /obj/item/organ/external/proc/open_enough_for_surgery() return (encased ? (open == 3) : (open == 2)) @@ -935,14 +915,17 @@ Note that amputating the affected organ does in fact remove the infection from t var/is_robotic = status & ORGAN_ROBOT var/mob/living/carbon/human/victim = owner + for(var/obj/item/I in embedded_objects) + embedded_objects -= I + I.forceMove(src) + if(!owner.has_embedded_objects()) + owner.clear_alert("embeddedobject") + . = ..() status |= ORGAN_DESTROYED victim.bad_external_organs -= src - for(var/implant in implants) //todo: check if this can be left alone - qdel(implant) - // Attached organs also fly off. if(!ignore_children) for(var/obj/item/organ/external/O in children) @@ -1022,3 +1005,22 @@ Note that amputating the affected organ does in fact remove the infection from t ..() // Parent call loads in the DNA if(data["dna"]) sync_colour_to_dna() + +//Remove all embedded objects from all limbs on the carbon mob +/mob/living/carbon/human/proc/remove_all_embedded_objects() + var/turf/T = get_turf(src) + + for(var/X in bodyparts) + var/obj/item/organ/external/L = X + for(var/obj/item/I in L.embedded_objects) + L.embedded_objects -= I + I.forceMove(T) + + clear_alert("embeddedobject") + +/mob/living/carbon/human/proc/has_embedded_objects() + . = 0 + for(var/X in bodyparts) + var/obj/item/organ/external/L = X + for(var/obj/item/I in L.embedded_objects) + return 1 \ No newline at end of file diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index 5dcb5954da5..da41915249c 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -159,6 +159,11 @@ else if(implement_type in implements_extract) current_type = "extract" var/list/organs = target.get_organs_zone(target_zone) + var/mob/living/simple_animal/borer/B = target.has_brain_worms() + if(target_zone == "head" && B) + user.visible_message("[user] begins to extract [B] from [target]'s [parse_zone(target_zone)].", + "You begin to extract [B] from [target]'s [parse_zone(target_zone)]...") + return TRUE if(!organs.len) to_chat(user, "There are no removeable organs in [target]'s [parse_zone(target_zone)]!") return -1 @@ -262,6 +267,13 @@ I.status &= ~ORGAN_CUT_AWAY else if(current_type == "extract") + var/mob/living/simple_animal/borer/B = target.has_brain_worms() + if(target_zone == "head" && B && B.host == target) + user.visible_message("[user] successfully extracts [B] from [target]'s [parse_zone(target_zone)]!", + "You successfully extract [B] from [target]'s [parse_zone(target_zone)].") + add_logs(user, target, "surgically removed [B] from", addition="INTENT: [uppertext(user.a_intent)]") + B.leave_host() + return FALSE if(I && I.owner == target) user.visible_message(" [user] has separated and extracts [target]'s [I] with [tool].", " You have separated and extracted [target]'s [I] with [tool].") diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm new file mode 100644 index 00000000000..d7fe8b7fb53 --- /dev/null +++ b/code/modules/surgery/remove_embedded_object.dm @@ -0,0 +1,65 @@ +/datum/surgery/embedded_removal + name = "Removal of Embedded Objects" + steps = list(/datum/surgery_step/generic/cut_open, /datum/surgery_step/generic/clamp_bleeders, /datum/surgery_step/generic/retract_skin, /datum/surgery_step/remove_object,/datum/surgery_step/generic/cauterize) + possible_locs = list("head", "chest", "l_arm", "l_hand", "r_arm", "r_hand","r_leg", "r_foot", "l_leg", "l_foot", "groin") + +/datum/surgery/embedded_removal/synth + steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/remove_object,/datum/surgery_step/robotics/external/close_hatch) + +/datum/surgery/embedded_removal/can_start(mob/user, mob/living/carbon/human/target) + if(!istype(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting) + if(!affected) + return 0 + if(affected.status & ORGAN_ROBOT) + return 0 + return 1 + +/datum/surgery/embedded_removal/synth/can_start(mob/user, mob/living/carbon/human/target) + if(!istype(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting) + if(!affected) + return 0 + if(!(affected.status & ORGAN_ROBOT)) + return 0 + + return 1 + +/datum/surgery_step/remove_object + name = "Remove Embedded Objects" + time = 32 + accept_hand = 1 + var/obj/item/organ/external/L = null + + +/datum/surgery_step/remove_object/begin_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + L = surgery.organ_ref + if(L) + user.visible_message("[user] looks for objects embedded in [target]'s [parse_zone(user.zone_sel.selecting)].", "You look for objects embedded in [target]'s [parse_zone(user.zone_sel.selecting)]...") + else + user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_sel.selecting)].", "You look for [target]'s [parse_zone(user.zone_sel.selecting)]...") + + +/datum/surgery_step/remove_object/end_step(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + if(L) + if(ishuman(target)) + var/mob/living/carbon/human/H = target + var/objects = 0 + for(var/obj/item/I in L.embedded_objects) + objects++ + I.forceMove(get_turf(H)) + L.embedded_objects -= I + if(!H.has_embedded_objects()) + H.clear_alert("embeddedobject") + + if(objects > 0) + user.visible_message("[user] sucessfully removes [objects] objects from [H]'s [L]!", "You successfully remove [objects] objects from [H]'s [L.name].") + else + to_chat(user, "You find no objects embedded in [H]'s [L]!") + + else + to_chat(user, "You can't find [target]'s [parse_zone(user.zone_sel.selecting)], let alone any objects embedded in it!") + + return 1 \ No newline at end of file diff --git a/code/world.dm b/code/world.dm index 34d61dbbc21..e293058cdf6 100644 --- a/code/world.dm +++ b/code/world.dm @@ -244,6 +244,27 @@ var/world_topic_spam_protect_time = world.timeofday for(var/client/C in clients) to_chat(C, "PR: [input["announce"]]") + else if("kick" in input) + /* + We have a kick request over coms. + Only needed portion is the ckey + */ + if(!key_valid) + return keySpamProtect(addr) + + var/client/C + + for(var/client/K in clients) + if(K.ckey == input["kick"]) + C = K + break + if(!C) + return "No client with that name on server" + + del(C) + + return "Kick Successful" + /proc/keySpamProtect(var/addr) if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) spawn(50) diff --git a/html/changelog.html b/html/changelog.html index 70f2ffdb953..4ff84de803b 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,56 @@ -->
    +

    03 July 2017

    +

    Fethas updated:

    + +

    fludd12 updated:

    + + +

    01 July 2017

    +

    Fox McCloud updated:

    + + +

    30 June 2017

    +

    fludd12 updated:

    + + +

    29 June 2017

    +

    Fox McCloud updated:

    + +

    Kluys updated:

    + + +

    28 June 2017

    +

    Fox McCloud updated:

    + +

    Purpose2 and Re-Opened by Fethas updated:

    + +

    27 June 2017

    Alexshreds updated: